wined3d: Simply use surface_modify_location() in IWineD3DSurfaceImpl_Map() with WINED...
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blobe2db1aa7be40605d5f44d831944a79246c6c5b7c
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
35 #include <string.h>
36 #ifdef HAVE_DIRENT_H
37 # include <dirent.h>
38 #endif
39 #include <stdio.h>
40 #include <assert.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
60 #undef LoadResource
61 #undef CompareString
62 #undef GetCurrentThread
63 #undef _CDECL
64 #undef DPRINTF
65 #undef GetCurrentProcess
66 #undef AnimatePalette
67 #undef EqualRgn
68 #undef FillRgn
69 #undef FrameRgn
70 #undef GetPixel
71 #undef InvertRgn
72 #undef LineTo
73 #undef OffsetRgn
74 #undef PaintRgn
75 #undef Polygon
76 #undef ResizePalette
77 #undef SetRectRgn
78 #endif /* HAVE_CARBON_CARBON_H */
80 #include "windef.h"
81 #include "winbase.h"
82 #include "winternl.h"
83 #include "winerror.h"
84 #include "winreg.h"
85 #include "wingdi.h"
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
92 WINE_DEFAULT_DEBUG_CHANNEL(font);
94 #ifdef HAVE_FREETYPE
96 #ifdef HAVE_FT2BUILD_H
97 #include <ft2build.h>
98 #endif
99 #ifdef HAVE_FREETYPE_FREETYPE_H
100 #include <freetype/freetype.h>
101 #endif
102 #ifdef HAVE_FREETYPE_FTGLYPH_H
103 #include <freetype/ftglyph.h>
104 #endif
105 #ifdef HAVE_FREETYPE_TTTABLES_H
106 #include <freetype/tttables.h>
107 #endif
108 #ifdef HAVE_FREETYPE_FTTYPES_H
109 #include <freetype/fttypes.h>
110 #endif
111 #ifdef HAVE_FREETYPE_FTSNAMES_H
112 #include <freetype/ftsnames.h>
113 #endif
114 #ifdef HAVE_FREETYPE_TTNAMEID_H
115 #include <freetype/ttnameid.h>
116 #endif
117 #ifdef HAVE_FREETYPE_FTOUTLN_H
118 #include <freetype/ftoutln.h>
119 #endif
120 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
121 #include <freetype/internal/sfnt.h>
122 #endif
123 #ifdef HAVE_FREETYPE_FTTRIGON_H
124 #include <freetype/fttrigon.h>
125 #endif
126 #ifdef HAVE_FREETYPE_FTWINFNT_H
127 #include <freetype/ftwinfnt.h>
128 #endif
129 #ifdef HAVE_FREETYPE_FTMODAPI_H
130 #include <freetype/ftmodapi.h>
131 #endif
132 #ifdef HAVE_FREETYPE_FTLCDFIL_H
133 #include <freetype/ftlcdfil.h>
134 #endif
136 #ifndef HAVE_FT_TRUETYPEENGINETYPE
137 typedef enum
139 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
140 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
141 FT_TRUETYPE_ENGINE_TYPE_PATENTED
142 } FT_TrueTypeEngineType;
143 #endif
145 static FT_Library library = 0;
146 typedef struct
148 FT_Int major;
149 FT_Int minor;
150 FT_Int patch;
151 } FT_Version_t;
152 static FT_Version_t FT_Version;
153 static DWORD FT_SimpleVersion;
155 static void *ft_handle = NULL;
157 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
158 MAKE_FUNCPTR(FT_Vector_Unit);
159 MAKE_FUNCPTR(FT_Done_Face);
160 MAKE_FUNCPTR(FT_Get_Char_Index);
161 MAKE_FUNCPTR(FT_Get_Module);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
165 MAKE_FUNCPTR(FT_Init_FreeType);
166 MAKE_FUNCPTR(FT_Load_Glyph);
167 MAKE_FUNCPTR(FT_Matrix_Multiply);
168 #ifdef FT_MULFIX_INLINED
169 #define pFT_MulFix FT_MULFIX_INLINED
170 #else
171 MAKE_FUNCPTR(FT_MulFix);
172 #endif
173 MAKE_FUNCPTR(FT_New_Face);
174 MAKE_FUNCPTR(FT_New_Memory_Face);
175 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
176 MAKE_FUNCPTR(FT_Outline_Transform);
177 MAKE_FUNCPTR(FT_Outline_Translate);
178 MAKE_FUNCPTR(FT_Select_Charmap);
179 MAKE_FUNCPTR(FT_Set_Charmap);
180 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
181 MAKE_FUNCPTR(FT_Vector_Transform);
182 MAKE_FUNCPTR(FT_Render_Glyph);
183 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
184 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
185 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
186 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
190 #endif
191 #ifdef HAVE_FREETYPE_FTWINFNT_H
192 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
193 #endif
195 #ifdef SONAME_LIBFONTCONFIG
196 #include <fontconfig/fontconfig.h>
197 MAKE_FUNCPTR(FcConfigGetCurrent);
198 MAKE_FUNCPTR(FcFontList);
199 MAKE_FUNCPTR(FcFontSetDestroy);
200 MAKE_FUNCPTR(FcInit);
201 MAKE_FUNCPTR(FcObjectSetAdd);
202 MAKE_FUNCPTR(FcObjectSetCreate);
203 MAKE_FUNCPTR(FcObjectSetDestroy);
204 MAKE_FUNCPTR(FcPatternCreate);
205 MAKE_FUNCPTR(FcPatternDestroy);
206 MAKE_FUNCPTR(FcPatternGetBool);
207 MAKE_FUNCPTR(FcPatternGetString);
208 #endif
210 #undef MAKE_FUNCPTR
212 #ifndef FT_MAKE_TAG
213 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
214 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
215 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
216 #endif
218 #ifndef ft_encoding_none
219 #define FT_ENCODING_NONE ft_encoding_none
220 #endif
221 #ifndef ft_encoding_ms_symbol
222 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
223 #endif
224 #ifndef ft_encoding_unicode
225 #define FT_ENCODING_UNICODE ft_encoding_unicode
226 #endif
227 #ifndef ft_encoding_apple_roman
228 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
229 #endif
231 #ifdef WORDS_BIGENDIAN
232 #define GET_BE_WORD(x) (x)
233 #else
234 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
235 #endif
237 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
238 typedef struct {
239 FT_Short height;
240 FT_Short width;
241 FT_Pos size;
242 FT_Pos x_ppem;
243 FT_Pos y_ppem;
244 FT_Short internal_leading;
245 } Bitmap_Size;
247 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
248 So to let this compile on older versions of FreeType we'll define the
249 new structure here. */
250 typedef struct {
251 FT_Short height, width;
252 FT_Pos size, x_ppem, y_ppem;
253 } My_FT_Bitmap_Size;
255 struct enum_data
257 ENUMLOGFONTEXW elf;
258 NEWTEXTMETRICEXW ntm;
259 DWORD type;
262 typedef struct tagFace {
263 struct list entry;
264 WCHAR *StyleName;
265 char *file;
266 void *font_data_ptr;
267 DWORD font_data_size;
268 FT_Long face_index;
269 FONTSIGNATURE fs;
270 FONTSIGNATURE fs_links;
271 DWORD ntmFlags;
272 FT_Fixed font_version;
273 BOOL scalable;
274 Bitmap_Size size; /* set if face is a bitmap */
275 BOOL external; /* TRUE if we should manually add this font to the registry */
276 struct tagFamily *family;
277 /* Cached data for Enum */
278 struct enum_data *cached_enum_data;
279 } Face;
281 typedef struct tagFamily {
282 struct list entry;
283 const WCHAR *FamilyName;
284 struct list faces;
285 } Family;
287 typedef struct {
288 GLYPHMETRICS gm;
289 INT adv; /* These three hold to widths of the unrotated chars */
290 INT lsb;
291 INT bbx;
292 BOOL init;
293 } GM;
295 typedef struct {
296 FLOAT eM11, eM12;
297 FLOAT eM21, eM22;
298 } FMAT2;
300 typedef struct {
301 DWORD hash;
302 LOGFONTW lf;
303 FMAT2 matrix;
304 BOOL can_use_bitmap;
305 } FONT_DESC;
307 typedef struct tagHFONTLIST {
308 struct list entry;
309 HFONT hfont;
310 } HFONTLIST;
312 typedef struct {
313 struct list entry;
314 Face *face;
315 GdiFont *font;
316 } CHILD_FONT;
318 struct tagGdiFont {
319 struct list entry;
320 GM **gm;
321 DWORD gmsize;
322 struct list hfontlist;
323 OUTLINETEXTMETRICW *potm;
324 DWORD total_kern_pairs;
325 KERNINGPAIR *kern_pairs;
326 struct list child_fonts;
328 /* the following members can be accessed without locking, they are never modified after creation */
329 FT_Face ft_face;
330 struct font_mapping *mapping;
331 LPWSTR name;
332 int charset;
333 int codepage;
334 BOOL fake_italic;
335 BOOL fake_bold;
336 BYTE underline;
337 BYTE strikeout;
338 INT orientation;
339 FONT_DESC font_desc;
340 LONG aveWidth, ppem;
341 double scale_y;
342 SHORT yMax;
343 SHORT yMin;
344 DWORD ntmFlags;
345 FONTSIGNATURE fs;
346 GdiFont *base_font;
347 VOID *GSUB_Table;
348 DWORD cache_num;
351 typedef struct {
352 struct list entry;
353 const WCHAR *font_name;
354 struct list links;
355 } SYSTEM_LINKS;
357 #define GM_BLOCK_SIZE 128
358 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
360 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
361 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
362 #define UNUSED_CACHE_SIZE 10
363 static struct list child_font_list = LIST_INIT(child_font_list);
364 static struct list system_links = LIST_INIT(system_links);
366 static struct list font_subst_list = LIST_INIT(font_subst_list);
368 static struct list font_list = LIST_INIT(font_list);
370 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
371 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
372 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
374 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
375 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
376 'W','i','n','d','o','w','s','\\',
377 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
378 'F','o','n','t','s','\0'};
380 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
381 'W','i','n','d','o','w','s',' ','N','T','\\',
382 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
383 'F','o','n','t','s','\0'};
385 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
386 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
387 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
388 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
390 static const WCHAR * const SystemFontValues[4] = {
391 System_Value,
392 OEMFont_Value,
393 FixedSys_Value,
394 NULL
397 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
398 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
400 /* Interesting and well-known (frequently-assumed!) font names */
401 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
402 static const WCHAR Microsoft_Sans_Serif[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0 };
403 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
404 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
405 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
406 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
407 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
408 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
410 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
411 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
412 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
413 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
414 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
415 'E','u','r','o','p','e','a','n','\0'};
416 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
417 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
418 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
419 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
420 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
421 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
422 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
423 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
424 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
425 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
426 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
427 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
429 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
430 WesternW, /*00*/
431 Central_EuropeanW,
432 CyrillicW,
433 GreekW,
434 TurkishW,
435 HebrewW,
436 ArabicW,
437 BalticW,
438 VietnameseW, /*08*/
439 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
440 ThaiW,
441 JapaneseW,
442 CHINESE_GB2312W,
443 HangulW,
444 CHINESE_BIG5W,
445 Hangul_Johab_W,
446 NULL, NULL, /*23*/
447 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
448 SymbolW /*31*/
451 typedef struct {
452 WCHAR *name;
453 INT charset;
454 } NameCs;
456 typedef struct tagFontSubst {
457 struct list entry;
458 NameCs from;
459 NameCs to;
460 } FontSubst;
462 struct font_mapping
464 struct list entry;
465 int refcount;
466 dev_t dev;
467 ino_t ino;
468 void *data;
469 size_t size;
472 static struct list mappings_list = LIST_INIT( mappings_list );
474 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
476 static CRITICAL_SECTION freetype_cs;
477 static CRITICAL_SECTION_DEBUG critsect_debug =
479 0, 0, &freetype_cs,
480 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
481 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
483 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
485 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
487 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
488 static BOOL use_default_fallback = FALSE;
490 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
492 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
493 'W','i','n','d','o','w','s',' ','N','T','\\',
494 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
495 'S','y','s','t','e','m','L','i','n','k',0};
497 /****************************************
498 * Notes on .fon files
500 * The fonts System, FixedSys and Terminal are special. There are typically multiple
501 * versions installed for different resolutions and codepages. Windows stores which one to use
502 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
503 * Key Meaning
504 * FIXEDFON.FON FixedSys
505 * FONTS.FON System
506 * OEMFONT.FON Terminal
507 * LogPixels Current dpi set by the display control panel applet
508 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
509 * also has a LogPixels value that appears to mirror this)
511 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
512 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
513 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
514 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
515 * so that makes sense.
517 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
518 * to be mapped into the registry on Windows 2000 at least).
519 * I have
520 * woafont=app850.fon
521 * ega80woa.fon=ega80850.fon
522 * ega40woa.fon=ega40850.fon
523 * cga80woa.fon=cga80850.fon
524 * cga40woa.fon=cga40850.fon
527 /* These are all structures needed for the GSUB table */
529 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
530 #define TATEGAKI_LOWER_BOUND 0x02F1
532 typedef struct {
533 DWORD version;
534 WORD ScriptList;
535 WORD FeatureList;
536 WORD LookupList;
537 } GSUB_Header;
539 typedef struct {
540 CHAR ScriptTag[4];
541 WORD Script;
542 } GSUB_ScriptRecord;
544 typedef struct {
545 WORD ScriptCount;
546 GSUB_ScriptRecord ScriptRecord[1];
547 } GSUB_ScriptList;
549 typedef struct {
550 CHAR LangSysTag[4];
551 WORD LangSys;
552 } GSUB_LangSysRecord;
554 typedef struct {
555 WORD DefaultLangSys;
556 WORD LangSysCount;
557 GSUB_LangSysRecord LangSysRecord[1];
558 } GSUB_Script;
560 typedef struct {
561 WORD LookupOrder; /* Reserved */
562 WORD ReqFeatureIndex;
563 WORD FeatureCount;
564 WORD FeatureIndex[1];
565 } GSUB_LangSys;
567 typedef struct {
568 CHAR FeatureTag[4];
569 WORD Feature;
570 } GSUB_FeatureRecord;
572 typedef struct {
573 WORD FeatureCount;
574 GSUB_FeatureRecord FeatureRecord[1];
575 } GSUB_FeatureList;
577 typedef struct {
578 WORD FeatureParams; /* Reserved */
579 WORD LookupCount;
580 WORD LookupListIndex[1];
581 } GSUB_Feature;
583 typedef struct {
584 WORD LookupCount;
585 WORD Lookup[1];
586 } GSUB_LookupList;
588 typedef struct {
589 WORD LookupType;
590 WORD LookupFlag;
591 WORD SubTableCount;
592 WORD SubTable[1];
593 } GSUB_LookupTable;
595 typedef struct {
596 WORD CoverageFormat;
597 WORD GlyphCount;
598 WORD GlyphArray[1];
599 } GSUB_CoverageFormat1;
601 typedef struct {
602 WORD Start;
603 WORD End;
604 WORD StartCoverageIndex;
605 } GSUB_RangeRecord;
607 typedef struct {
608 WORD CoverageFormat;
609 WORD RangeCount;
610 GSUB_RangeRecord RangeRecord[1];
611 } GSUB_CoverageFormat2;
613 typedef struct {
614 WORD SubstFormat; /* = 1 */
615 WORD Coverage;
616 WORD DeltaGlyphID;
617 } GSUB_SingleSubstFormat1;
619 typedef struct {
620 WORD SubstFormat; /* = 2 */
621 WORD Coverage;
622 WORD GlyphCount;
623 WORD Substitute[1];
624 }GSUB_SingleSubstFormat2;
626 #ifdef HAVE_CARBON_CARBON_H
627 static char *find_cache_dir(void)
629 FSRef ref;
630 OSErr err;
631 static char cached_path[MAX_PATH];
632 static const char *wine = "/Wine", *fonts = "/Fonts";
634 if(*cached_path) return cached_path;
636 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
637 if(err != noErr)
639 WARN("can't create cached data folder\n");
640 return NULL;
642 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
643 if(err != noErr)
645 WARN("can't create cached data path\n");
646 *cached_path = '\0';
647 return NULL;
649 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
651 ERR("Could not create full path\n");
652 *cached_path = '\0';
653 return NULL;
655 strcat(cached_path, wine);
657 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
659 WARN("Couldn't mkdir %s\n", cached_path);
660 *cached_path = '\0';
661 return NULL;
663 strcat(cached_path, fonts);
664 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
666 WARN("Couldn't mkdir %s\n", cached_path);
667 *cached_path = '\0';
668 return NULL;
670 return cached_path;
673 /******************************************************************
674 * expand_mac_font
676 * Extracts individual TrueType font files from a Mac suitcase font
677 * and saves them into the user's caches directory (see
678 * find_cache_dir()).
679 * Returns a NULL terminated array of filenames.
681 * We do this because they are apps that try to read ttf files
682 * themselves and they don't like Mac suitcase files.
684 static char **expand_mac_font(const char *path)
686 FSRef ref;
687 SInt16 res_ref;
688 OSStatus s;
689 unsigned int idx;
690 const char *out_dir;
691 const char *filename;
692 int output_len;
693 struct {
694 char **array;
695 unsigned int size, max_size;
696 } ret;
698 TRACE("path %s\n", path);
700 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
701 if(s != noErr)
703 WARN("failed to get ref\n");
704 return NULL;
707 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
708 if(s != noErr)
710 TRACE("no data fork, so trying resource fork\n");
711 res_ref = FSOpenResFile(&ref, fsRdPerm);
712 if(res_ref == -1)
714 TRACE("unable to open resource fork\n");
715 return NULL;
719 ret.size = 0;
720 ret.max_size = 10;
721 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
722 if(!ret.array)
724 CloseResFile(res_ref);
725 return NULL;
728 out_dir = find_cache_dir();
730 filename = strrchr(path, '/');
731 if(!filename) filename = path;
732 else filename++;
734 /* output filename has the form out_dir/filename_%04x.ttf */
735 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
737 UseResFile(res_ref);
738 idx = 1;
739 while(1)
741 FamRec *fam_rec;
742 unsigned short *num_faces_ptr, num_faces, face;
743 AsscEntry *assoc;
744 Handle fond;
745 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
747 fond = Get1IndResource(fond_res, idx);
748 if(!fond) break;
749 TRACE("got fond resource %d\n", idx);
750 HLock(fond);
752 fam_rec = *(FamRec**)fond;
753 num_faces_ptr = (unsigned short *)(fam_rec + 1);
754 num_faces = GET_BE_WORD(*num_faces_ptr);
755 num_faces++;
756 assoc = (AsscEntry*)(num_faces_ptr + 1);
757 TRACE("num faces %04x\n", num_faces);
758 for(face = 0; face < num_faces; face++, assoc++)
760 Handle sfnt;
761 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
762 unsigned short size, font_id;
763 char *output;
765 size = GET_BE_WORD(assoc->fontSize);
766 font_id = GET_BE_WORD(assoc->fontID);
767 if(size != 0)
769 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
770 continue;
773 TRACE("trying to load sfnt id %04x\n", font_id);
774 sfnt = GetResource(sfnt_res, font_id);
775 if(!sfnt)
777 TRACE("can't get sfnt resource %04x\n", font_id);
778 continue;
781 output = HeapAlloc(GetProcessHeap(), 0, output_len);
782 if(output)
784 int fd;
786 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
788 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
789 if(fd != -1 || errno == EEXIST)
791 if(fd != -1)
793 unsigned char *sfnt_data;
795 HLock(sfnt);
796 sfnt_data = *(unsigned char**)sfnt;
797 write(fd, sfnt_data, GetHandleSize(sfnt));
798 HUnlock(sfnt);
799 close(fd);
801 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
803 ret.max_size *= 2;
804 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
806 ret.array[ret.size++] = output;
808 else
810 WARN("unable to create %s\n", output);
811 HeapFree(GetProcessHeap(), 0, output);
814 ReleaseResource(sfnt);
816 HUnlock(fond);
817 ReleaseResource(fond);
818 idx++;
820 CloseResFile(res_ref);
822 return ret.array;
825 #endif /* HAVE_CARBON_CARBON_H */
827 static inline BOOL is_win9x(void)
829 return GetVersion() & 0x80000000;
832 This function builds an FT_Fixed from a double. It fails if the absolute
833 value of the float number is greater than 32768.
835 static inline FT_Fixed FT_FixedFromFloat(double f)
837 return f * 0x10000;
841 This function builds an FT_Fixed from a FIXED. It simply put f.value
842 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
844 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
846 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
850 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
852 Family *family;
853 Face *face;
854 const char *file;
855 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
856 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
858 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
859 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
861 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
863 if(face_name && strcmpiW(face_name, family->FamilyName))
864 continue;
865 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
867 if (!face->file)
868 continue;
869 file = strrchr(face->file, '/');
870 if(!file)
871 file = face->file;
872 else
873 file++;
874 if(!strcasecmp(file, file_nameA))
876 HeapFree(GetProcessHeap(), 0, file_nameA);
877 return face;
881 HeapFree(GetProcessHeap(), 0, file_nameA);
882 return NULL;
885 static Family *find_family_from_name(const WCHAR *name)
887 Family *family;
889 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
891 if(!strcmpiW(family->FamilyName, name))
892 return family;
895 return NULL;
898 static void DumpSubstList(void)
900 FontSubst *psub;
902 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
904 if(psub->from.charset != -1 || psub->to.charset != -1)
905 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
906 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
907 else
908 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
909 debugstr_w(psub->to.name));
911 return;
914 static LPWSTR strdupW(LPCWSTR p)
916 LPWSTR ret;
917 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
918 ret = HeapAlloc(GetProcessHeap(), 0, len);
919 memcpy(ret, p, len);
920 return ret;
923 static LPSTR strdupA(LPCSTR p)
925 LPSTR ret;
926 DWORD len = (strlen(p) + 1);
927 ret = HeapAlloc(GetProcessHeap(), 0, len);
928 memcpy(ret, p, len);
929 return ret;
932 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
933 INT from_charset)
935 FontSubst *element;
937 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
939 if(!strcmpiW(element->from.name, from_name) &&
940 (element->from.charset == from_charset ||
941 element->from.charset == -1))
942 return element;
945 return NULL;
948 #define ADD_FONT_SUBST_FORCE 1
950 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
952 FontSubst *from_exist, *to_exist;
954 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
956 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
958 list_remove(&from_exist->entry);
959 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
960 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
961 HeapFree(GetProcessHeap(), 0, from_exist);
962 from_exist = NULL;
965 if(!from_exist)
967 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
969 if(to_exist)
971 HeapFree(GetProcessHeap(), 0, subst->to.name);
972 subst->to.name = strdupW(to_exist->to.name);
975 list_add_tail(subst_list, &subst->entry);
977 return TRUE;
980 HeapFree(GetProcessHeap(), 0, subst->from.name);
981 HeapFree(GetProcessHeap(), 0, subst->to.name);
982 HeapFree(GetProcessHeap(), 0, subst);
983 return FALSE;
986 static void split_subst_info(NameCs *nc, LPSTR str)
988 CHAR *p = strrchr(str, ',');
989 DWORD len;
991 nc->charset = -1;
992 if(p && *(p+1)) {
993 nc->charset = strtol(p+1, NULL, 10);
994 *p = '\0';
996 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
997 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
998 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
1001 static void LoadSubstList(void)
1003 FontSubst *psub;
1004 HKEY hkey;
1005 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1006 LPSTR value;
1007 LPVOID data;
1009 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1010 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1011 &hkey) == ERROR_SUCCESS) {
1013 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1014 &valuelen, &datalen, NULL, NULL);
1016 valuelen++; /* returned value doesn't include room for '\0' */
1017 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1018 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1020 dlen = datalen;
1021 vlen = valuelen;
1022 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1023 &dlen) == ERROR_SUCCESS) {
1024 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1026 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1027 split_subst_info(&psub->from, value);
1028 split_subst_info(&psub->to, data);
1030 /* Win 2000 doesn't allow mapping between different charsets
1031 or mapping of DEFAULT_CHARSET */
1032 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1033 psub->to.charset == DEFAULT_CHARSET) {
1034 HeapFree(GetProcessHeap(), 0, psub->to.name);
1035 HeapFree(GetProcessHeap(), 0, psub->from.name);
1036 HeapFree(GetProcessHeap(), 0, psub);
1037 } else {
1038 add_font_subst(&font_subst_list, psub, 0);
1040 /* reset dlen and vlen */
1041 dlen = datalen;
1042 vlen = valuelen;
1044 HeapFree(GetProcessHeap(), 0, data);
1045 HeapFree(GetProcessHeap(), 0, value);
1046 RegCloseKey(hkey);
1051 /*****************************************************************
1052 * get_name_table_entry
1054 * Supply the platform, encoding, language and name ids in req
1055 * and if the name exists the function will fill in the string
1056 * and string_len members. The string is owned by FreeType so
1057 * don't free it. Returns TRUE if the name is found else FALSE.
1059 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1061 FT_SfntName name;
1062 FT_UInt num_names, name_index;
1064 if(FT_IS_SFNT(ft_face))
1066 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1068 for(name_index = 0; name_index < num_names; name_index++)
1070 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1072 if((name.platform_id == req->platform_id) &&
1073 (name.encoding_id == req->encoding_id) &&
1074 (name.language_id == req->language_id) &&
1075 (name.name_id == req->name_id))
1077 req->string = name.string;
1078 req->string_len = name.string_len;
1079 return TRUE;
1084 req->string = NULL;
1085 req->string_len = 0;
1086 return FALSE;
1089 static WCHAR *get_familyname(FT_Face ft_face)
1091 WCHAR *family = NULL;
1092 FT_SfntName name;
1094 name.platform_id = TT_PLATFORM_MICROSOFT;
1095 name.encoding_id = TT_MS_ID_UNICODE_CS;
1096 name.language_id = GetUserDefaultLCID();
1097 name.name_id = TT_NAME_ID_FONT_FAMILY;
1099 if(get_name_table_entry(ft_face, &name))
1101 FT_UInt i;
1103 /* String is not nul terminated and string_len is a byte length. */
1104 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1105 for(i = 0; i < name.string_len / 2; i++)
1107 WORD *tmp = (WORD *)&name.string[i * 2];
1108 family[i] = GET_BE_WORD(*tmp);
1110 family[i] = 0;
1111 TRACE("Got localised name %s\n", debugstr_w(family));
1114 return family;
1118 /*****************************************************************
1119 * load_sfnt_table
1121 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1122 * of FreeType that don't export this function.
1125 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1128 FT_Error err;
1130 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1131 if(pFT_Load_Sfnt_Table)
1133 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1135 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1136 else /* Do it the hard way */
1138 TT_Face tt_face = (TT_Face) ft_face;
1139 SFNT_Interface *sfnt;
1140 if (FT_Version.major==2 && FT_Version.minor==0)
1142 /* 2.0.x */
1143 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1145 else
1147 /* A field was added in the middle of the structure in 2.1.x */
1148 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1150 err = sfnt->load_any(tt_face, table, offset, buf, len);
1152 #else
1153 else
1155 static int msg;
1156 if(!msg)
1158 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1159 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1160 "Please upgrade your freetype library.\n");
1161 msg++;
1163 err = FT_Err_Unimplemented_Feature;
1165 #endif
1166 return err;
1169 static inline int TestStyles(DWORD flags, DWORD styles)
1171 return (flags & styles) == styles;
1174 static int StyleOrdering(Face *face)
1176 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1177 return 3;
1178 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1179 return 2;
1180 if (TestStyles(face->ntmFlags, NTM_BOLD))
1181 return 1;
1182 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1183 return 0;
1185 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1186 debugstr_w(face->family->FamilyName),
1187 debugstr_w(face->StyleName),
1188 face->ntmFlags);
1190 return 9999;
1193 /* Add a style of face to a font family using an ordering of the list such
1194 that regular fonts come before bold and italic, and single styles come
1195 before compound styles. */
1196 static void AddFaceToFamily(Face *face, Family *family)
1198 struct list *entry;
1200 LIST_FOR_EACH( entry, &family->faces )
1202 Face *ent = LIST_ENTRY(entry, Face, entry);
1203 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1205 list_add_before( entry, &face->entry );
1208 #define ADDFONT_EXTERNAL_FONT 0x01
1209 #define ADDFONT_FORCE_BITMAP 0x02
1210 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1212 FT_Face ft_face;
1213 TT_OS2 *pOS2;
1214 TT_Header *pHeader = NULL;
1215 WCHAR *english_family, *localised_family, *StyleW;
1216 DWORD len;
1217 Family *family;
1218 Face *face;
1219 struct list *family_elem_ptr, *face_elem_ptr;
1220 FT_Error err;
1221 FT_Long face_index = 0, num_faces;
1222 #ifdef HAVE_FREETYPE_FTWINFNT_H
1223 FT_WinFNT_HeaderRec winfnt_header;
1224 #endif
1225 int i, bitmap_num, internal_leading;
1226 FONTSIGNATURE fs;
1228 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1229 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1231 #ifdef HAVE_CARBON_CARBON_H
1232 if(file && !fake_family)
1234 char **mac_list = expand_mac_font(file);
1235 if(mac_list)
1237 BOOL had_one = FALSE;
1238 char **cursor;
1239 for(cursor = mac_list; *cursor; cursor++)
1241 had_one = TRUE;
1242 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1243 HeapFree(GetProcessHeap(), 0, *cursor);
1245 HeapFree(GetProcessHeap(), 0, mac_list);
1246 if(had_one)
1247 return 1;
1250 #endif /* HAVE_CARBON_CARBON_H */
1252 do {
1253 char *family_name = fake_family;
1255 if (file)
1257 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1258 err = pFT_New_Face(library, file, face_index, &ft_face);
1259 } else
1261 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1262 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1265 if(err != 0) {
1266 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1267 return 0;
1270 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*/
1271 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1272 pFT_Done_Face(ft_face);
1273 return 0;
1276 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1277 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1278 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1279 pFT_Done_Face(ft_face);
1280 return 0;
1283 if(FT_IS_SFNT(ft_face))
1285 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1286 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1287 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1289 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1290 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1291 pFT_Done_Face(ft_face);
1292 return 0;
1295 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1296 we don't want to load these. */
1297 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1299 FT_ULong len = 0;
1301 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1303 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1304 pFT_Done_Face(ft_face);
1305 return 0;
1310 if(!ft_face->family_name || !ft_face->style_name) {
1311 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1312 pFT_Done_Face(ft_face);
1313 return 0;
1316 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1318 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1319 pFT_Done_Face(ft_face);
1320 return 0;
1323 if (target_family)
1325 localised_family = get_familyname(ft_face);
1326 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1328 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1329 HeapFree(GetProcessHeap(), 0, localised_family);
1330 num_faces = ft_face->num_faces;
1331 pFT_Done_Face(ft_face);
1332 continue;
1334 HeapFree(GetProcessHeap(), 0, localised_family);
1337 if(!family_name)
1338 family_name = ft_face->family_name;
1340 bitmap_num = 0;
1341 do {
1342 My_FT_Bitmap_Size *size = NULL;
1343 FT_ULong tmp_size;
1345 if(!FT_IS_SCALABLE(ft_face))
1346 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1348 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1349 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1350 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1352 localised_family = NULL;
1353 if(!fake_family) {
1354 localised_family = get_familyname(ft_face);
1355 if(localised_family && !strcmpiW(localised_family, english_family)) {
1356 HeapFree(GetProcessHeap(), 0, localised_family);
1357 localised_family = NULL;
1361 family = NULL;
1362 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1363 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1364 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1365 break;
1366 family = NULL;
1368 if(!family) {
1369 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1370 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1371 list_init(&family->faces);
1372 list_add_tail(&font_list, &family->entry);
1374 if(localised_family) {
1375 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1376 subst->from.name = strdupW(english_family);
1377 subst->from.charset = -1;
1378 subst->to.name = strdupW(localised_family);
1379 subst->to.charset = -1;
1380 add_font_subst(&font_subst_list, subst, 0);
1383 HeapFree(GetProcessHeap(), 0, localised_family);
1384 HeapFree(GetProcessHeap(), 0, english_family);
1386 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1387 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1388 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1390 internal_leading = 0;
1391 memset(&fs, 0, sizeof(fs));
1393 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1394 if(pOS2) {
1395 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1396 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1397 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1398 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1399 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1400 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1401 if(pOS2->version == 0) {
1402 FT_UInt dummy;
1404 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1405 fs.fsCsb[0] |= FS_LATIN1;
1406 else
1407 fs.fsCsb[0] |= FS_SYMBOL;
1410 #ifdef HAVE_FREETYPE_FTWINFNT_H
1411 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1412 CHARSETINFO csi;
1413 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1414 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1415 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1416 fs = csi.fs;
1417 internal_leading = winfnt_header.internal_leading;
1419 #endif
1421 face_elem_ptr = list_head(&family->faces);
1422 while(face_elem_ptr) {
1423 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1424 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1425 if(!strcmpiW(face->StyleName, StyleW) &&
1426 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1427 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1428 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1429 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1431 if(fake_family) {
1432 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1433 HeapFree(GetProcessHeap(), 0, StyleW);
1434 pFT_Done_Face(ft_face);
1435 return 1;
1437 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1438 TRACE("Original font is newer so skipping this one\n");
1439 HeapFree(GetProcessHeap(), 0, StyleW);
1440 pFT_Done_Face(ft_face);
1441 return 1;
1442 } else {
1443 TRACE("Replacing original with this one\n");
1444 list_remove(&face->entry);
1445 HeapFree(GetProcessHeap(), 0, face->file);
1446 HeapFree(GetProcessHeap(), 0, face->StyleName);
1447 HeapFree(GetProcessHeap(), 0, face);
1448 break;
1452 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1453 face->cached_enum_data = NULL;
1454 face->StyleName = StyleW;
1455 if (file)
1457 face->file = strdupA(file);
1458 face->font_data_ptr = NULL;
1459 face->font_data_size = 0;
1461 else
1463 face->file = NULL;
1464 face->font_data_ptr = font_data_ptr;
1465 face->font_data_size = font_data_size;
1467 face->face_index = face_index;
1468 face->ntmFlags = 0;
1469 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1470 face->ntmFlags |= NTM_ITALIC;
1471 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1472 face->ntmFlags |= NTM_BOLD;
1473 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1474 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1475 face->family = family;
1476 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1477 face->fs = fs;
1478 memset(&face->fs_links, 0, sizeof(face->fs_links));
1480 if(FT_IS_SCALABLE(ft_face)) {
1481 memset(&face->size, 0, sizeof(face->size));
1482 face->scalable = TRUE;
1483 } else {
1484 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1485 size->height, size->width, size->size >> 6,
1486 size->x_ppem >> 6, size->y_ppem >> 6);
1487 face->size.height = size->height;
1488 face->size.width = size->width;
1489 face->size.size = size->size;
1490 face->size.x_ppem = size->x_ppem;
1491 face->size.y_ppem = size->y_ppem;
1492 face->size.internal_leading = internal_leading;
1493 face->scalable = FALSE;
1496 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1497 tmp_size = 0;
1498 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1500 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1501 face->ntmFlags |= NTM_PS_OPENTYPE;
1504 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1505 face->fs.fsCsb[0], face->fs.fsCsb[1],
1506 face->fs.fsUsb[0], face->fs.fsUsb[1],
1507 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1510 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1511 for(i = 0; i < ft_face->num_charmaps; i++) {
1512 switch(ft_face->charmaps[i]->encoding) {
1513 case FT_ENCODING_UNICODE:
1514 case FT_ENCODING_APPLE_ROMAN:
1515 face->fs.fsCsb[0] |= FS_LATIN1;
1516 break;
1517 case FT_ENCODING_MS_SYMBOL:
1518 face->fs.fsCsb[0] |= FS_SYMBOL;
1519 break;
1520 default:
1521 break;
1526 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1527 have_installed_roman_font = TRUE;
1529 AddFaceToFamily(face, family);
1531 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1533 num_faces = ft_face->num_faces;
1534 pFT_Done_Face(ft_face);
1535 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1536 debugstr_w(StyleW));
1537 } while(num_faces > ++face_index);
1538 return num_faces;
1541 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1543 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1546 static void DumpFontList(void)
1548 Family *family;
1549 Face *face;
1550 struct list *family_elem_ptr, *face_elem_ptr;
1552 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1553 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1554 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1555 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1556 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1557 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1558 if(!face->scalable)
1559 TRACE(" %d", face->size.height);
1560 TRACE("\n");
1563 return;
1566 /***********************************************************
1567 * The replacement list is a way to map an entire font
1568 * family onto another family. For example adding
1570 * [HKCU\Software\Wine\Fonts\Replacements]
1571 * "Wingdings"="Winedings"
1573 * would enumerate the Winedings font both as Winedings and
1574 * Wingdings. However if a real Wingdings font is present the
1575 * replacement does not take place.
1578 static void LoadReplaceList(void)
1580 HKEY hkey;
1581 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1582 LPWSTR value;
1583 LPVOID data;
1584 Family *family;
1585 Face *face;
1586 struct list *family_elem_ptr, *face_elem_ptr;
1587 CHAR familyA[400];
1589 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1590 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1592 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1593 &valuelen, &datalen, NULL, NULL);
1595 valuelen++; /* returned value doesn't include room for '\0' */
1596 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1597 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1599 dlen = datalen;
1600 vlen = valuelen;
1601 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1602 &dlen) == ERROR_SUCCESS) {
1603 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1604 /* "NewName"="Oldname" */
1605 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1607 /* Find the old family and hence all of the font files
1608 in that family */
1609 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1610 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1611 if(!strcmpiW(family->FamilyName, data)) {
1612 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1613 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1614 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1615 debugstr_w(face->StyleName), familyA);
1616 /* Now add a new entry with the new family name */
1617 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1619 break;
1622 /* reset dlen and vlen */
1623 dlen = datalen;
1624 vlen = valuelen;
1626 HeapFree(GetProcessHeap(), 0, data);
1627 HeapFree(GetProcessHeap(), 0, value);
1628 RegCloseKey(hkey);
1632 /*************************************************************
1633 * init_system_links
1635 static BOOL init_system_links(void)
1637 HKEY hkey;
1638 BOOL ret = FALSE;
1639 DWORD type, max_val, max_data, val_len, data_len, index;
1640 WCHAR *value, *data;
1641 WCHAR *entry, *next;
1642 SYSTEM_LINKS *font_link, *system_font_link;
1643 CHILD_FONT *child_font;
1644 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1645 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1646 FONTSIGNATURE fs;
1647 Family *family;
1648 Face *face;
1649 FontSubst *psub;
1651 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1653 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1654 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1655 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1656 val_len = max_val + 1;
1657 data_len = max_data;
1658 index = 0;
1659 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1661 memset(&fs, 0, sizeof(fs));
1662 psub = get_font_subst(&font_subst_list, value, -1);
1663 /* Don't store fonts that are only substitutes for other fonts */
1664 if(psub)
1666 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1667 goto next;
1669 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1670 font_link->font_name = strdupW(value);
1671 list_init(&font_link->links);
1672 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1674 WCHAR *face_name;
1675 CHILD_FONT *child_font;
1677 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1679 next = entry + strlenW(entry) + 1;
1681 face_name = strchrW(entry, ',');
1682 if(face_name)
1684 *face_name++ = 0;
1685 while(isspaceW(*face_name))
1686 face_name++;
1688 psub = get_font_subst(&font_subst_list, face_name, -1);
1689 if(psub)
1690 face_name = psub->to.name;
1692 face = find_face_from_filename(entry, face_name);
1693 if(!face)
1695 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1696 continue;
1699 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1700 child_font->face = face;
1701 child_font->font = NULL;
1702 fs.fsCsb[0] |= face->fs.fsCsb[0];
1703 fs.fsCsb[1] |= face->fs.fsCsb[1];
1704 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1705 list_add_tail(&font_link->links, &child_font->entry);
1707 family = find_family_from_name(font_link->font_name);
1708 if(family)
1710 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1712 face->fs_links = fs;
1715 list_add_tail(&system_links, &font_link->entry);
1716 next:
1717 val_len = max_val + 1;
1718 data_len = max_data;
1721 HeapFree(GetProcessHeap(), 0, value);
1722 HeapFree(GetProcessHeap(), 0, data);
1723 RegCloseKey(hkey);
1726 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1727 that Tahoma has */
1729 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1730 system_font_link->font_name = strdupW(System);
1731 list_init(&system_font_link->links);
1733 face = find_face_from_filename(tahoma_ttf, Tahoma);
1734 if(face)
1736 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1737 child_font->face = face;
1738 child_font->font = NULL;
1739 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1740 list_add_tail(&system_font_link->links, &child_font->entry);
1742 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1744 if(!strcmpiW(font_link->font_name, Tahoma))
1746 CHILD_FONT *font_link_entry;
1747 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1749 CHILD_FONT *new_child;
1750 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1751 new_child->face = font_link_entry->face;
1752 new_child->font = NULL;
1753 list_add_tail(&system_font_link->links, &new_child->entry);
1755 break;
1758 list_add_tail(&system_links, &system_font_link->entry);
1759 return ret;
1762 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1764 DIR *dir;
1765 struct dirent *dent;
1766 char path[MAX_PATH];
1768 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1770 dir = opendir(dirname);
1771 if(!dir) {
1772 WARN("Can't open directory %s\n", debugstr_a(dirname));
1773 return FALSE;
1775 while((dent = readdir(dir)) != NULL) {
1776 struct stat statbuf;
1778 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1779 continue;
1781 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1783 sprintf(path, "%s/%s", dirname, dent->d_name);
1785 if(stat(path, &statbuf) == -1)
1787 WARN("Can't stat %s\n", debugstr_a(path));
1788 continue;
1790 if(S_ISDIR(statbuf.st_mode))
1791 ReadFontDir(path, external_fonts);
1792 else
1793 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1795 closedir(dir);
1796 return TRUE;
1799 static void load_fontconfig_fonts(void)
1801 #ifdef SONAME_LIBFONTCONFIG
1802 void *fc_handle = NULL;
1803 FcConfig *config;
1804 FcPattern *pat;
1805 FcObjectSet *os;
1806 FcFontSet *fontset;
1807 int i, len;
1808 char *file;
1809 const char *ext;
1811 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1812 if(!fc_handle) {
1813 TRACE("Wine cannot find the fontconfig library (%s).\n",
1814 SONAME_LIBFONTCONFIG);
1815 return;
1817 #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;}
1818 LOAD_FUNCPTR(FcConfigGetCurrent);
1819 LOAD_FUNCPTR(FcFontList);
1820 LOAD_FUNCPTR(FcFontSetDestroy);
1821 LOAD_FUNCPTR(FcInit);
1822 LOAD_FUNCPTR(FcObjectSetAdd);
1823 LOAD_FUNCPTR(FcObjectSetCreate);
1824 LOAD_FUNCPTR(FcObjectSetDestroy);
1825 LOAD_FUNCPTR(FcPatternCreate);
1826 LOAD_FUNCPTR(FcPatternDestroy);
1827 LOAD_FUNCPTR(FcPatternGetBool);
1828 LOAD_FUNCPTR(FcPatternGetString);
1829 #undef LOAD_FUNCPTR
1831 if(!pFcInit()) return;
1833 config = pFcConfigGetCurrent();
1834 pat = pFcPatternCreate();
1835 os = pFcObjectSetCreate();
1836 pFcObjectSetAdd(os, FC_FILE);
1837 pFcObjectSetAdd(os, FC_SCALABLE);
1838 fontset = pFcFontList(config, pat, os);
1839 if(!fontset) return;
1840 for(i = 0; i < fontset->nfont; i++) {
1841 FcBool scalable;
1843 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1844 continue;
1845 TRACE("fontconfig: %s\n", file);
1847 /* We're just interested in OT/TT fonts for now, so this hack just
1848 picks up the scalable fonts without extensions .pf[ab] to save time
1849 loading every other font */
1851 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1853 TRACE("not scalable\n");
1854 continue;
1857 len = strlen( file );
1858 if(len < 4) continue;
1859 ext = &file[ len - 3 ];
1860 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1861 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1863 pFcFontSetDestroy(fontset);
1864 pFcObjectSetDestroy(os);
1865 pFcPatternDestroy(pat);
1866 sym_not_found:
1867 #endif
1868 return;
1871 static BOOL load_font_from_data_dir(LPCWSTR file)
1873 BOOL ret = FALSE;
1874 const char *data_dir = wine_get_data_dir();
1876 if (!data_dir) data_dir = wine_get_build_dir();
1878 if (data_dir)
1880 INT len;
1881 char *unix_name;
1883 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1885 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1887 strcpy(unix_name, data_dir);
1888 strcat(unix_name, "/fonts/");
1890 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1892 EnterCriticalSection( &freetype_cs );
1893 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1894 LeaveCriticalSection( &freetype_cs );
1895 HeapFree(GetProcessHeap(), 0, unix_name);
1897 return ret;
1900 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1902 static const WCHAR slashW[] = {'\\','\0'};
1903 BOOL ret = FALSE;
1904 WCHAR windowsdir[MAX_PATH];
1905 char *unixname;
1907 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1908 strcatW(windowsdir, fontsW);
1909 strcatW(windowsdir, slashW);
1910 strcatW(windowsdir, file);
1911 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1912 EnterCriticalSection( &freetype_cs );
1913 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1914 LeaveCriticalSection( &freetype_cs );
1915 HeapFree(GetProcessHeap(), 0, unixname);
1917 return ret;
1920 static void load_system_fonts(void)
1922 HKEY hkey;
1923 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1924 const WCHAR * const *value;
1925 DWORD dlen, type;
1926 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1927 char *unixname;
1929 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1930 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1931 strcatW(windowsdir, fontsW);
1932 for(value = SystemFontValues; *value; value++) {
1933 dlen = sizeof(data);
1934 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1935 type == REG_SZ) {
1936 BOOL added = FALSE;
1938 sprintfW(pathW, fmtW, windowsdir, data);
1939 if((unixname = wine_get_unix_file_name(pathW))) {
1940 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1941 HeapFree(GetProcessHeap(), 0, unixname);
1943 if (!added)
1944 load_font_from_data_dir(data);
1947 RegCloseKey(hkey);
1951 /*************************************************************
1953 * This adds registry entries for any externally loaded fonts
1954 * (fonts from fontconfig or FontDirs). It also deletes entries
1955 * of no longer existing fonts.
1958 static void update_reg_entries(void)
1960 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1961 LPWSTR valueW;
1962 DWORD len, len_fam;
1963 Family *family;
1964 Face *face;
1965 struct list *family_elem_ptr, *face_elem_ptr;
1966 WCHAR *file;
1967 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1968 static const WCHAR spaceW[] = {' ', '\0'};
1969 char *path;
1971 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1972 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1973 ERR("Can't create Windows font reg key\n");
1974 goto end;
1977 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1978 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1979 ERR("Can't create Windows font reg key\n");
1980 goto end;
1983 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1984 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1985 ERR("Can't create external font reg key\n");
1986 goto end;
1989 /* enumerate the fonts and add external ones to the two keys */
1991 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1992 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1993 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1994 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1995 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1996 if(!face->external) continue;
1997 len = len_fam;
1998 if (!(face->ntmFlags & NTM_REGULAR))
1999 len = len_fam + strlenW(face->StyleName) + 1;
2000 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2001 strcpyW(valueW, family->FamilyName);
2002 if(len != len_fam) {
2003 strcatW(valueW, spaceW);
2004 strcatW(valueW, face->StyleName);
2006 strcatW(valueW, TrueType);
2008 file = wine_get_dos_file_name(face->file);
2009 if(file)
2010 len = strlenW(file) + 1;
2011 else
2013 if((path = strrchr(face->file, '/')) == NULL)
2014 path = face->file;
2015 else
2016 path++;
2017 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2019 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2020 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2022 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2023 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2024 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2026 HeapFree(GetProcessHeap(), 0, file);
2027 HeapFree(GetProcessHeap(), 0, valueW);
2030 end:
2031 if(external_key) RegCloseKey(external_key);
2032 if(win9x_key) RegCloseKey(win9x_key);
2033 if(winnt_key) RegCloseKey(winnt_key);
2034 return;
2037 static void delete_external_font_keys(void)
2039 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2040 DWORD dlen, vlen, datalen, valuelen, i, type;
2041 LPWSTR valueW;
2042 LPVOID data;
2044 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2045 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2046 ERR("Can't create Windows font reg key\n");
2047 goto end;
2050 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2051 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2052 ERR("Can't create Windows font reg key\n");
2053 goto end;
2056 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2057 ERR("Can't create external font reg key\n");
2058 goto end;
2061 /* Delete all external fonts added last time */
2063 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2064 &valuelen, &datalen, NULL, NULL);
2065 valuelen++; /* returned value doesn't include room for '\0' */
2066 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2067 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2069 dlen = datalen * sizeof(WCHAR);
2070 vlen = valuelen;
2071 i = 0;
2072 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2073 &dlen) == ERROR_SUCCESS) {
2075 RegDeleteValueW(winnt_key, valueW);
2076 RegDeleteValueW(win9x_key, valueW);
2077 /* reset dlen and vlen */
2078 dlen = datalen;
2079 vlen = valuelen;
2081 HeapFree(GetProcessHeap(), 0, data);
2082 HeapFree(GetProcessHeap(), 0, valueW);
2084 /* Delete the old external fonts key */
2085 RegCloseKey(external_key);
2086 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2088 end:
2089 if(win9x_key) RegCloseKey(win9x_key);
2090 if(winnt_key) RegCloseKey(winnt_key);
2093 /*************************************************************
2094 * WineEngAddFontResourceEx
2097 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2099 INT ret = 0;
2101 GDI_CheckNotLock();
2103 if (ft_handle) /* do it only if we have freetype up and running */
2105 char *unixname;
2107 if(flags)
2108 FIXME("Ignoring flags %x\n", flags);
2110 if((unixname = wine_get_unix_file_name(file)))
2112 EnterCriticalSection( &freetype_cs );
2113 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2114 LeaveCriticalSection( &freetype_cs );
2115 HeapFree(GetProcessHeap(), 0, unixname);
2117 if (!ret && !strchrW(file, '\\')) {
2118 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2119 ret = load_font_from_winfonts_dir(file);
2120 if (!ret) {
2121 /* Try in datadir/fonts (or builddir/fonts),
2122 * needed for Magic the Gathering Online
2124 ret = load_font_from_data_dir(file);
2128 return ret;
2131 /*************************************************************
2132 * WineEngAddFontMemResourceEx
2135 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2137 GDI_CheckNotLock();
2139 if (ft_handle) /* do it only if we have freetype up and running */
2141 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2143 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2144 memcpy(pFontCopy, pbFont, cbFont);
2146 EnterCriticalSection( &freetype_cs );
2147 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2148 LeaveCriticalSection( &freetype_cs );
2150 if (*pcFonts == 0)
2152 TRACE("AddFontToList failed\n");
2153 HeapFree(GetProcessHeap(), 0, pFontCopy);
2154 return 0;
2156 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2157 * For now return something unique but quite random
2159 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2160 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2163 *pcFonts = 0;
2164 return 0;
2167 /*************************************************************
2168 * WineEngRemoveFontResourceEx
2171 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2173 GDI_CheckNotLock();
2174 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2175 return TRUE;
2178 static const struct nls_update_font_list
2180 UINT ansi_cp, oem_cp;
2181 const char *oem, *fixed, *system;
2182 const char *courier, *serif, *small, *sserif;
2183 /* these are for font substitutes */
2184 const char *shelldlg, *tmsrmn;
2185 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2186 *helv_0, *tmsrmn_0;
2187 const struct subst
2189 const char *from, *to;
2190 } arial_0, courier_new_0, times_new_roman_0;
2191 } nls_update_font_list[] =
2193 /* Latin 1 (United States) */
2194 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2195 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2196 "Tahoma","Times New Roman",
2197 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2198 { 0 }, { 0 }, { 0 }
2200 /* Latin 1 (Multilingual) */
2201 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2202 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2203 "Tahoma","Times New Roman", /* FIXME unverified */
2204 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2205 { 0 }, { 0 }, { 0 }
2207 /* Eastern Europe */
2208 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2209 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2210 "Tahoma","Times New Roman", /* FIXME unverified */
2211 "Fixedsys,238", "System,238",
2212 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2213 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2214 { "Arial CE,0", "Arial,238" },
2215 { "Courier New CE,0", "Courier New,238" },
2216 { "Times New Roman CE,0", "Times New Roman,238" }
2218 /* Cyrillic */
2219 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2220 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2221 "Tahoma","Times New Roman", /* FIXME unverified */
2222 "Fixedsys,204", "System,204",
2223 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2224 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2225 { "Arial Cyr,0", "Arial,204" },
2226 { "Courier New Cyr,0", "Courier New,204" },
2227 { "Times New Roman Cyr,0", "Times New Roman,204" }
2229 /* Greek */
2230 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2231 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2232 "Tahoma","Times New Roman", /* FIXME unverified */
2233 "Fixedsys,161", "System,161",
2234 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2235 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2236 { "Arial Greek,0", "Arial,161" },
2237 { "Courier New Greek,0", "Courier New,161" },
2238 { "Times New Roman Greek,0", "Times New Roman,161" }
2240 /* Turkish */
2241 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2242 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2243 "Tahoma","Times New Roman", /* FIXME unverified */
2244 "Fixedsys,162", "System,162",
2245 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2246 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2247 { "Arial Tur,0", "Arial,162" },
2248 { "Courier New Tur,0", "Courier New,162" },
2249 { "Times New Roman Tur,0", "Times New Roman,162" }
2251 /* Hebrew */
2252 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2253 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2254 "Tahoma","Times New Roman", /* FIXME unverified */
2255 "Fixedsys,177", "System,177",
2256 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2257 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2258 { 0 }, { 0 }, { 0 }
2260 /* Arabic */
2261 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2262 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2263 "Tahoma","Times New Roman", /* FIXME unverified */
2264 "Fixedsys,178", "System,178",
2265 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2266 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2267 { 0 }, { 0 }, { 0 }
2269 /* Baltic */
2270 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2271 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2272 "Tahoma","Times New Roman", /* FIXME unverified */
2273 "Fixedsys,186", "System,186",
2274 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2275 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2276 { "Arial Baltic,0", "Arial,186" },
2277 { "Courier New Baltic,0", "Courier New,186" },
2278 { "Times New Roman Baltic,0", "Times New Roman,186" }
2280 /* Vietnamese */
2281 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2282 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2283 "Tahoma","Times New Roman", /* FIXME unverified */
2284 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2285 { 0 }, { 0 }, { 0 }
2287 /* Thai */
2288 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2289 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2290 "Tahoma","Times New Roman", /* FIXME unverified */
2291 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2292 { 0 }, { 0 }, { 0 }
2294 /* Japanese */
2295 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2296 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2297 "MS UI Gothic","MS Serif",
2298 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2299 { 0 }, { 0 }, { 0 }
2301 /* Chinese Simplified */
2302 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2303 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2304 "SimSun", "NSimSun",
2305 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2306 { 0 }, { 0 }, { 0 }
2308 /* Korean */
2309 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2310 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2311 "Gulim", "Batang",
2312 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2313 { 0 }, { 0 }, { 0 }
2315 /* Chinese Traditional */
2316 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2317 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2318 "PMingLiU", "MingLiU",
2319 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2320 { 0 }, { 0 }, { 0 }
2324 static const WCHAR *font_links_list[] =
2326 Lucida_Sans_Unicode,
2327 Microsoft_Sans_Serif,
2328 Tahoma
2331 static const struct font_links_defaults_list
2333 /* Keyed off substitution for "MS Shell Dlg" */
2334 const WCHAR *shelldlg;
2335 /* Maximum of four substitutes, plus terminating NULL pointer */
2336 const WCHAR *substitutes[5];
2337 } font_links_defaults_list[] =
2339 /* Non East-Asian */
2340 { Tahoma, /* FIXME unverified ordering */
2341 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2343 /* Below lists are courtesy of
2344 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2346 /* Japanese */
2347 { MS_UI_Gothic,
2348 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2350 /* Chinese Simplified */
2351 { SimSun,
2352 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2354 /* Korean */
2355 { Gulim,
2356 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2358 /* Chinese Traditional */
2359 { PMingLiU,
2360 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2364 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2366 return ( ansi_cp == 932 /* CP932 for Japanese */
2367 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2368 || ansi_cp == 949 /* CP949 for Korean */
2369 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2372 static inline HKEY create_fonts_NT_registry_key(void)
2374 HKEY hkey = 0;
2376 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2377 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2378 return hkey;
2381 static inline HKEY create_fonts_9x_registry_key(void)
2383 HKEY hkey = 0;
2385 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2386 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2387 return hkey;
2390 static inline HKEY create_config_fonts_registry_key(void)
2392 HKEY hkey = 0;
2394 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2395 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2396 return hkey;
2399 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2401 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2402 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2403 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2404 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2407 static void set_value_key(HKEY hkey, const char *name, const char *value)
2409 if (value)
2410 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2411 else if (name)
2412 RegDeleteValueA(hkey, name);
2415 static void update_font_info(void)
2417 char buf[40], cpbuf[40];
2418 DWORD len, type;
2419 HKEY hkey = 0;
2420 UINT i, ansi_cp = 0, oem_cp = 0;
2421 BOOL done = FALSE;
2423 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2424 return;
2426 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2427 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2428 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2429 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2430 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2432 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2433 if (is_dbcs_ansi_cp(ansi_cp))
2434 use_default_fallback = TRUE;
2436 len = sizeof(buf);
2437 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2439 if (!strcmp( buf, cpbuf )) /* already set correctly */
2441 RegCloseKey(hkey);
2442 return;
2444 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2446 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2448 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2449 RegCloseKey(hkey);
2451 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2453 HKEY hkey;
2455 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2456 nls_update_font_list[i].oem_cp == oem_cp)
2458 hkey = create_config_fonts_registry_key();
2459 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2460 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2461 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2462 RegCloseKey(hkey);
2464 hkey = create_fonts_NT_registry_key();
2465 add_font_list(hkey, &nls_update_font_list[i]);
2466 RegCloseKey(hkey);
2468 hkey = create_fonts_9x_registry_key();
2469 add_font_list(hkey, &nls_update_font_list[i]);
2470 RegCloseKey(hkey);
2472 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2474 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2475 strlen(nls_update_font_list[i].shelldlg)+1);
2476 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2477 strlen(nls_update_font_list[i].tmsrmn)+1);
2479 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2480 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2481 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2482 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2483 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2484 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2485 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2486 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2488 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2489 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2490 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2492 RegCloseKey(hkey);
2494 done = TRUE;
2496 else
2498 /* Delete the FontSubstitutes from other locales */
2499 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2501 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2502 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2503 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2504 RegCloseKey(hkey);
2508 if (!done)
2509 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2511 /* Clear out system links */
2512 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2515 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2517 const WCHAR *value;
2518 int i;
2519 FontSubst *psub;
2520 Family *family;
2521 Face *face;
2522 const char *file;
2523 WCHAR *fileW;
2524 int fileLen;
2525 WCHAR buff[MAX_PATH];
2526 WCHAR *data;
2527 int entryLen;
2529 static const WCHAR comma[] = {',',0};
2531 RegDeleteValueW(hkey, name);
2532 if (values)
2534 data = buff;
2535 data[0] = '\0';
2536 for (i = 0; values[i] != NULL; i++)
2538 value = values[i];
2539 if (!strcmpiW(name,value))
2540 continue;
2541 psub = get_font_subst(&font_subst_list, value, -1);
2542 if(psub)
2543 value = psub->to.name;
2544 family = find_family_from_name(value);
2545 if (!family)
2546 continue;
2547 file = NULL;
2548 /* Use first extant filename for this Family */
2549 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2551 if (!face->file)
2552 continue;
2553 file = strrchr(face->file, '/');
2554 if (!file)
2555 file = face->file;
2556 else
2557 file++;
2558 break;
2560 if (!file)
2561 continue;
2562 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2563 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2564 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2565 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2566 if (sizeof(buff)-(data-buff) < entryLen + 1)
2568 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2569 HeapFree(GetProcessHeap(), 0, fileW);
2570 break;
2572 strcpyW(data, fileW);
2573 strcatW(data, comma);
2574 strcatW(data, value);
2575 data += entryLen;
2576 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2577 HeapFree(GetProcessHeap(), 0, fileW);
2579 if (data != buff)
2581 *data='\0';
2582 data++;
2583 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2584 } else
2585 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2586 } else
2587 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2590 static void update_system_links(void)
2592 HKEY hkey = 0;
2593 UINT i, j;
2594 BOOL done = FALSE;
2595 DWORD disposition;
2596 FontSubst *psub;
2598 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2600 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2602 if (disposition == REG_OPENED_EXISTING_KEY)
2604 TRACE("SystemLink key already exists, doing nothing\n");
2605 RegCloseKey(hkey);
2606 return;
2609 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2610 if (!psub) {
2611 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2612 RegCloseKey(hkey);
2613 return;
2616 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2618 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2620 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2621 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2623 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2624 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2625 done = TRUE;
2627 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2629 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2632 RegCloseKey(hkey);
2633 if (!done)
2634 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2635 } else
2636 WARN("failed to create SystemLink key\n");
2640 static BOOL init_freetype(void)
2642 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2643 if(!ft_handle) {
2644 WINE_MESSAGE(
2645 "Wine cannot find the FreeType font library. To enable Wine to\n"
2646 "use TrueType fonts please install a version of FreeType greater than\n"
2647 "or equal to 2.0.5.\n"
2648 "http://www.freetype.org\n");
2649 return FALSE;
2652 #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;}
2654 LOAD_FUNCPTR(FT_Vector_Unit)
2655 LOAD_FUNCPTR(FT_Done_Face)
2656 LOAD_FUNCPTR(FT_Get_Char_Index)
2657 LOAD_FUNCPTR(FT_Get_Module)
2658 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2659 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2660 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2661 LOAD_FUNCPTR(FT_Init_FreeType)
2662 LOAD_FUNCPTR(FT_Load_Glyph)
2663 LOAD_FUNCPTR(FT_Matrix_Multiply)
2664 #ifndef FT_MULFIX_INLINED
2665 LOAD_FUNCPTR(FT_MulFix)
2666 #endif
2667 LOAD_FUNCPTR(FT_New_Face)
2668 LOAD_FUNCPTR(FT_New_Memory_Face)
2669 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2670 LOAD_FUNCPTR(FT_Outline_Transform)
2671 LOAD_FUNCPTR(FT_Outline_Translate)
2672 LOAD_FUNCPTR(FT_Select_Charmap)
2673 LOAD_FUNCPTR(FT_Set_Charmap)
2674 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2675 LOAD_FUNCPTR(FT_Vector_Transform)
2676 LOAD_FUNCPTR(FT_Render_Glyph)
2678 #undef LOAD_FUNCPTR
2679 /* Don't warn if these ones are missing */
2680 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2681 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2682 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2683 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2684 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2685 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2686 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2687 #endif
2688 #ifdef HAVE_FREETYPE_FTWINFNT_H
2689 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2690 #endif
2691 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2692 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2693 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2694 <= 2.0.3 has FT_Sqrt64 */
2695 goto sym_not_found;
2698 if(pFT_Init_FreeType(&library) != 0) {
2699 ERR("Can't init FreeType library\n");
2700 wine_dlclose(ft_handle, NULL, 0);
2701 ft_handle = NULL;
2702 return FALSE;
2704 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2705 if (pFT_Library_Version)
2706 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2708 if (FT_Version.major<=0)
2710 FT_Version.major=2;
2711 FT_Version.minor=0;
2712 FT_Version.patch=5;
2714 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2715 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2716 ((FT_Version.minor << 8) & 0x00ff00) |
2717 ((FT_Version.patch ) & 0x0000ff);
2719 return TRUE;
2721 sym_not_found:
2722 WINE_MESSAGE(
2723 "Wine cannot find certain functions that it needs inside the FreeType\n"
2724 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2725 "FreeType to at least version 2.0.5.\n"
2726 "http://www.freetype.org\n");
2727 wine_dlclose(ft_handle, NULL, 0);
2728 ft_handle = NULL;
2729 return FALSE;
2732 /*************************************************************
2733 * WineEngInit
2735 * Initialize FreeType library and create a list of available faces
2737 BOOL WineEngInit(void)
2739 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2740 static const WCHAR pathW[] = {'P','a','t','h',0};
2741 HKEY hkey;
2742 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2743 WCHAR windowsdir[MAX_PATH];
2744 char *unixname;
2745 HANDLE font_mutex;
2746 const char *data_dir;
2748 TRACE("\n");
2750 /* update locale dependent font info in registry */
2751 update_font_info();
2753 if(!init_freetype()) return FALSE;
2755 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2756 ERR("Failed to create font mutex\n");
2757 return FALSE;
2759 WaitForSingleObject(font_mutex, INFINITE);
2761 delete_external_font_keys();
2763 /* load the system bitmap fonts */
2764 load_system_fonts();
2766 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2767 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2768 strcatW(windowsdir, fontsW);
2769 if((unixname = wine_get_unix_file_name(windowsdir)))
2771 ReadFontDir(unixname, FALSE);
2772 HeapFree(GetProcessHeap(), 0, unixname);
2775 /* load the system truetype fonts */
2776 data_dir = wine_get_data_dir();
2777 if (!data_dir) data_dir = wine_get_build_dir();
2778 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2779 strcpy(unixname, data_dir);
2780 strcat(unixname, "/fonts/");
2781 ReadFontDir(unixname, TRUE);
2782 HeapFree(GetProcessHeap(), 0, unixname);
2785 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2786 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2787 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2788 will skip these. */
2789 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2790 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2791 &hkey) == ERROR_SUCCESS) {
2792 LPWSTR data, valueW;
2793 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2794 &valuelen, &datalen, NULL, NULL);
2796 valuelen++; /* returned value doesn't include room for '\0' */
2797 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2798 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2799 if (valueW && data)
2801 dlen = datalen * sizeof(WCHAR);
2802 vlen = valuelen;
2803 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
2804 &dlen) == ERROR_SUCCESS) {
2805 if(data[0] && (data[1] == ':'))
2807 if((unixname = wine_get_unix_file_name(data)))
2809 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2810 HeapFree(GetProcessHeap(), 0, unixname);
2813 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
2815 WCHAR pathW[MAX_PATH];
2816 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2817 BOOL added = FALSE;
2819 sprintfW(pathW, fmtW, windowsdir, data);
2820 if((unixname = wine_get_unix_file_name(pathW)))
2822 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2823 HeapFree(GetProcessHeap(), 0, unixname);
2825 if (!added)
2826 load_font_from_data_dir(data);
2828 /* reset dlen and vlen */
2829 dlen = datalen;
2830 vlen = valuelen;
2833 HeapFree(GetProcessHeap(), 0, data);
2834 HeapFree(GetProcessHeap(), 0, valueW);
2835 RegCloseKey(hkey);
2838 load_fontconfig_fonts();
2840 /* then look in any directories that we've specified in the config file */
2841 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2842 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2844 DWORD len;
2845 LPWSTR valueW;
2846 LPSTR valueA, ptr;
2848 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2850 len += sizeof(WCHAR);
2851 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2852 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2854 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2855 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2856 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2857 TRACE( "got font path %s\n", debugstr_a(valueA) );
2858 ptr = valueA;
2859 while (ptr)
2861 LPSTR next = strchr( ptr, ':' );
2862 if (next) *next++ = 0;
2863 ReadFontDir( ptr, TRUE );
2864 ptr = next;
2866 HeapFree( GetProcessHeap(), 0, valueA );
2868 HeapFree( GetProcessHeap(), 0, valueW );
2870 RegCloseKey(hkey);
2873 DumpFontList();
2874 LoadSubstList();
2875 DumpSubstList();
2876 LoadReplaceList();
2877 update_reg_entries();
2879 update_system_links();
2880 init_system_links();
2882 ReleaseMutex(font_mutex);
2883 return TRUE;
2887 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2889 TT_OS2 *pOS2;
2890 TT_HoriHeader *pHori;
2892 LONG ppem;
2894 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2895 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2897 if(height == 0) height = 16;
2899 /* Calc. height of EM square:
2901 * For +ve lfHeight we have
2902 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2903 * Re-arranging gives:
2904 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2906 * For -ve lfHeight we have
2907 * |lfHeight| = ppem
2908 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2909 * with il = winAscent + winDescent - units_per_em]
2913 if(height > 0) {
2914 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2915 ppem = MulDiv(ft_face->units_per_EM, height,
2916 pHori->Ascender - pHori->Descender);
2917 else
2918 ppem = MulDiv(ft_face->units_per_EM, height,
2919 pOS2->usWinAscent + pOS2->usWinDescent);
2921 else
2922 ppem = -height;
2924 return ppem;
2927 static struct font_mapping *map_font_file( const char *name )
2929 struct font_mapping *mapping;
2930 struct stat st;
2931 int fd;
2933 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2934 if (fstat( fd, &st ) == -1) goto error;
2936 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2938 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2940 mapping->refcount++;
2941 close( fd );
2942 return mapping;
2945 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2946 goto error;
2948 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2949 close( fd );
2951 if (mapping->data == MAP_FAILED)
2953 HeapFree( GetProcessHeap(), 0, mapping );
2954 return NULL;
2956 mapping->refcount = 1;
2957 mapping->dev = st.st_dev;
2958 mapping->ino = st.st_ino;
2959 mapping->size = st.st_size;
2960 list_add_tail( &mappings_list, &mapping->entry );
2961 return mapping;
2963 error:
2964 close( fd );
2965 return NULL;
2968 static void unmap_font_file( struct font_mapping *mapping )
2970 if (!--mapping->refcount)
2972 list_remove( &mapping->entry );
2973 munmap( mapping->data, mapping->size );
2974 HeapFree( GetProcessHeap(), 0, mapping );
2978 static LONG load_VDMX(GdiFont*, LONG);
2980 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2982 FT_Error err;
2983 FT_Face ft_face;
2984 void *data_ptr;
2985 DWORD data_size;
2987 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2989 if (face->file)
2991 if (!(font->mapping = map_font_file( face->file )))
2993 WARN("failed to map %s\n", debugstr_a(face->file));
2994 return 0;
2996 data_ptr = font->mapping->data;
2997 data_size = font->mapping->size;
2999 else
3001 data_ptr = face->font_data_ptr;
3002 data_size = face->font_data_size;
3005 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3006 if(err) {
3007 ERR("FT_New_Face rets %d\n", err);
3008 return 0;
3011 /* set it here, as load_VDMX needs it */
3012 font->ft_face = ft_face;
3014 if(FT_IS_SCALABLE(ft_face)) {
3015 /* load the VDMX table if we have one */
3016 font->ppem = load_VDMX(font, height);
3017 if(font->ppem == 0)
3018 font->ppem = calc_ppem_for_height(ft_face, height);
3019 TRACE("height %d => ppem %d\n", height, font->ppem);
3021 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3022 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3023 } else {
3024 font->ppem = height;
3025 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3026 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3028 return ft_face;
3032 static int get_nearest_charset(Face *face, int *cp)
3034 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3035 a single face with the requested charset. The idea is to check if
3036 the selected font supports the current ANSI codepage, if it does
3037 return the corresponding charset, else return the first charset */
3039 CHARSETINFO csi;
3040 int acp = GetACP(), i;
3041 DWORD fs0;
3043 *cp = acp;
3044 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3045 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3046 return csi.ciCharset;
3048 for(i = 0; i < 32; i++) {
3049 fs0 = 1L << i;
3050 if(face->fs.fsCsb[0] & fs0) {
3051 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3052 *cp = csi.ciACP;
3053 return csi.ciCharset;
3055 else
3056 FIXME("TCI failing on %x\n", fs0);
3060 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3061 face->fs.fsCsb[0], face->file);
3062 *cp = acp;
3063 return DEFAULT_CHARSET;
3066 static GdiFont *alloc_font(void)
3068 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3069 ret->gmsize = 1;
3070 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3071 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3072 ret->potm = NULL;
3073 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3074 ret->total_kern_pairs = (DWORD)-1;
3075 ret->kern_pairs = NULL;
3076 list_init(&ret->hfontlist);
3077 list_init(&ret->child_fonts);
3078 return ret;
3081 static void free_font(GdiFont *font)
3083 struct list *cursor, *cursor2;
3084 DWORD i;
3086 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3088 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3089 struct list *first_hfont;
3090 HFONTLIST *hfontlist;
3091 list_remove(cursor);
3092 if(child->font)
3094 first_hfont = list_head(&child->font->hfontlist);
3095 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3096 DeleteObject(hfontlist->hfont);
3097 HeapFree(GetProcessHeap(), 0, hfontlist);
3098 free_font(child->font);
3100 HeapFree(GetProcessHeap(), 0, child);
3103 if (font->ft_face) pFT_Done_Face(font->ft_face);
3104 if (font->mapping) unmap_font_file( font->mapping );
3105 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3106 HeapFree(GetProcessHeap(), 0, font->potm);
3107 HeapFree(GetProcessHeap(), 0, font->name);
3108 for (i = 0; i < font->gmsize; i++)
3109 HeapFree(GetProcessHeap(),0,font->gm[i]);
3110 HeapFree(GetProcessHeap(), 0, font->gm);
3111 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3112 HeapFree(GetProcessHeap(), 0, font);
3116 /*************************************************************
3117 * load_VDMX
3119 * load the vdmx entry for the specified height
3122 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3123 ( ( (FT_ULong)_x4 << 24 ) | \
3124 ( (FT_ULong)_x3 << 16 ) | \
3125 ( (FT_ULong)_x2 << 8 ) | \
3126 (FT_ULong)_x1 )
3128 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3130 typedef struct {
3131 BYTE bCharSet;
3132 BYTE xRatio;
3133 BYTE yStartRatio;
3134 BYTE yEndRatio;
3135 } Ratios;
3137 typedef struct {
3138 WORD recs;
3139 BYTE startsz;
3140 BYTE endsz;
3141 } VDMX_group;
3143 static LONG load_VDMX(GdiFont *font, LONG height)
3145 WORD hdr[3], tmp;
3146 VDMX_group group;
3147 BYTE devXRatio, devYRatio;
3148 USHORT numRecs, numRatios;
3149 DWORD result, offset = -1;
3150 LONG ppem = 0;
3151 int i;
3153 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
3155 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3156 return ppem;
3158 /* FIXME: need the real device aspect ratio */
3159 devXRatio = 1;
3160 devYRatio = 1;
3162 numRecs = GET_BE_WORD(hdr[1]);
3163 numRatios = GET_BE_WORD(hdr[2]);
3165 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3166 for(i = 0; i < numRatios; i++) {
3167 Ratios ratio;
3169 offset = (3 * 2) + (i * sizeof(Ratios));
3170 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3171 offset = -1;
3173 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3175 if((ratio.xRatio == 0 &&
3176 ratio.yStartRatio == 0 &&
3177 ratio.yEndRatio == 0) ||
3178 (devXRatio == ratio.xRatio &&
3179 devYRatio >= ratio.yStartRatio &&
3180 devYRatio <= ratio.yEndRatio))
3182 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3183 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3184 offset = GET_BE_WORD(tmp);
3185 break;
3189 if(offset == -1) {
3190 FIXME("No suitable ratio found\n");
3191 return ppem;
3194 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3195 USHORT recs;
3196 BYTE startsz, endsz;
3197 WORD *vTable;
3199 recs = GET_BE_WORD(group.recs);
3200 startsz = group.startsz;
3201 endsz = group.endsz;
3203 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3205 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3206 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3207 if(result == GDI_ERROR) {
3208 FIXME("Failed to retrieve vTable\n");
3209 goto end;
3212 if(height > 0) {
3213 for(i = 0; i < recs; i++) {
3214 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3215 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3216 ppem = GET_BE_WORD(vTable[i * 3]);
3218 if(yMax + -yMin == height) {
3219 font->yMax = yMax;
3220 font->yMin = yMin;
3221 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3222 break;
3224 if(yMax + -yMin > height) {
3225 if(--i < 0) {
3226 ppem = 0;
3227 goto end; /* failed */
3229 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3230 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3231 ppem = GET_BE_WORD(vTable[i * 3]);
3232 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3233 break;
3236 if(!font->yMax) {
3237 ppem = 0;
3238 TRACE("ppem not found for height %d\n", height);
3241 end:
3242 HeapFree(GetProcessHeap(), 0, vTable);
3245 return ppem;
3248 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3250 if(font->font_desc.hash != fd->hash) return TRUE;
3251 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3252 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3253 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3254 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3257 static void calc_hash(FONT_DESC *pfd)
3259 DWORD hash = 0, *ptr, two_chars;
3260 WORD *pwc;
3261 unsigned int i;
3263 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3264 hash ^= *ptr;
3265 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3266 hash ^= *ptr;
3267 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3268 two_chars = *ptr;
3269 pwc = (WCHAR *)&two_chars;
3270 if(!*pwc) break;
3271 *pwc = toupperW(*pwc);
3272 pwc++;
3273 *pwc = toupperW(*pwc);
3274 hash ^= two_chars;
3275 if(!*pwc) break;
3277 hash ^= !pfd->can_use_bitmap;
3278 pfd->hash = hash;
3279 return;
3282 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3284 GdiFont *ret;
3285 FONT_DESC fd;
3286 HFONTLIST *hflist;
3287 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3289 fd.lf = *plf;
3290 fd.matrix = *pmat;
3291 fd.can_use_bitmap = can_use_bitmap;
3292 calc_hash(&fd);
3294 /* try the child list */
3295 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3296 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3297 if(!fontcmp(ret, &fd)) {
3298 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3299 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3300 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3301 if(hflist->hfont == hfont)
3302 return ret;
3307 /* try the in-use list */
3308 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3309 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3310 if(!fontcmp(ret, &fd)) {
3311 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3312 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3313 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3314 if(hflist->hfont == hfont)
3315 return ret;
3317 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3318 hflist->hfont = hfont;
3319 list_add_head(&ret->hfontlist, &hflist->entry);
3320 return ret;
3324 /* then the unused list */
3325 font_elem_ptr = list_head(&unused_gdi_font_list);
3326 while(font_elem_ptr) {
3327 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3328 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3329 if(!fontcmp(ret, &fd)) {
3330 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3331 assert(list_empty(&ret->hfontlist));
3332 TRACE("Found %p in unused list\n", ret);
3333 list_remove(&ret->entry);
3334 list_add_head(&gdi_font_list, &ret->entry);
3335 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3336 hflist->hfont = hfont;
3337 list_add_head(&ret->hfontlist, &hflist->entry);
3338 return ret;
3341 return NULL;
3344 static void add_to_cache(GdiFont *font)
3346 static DWORD cache_num = 1;
3348 font->cache_num = cache_num++;
3349 list_add_head(&gdi_font_list, &font->entry);
3352 /*************************************************************
3353 * create_child_font_list
3355 static BOOL create_child_font_list(GdiFont *font)
3357 BOOL ret = FALSE;
3358 SYSTEM_LINKS *font_link;
3359 CHILD_FONT *font_link_entry, *new_child;
3360 FontSubst *psub;
3361 WCHAR* font_name;
3363 psub = get_font_subst(&font_subst_list, font->name, -1);
3364 font_name = psub ? psub->to.name : font->name;
3365 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3367 if(!strcmpiW(font_link->font_name, font_name))
3369 TRACE("found entry in system list\n");
3370 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3372 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3373 new_child->face = font_link_entry->face;
3374 new_child->font = NULL;
3375 list_add_tail(&font->child_fonts, &new_child->entry);
3376 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3378 ret = TRUE;
3379 break;
3383 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3384 * Sans Serif. This is how asian windows get default fallbacks for fonts
3386 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3387 font->charset != OEM_CHARSET &&
3388 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3389 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3391 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3393 TRACE("found entry in default fallback list\n");
3394 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3396 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3397 new_child->face = font_link_entry->face;
3398 new_child->font = NULL;
3399 list_add_tail(&font->child_fonts, &new_child->entry);
3400 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3402 ret = TRUE;
3403 break;
3407 return ret;
3410 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3412 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3414 if (pFT_Set_Charmap)
3416 FT_Int i;
3417 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3419 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3421 for (i = 0; i < ft_face->num_charmaps; i++)
3423 if (ft_face->charmaps[i]->encoding == encoding)
3425 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3426 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3428 switch (ft_face->charmaps[i]->platform_id)
3430 default:
3431 cmap_def = ft_face->charmaps[i];
3432 break;
3433 case 0: /* Apple Unicode */
3434 cmap0 = ft_face->charmaps[i];
3435 break;
3436 case 1: /* Macintosh */
3437 cmap1 = ft_face->charmaps[i];
3438 break;
3439 case 2: /* ISO */
3440 cmap2 = ft_face->charmaps[i];
3441 break;
3442 case 3: /* Microsoft */
3443 cmap3 = ft_face->charmaps[i];
3444 break;
3448 if (cmap3) /* prefer Microsoft cmap table */
3449 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3450 else if (cmap1)
3451 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3452 else if (cmap2)
3453 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3454 else if (cmap0)
3455 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3456 else if (cmap_def)
3457 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3459 return ft_err == FT_Err_Ok;
3462 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3465 /*************************************************************
3466 * WineEngCreateFontInstance
3469 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3471 GdiFont *ret;
3472 Face *face, *best, *best_bitmap;
3473 Family *family, *last_resort_family;
3474 struct list *family_elem_ptr, *face_elem_ptr;
3475 INT height, width = 0;
3476 unsigned int score = 0, new_score;
3477 signed int diff = 0, newdiff;
3478 BOOL bd, it, can_use_bitmap;
3479 LOGFONTW lf;
3480 CHARSETINFO csi;
3481 HFONTLIST *hflist;
3482 FMAT2 dcmat;
3483 FontSubst *psub = NULL;
3485 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3486 lf.lfWidth = abs(lf.lfWidth);
3488 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3490 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3491 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3492 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3493 lf.lfEscapement);
3495 if(dc->GraphicsMode == GM_ADVANCED)
3496 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3497 else
3499 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3500 font scaling abilities. */
3501 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3502 dcmat.eM21 = dcmat.eM12 = 0;
3505 /* Try to avoid not necessary glyph transformations */
3506 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3508 lf.lfHeight *= fabs(dcmat.eM11);
3509 lf.lfWidth *= fabs(dcmat.eM11);
3510 dcmat.eM11 = dcmat.eM22 = 1.0;
3513 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3514 dcmat.eM21, dcmat.eM22);
3516 GDI_CheckNotLock();
3517 EnterCriticalSection( &freetype_cs );
3519 /* check the cache first */
3520 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3521 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3522 LeaveCriticalSection( &freetype_cs );
3523 return ret;
3526 TRACE("not in cache\n");
3527 if(list_empty(&font_list)) /* No fonts installed */
3529 TRACE("No fonts installed\n");
3530 LeaveCriticalSection( &freetype_cs );
3531 return NULL;
3533 if(!have_installed_roman_font)
3535 TRACE("No roman font installed\n");
3536 LeaveCriticalSection( &freetype_cs );
3537 return NULL;
3540 ret = alloc_font();
3542 ret->font_desc.matrix = dcmat;
3543 ret->font_desc.lf = lf;
3544 ret->font_desc.can_use_bitmap = can_use_bitmap;
3545 calc_hash(&ret->font_desc);
3546 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3547 hflist->hfont = hfont;
3548 list_add_head(&ret->hfontlist, &hflist->entry);
3550 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3551 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3552 original value lfCharSet. Note this is a special case for
3553 Symbol and doesn't happen at least for "Wingdings*" */
3555 if(!strcmpiW(lf.lfFaceName, SymbolW))
3556 lf.lfCharSet = SYMBOL_CHARSET;
3558 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3559 switch(lf.lfCharSet) {
3560 case DEFAULT_CHARSET:
3561 csi.fs.fsCsb[0] = 0;
3562 break;
3563 default:
3564 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3565 csi.fs.fsCsb[0] = 0;
3566 break;
3570 family = NULL;
3571 if(lf.lfFaceName[0] != '\0') {
3572 SYSTEM_LINKS *font_link;
3573 CHILD_FONT *font_link_entry;
3574 LPWSTR FaceName = lf.lfFaceName;
3577 * Check for a leading '@' this signals that the font is being
3578 * requested in tategaki mode (vertical writing substitution) but
3579 * does not affect the fontface that is to be selected.
3581 if (lf.lfFaceName[0]=='@')
3582 FaceName = &lf.lfFaceName[1];
3584 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3586 if(psub) {
3587 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3588 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3589 if (psub->to.charset != -1)
3590 lf.lfCharSet = psub->to.charset;
3593 /* We want a match on name and charset or just name if
3594 charset was DEFAULT_CHARSET. If the latter then
3595 we fixup the returned charset later in get_nearest_charset
3596 where we'll either use the charset of the current ansi codepage
3597 or if that's unavailable the first charset that the font supports.
3599 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3600 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3601 if (!strcmpiW(family->FamilyName, FaceName) ||
3602 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3604 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3605 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3606 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3607 if(face->scalable || can_use_bitmap)
3608 goto found;
3614 * Try check the SystemLink list first for a replacement font.
3615 * We may find good replacements there.
3617 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3619 if(!strcmpiW(font_link->font_name, FaceName) ||
3620 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3622 TRACE("found entry in system list\n");
3623 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3625 face = font_link_entry->face;
3626 family = face->family;
3627 if(csi.fs.fsCsb[0] &
3628 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3630 if(face->scalable || can_use_bitmap)
3631 goto found;
3638 psub = NULL; /* substitution is no more relevant */
3640 /* If requested charset was DEFAULT_CHARSET then try using charset
3641 corresponding to the current ansi codepage */
3642 if (!csi.fs.fsCsb[0])
3644 INT acp = GetACP();
3645 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3646 FIXME("TCI failed on codepage %d\n", acp);
3647 csi.fs.fsCsb[0] = 0;
3648 } else
3649 lf.lfCharSet = csi.ciCharset;
3652 /* Face families are in the top 4 bits of lfPitchAndFamily,
3653 so mask with 0xF0 before testing */
3655 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3656 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3657 strcpyW(lf.lfFaceName, defFixed);
3658 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3659 strcpyW(lf.lfFaceName, defSerif);
3660 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3661 strcpyW(lf.lfFaceName, defSans);
3662 else
3663 strcpyW(lf.lfFaceName, defSans);
3664 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3665 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3666 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3667 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3668 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3669 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3670 if(face->scalable || can_use_bitmap)
3671 goto found;
3676 last_resort_family = NULL;
3677 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3678 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3679 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3680 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3681 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3682 if(face->scalable)
3683 goto found;
3684 if(can_use_bitmap && !last_resort_family)
3685 last_resort_family = family;
3690 if(last_resort_family) {
3691 family = last_resort_family;
3692 csi.fs.fsCsb[0] = 0;
3693 goto found;
3696 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3697 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3698 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3699 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3700 if(face->scalable) {
3701 csi.fs.fsCsb[0] = 0;
3702 WARN("just using first face for now\n");
3703 goto found;
3705 if(can_use_bitmap && !last_resort_family)
3706 last_resort_family = family;
3709 if(!last_resort_family) {
3710 FIXME("can't find a single appropriate font - bailing\n");
3711 free_font(ret);
3712 LeaveCriticalSection( &freetype_cs );
3713 return NULL;
3716 WARN("could only find a bitmap font - this will probably look awful!\n");
3717 family = last_resort_family;
3718 csi.fs.fsCsb[0] = 0;
3720 found:
3721 it = lf.lfItalic ? 1 : 0;
3722 bd = lf.lfWeight > 550 ? 1 : 0;
3724 height = lf.lfHeight;
3726 face = best = best_bitmap = NULL;
3727 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3729 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3731 BOOL italic, bold;
3733 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3734 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3735 new_score = (italic ^ it) + (bold ^ bd);
3736 if(!best || new_score <= score)
3738 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3739 italic, bold, it, bd);
3740 score = new_score;
3741 best = face;
3742 if(best->scalable && score == 0) break;
3743 if(!best->scalable)
3745 if(height > 0)
3746 newdiff = height - (signed int)(best->size.height);
3747 else
3748 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3749 if(!best_bitmap || new_score < score ||
3750 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3752 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3753 diff = newdiff;
3754 best_bitmap = best;
3755 if(score == 0 && diff == 0) break;
3761 if(best)
3762 face = best->scalable ? best : best_bitmap;
3763 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3764 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3766 ret->fs = face->fs;
3768 if(csi.fs.fsCsb[0]) {
3769 ret->charset = lf.lfCharSet;
3770 ret->codepage = csi.ciACP;
3772 else
3773 ret->charset = get_nearest_charset(face, &ret->codepage);
3775 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3776 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3778 ret->aveWidth = height ? lf.lfWidth : 0;
3780 if(!face->scalable) {
3781 /* Windows uses integer scaling factors for bitmap fonts */
3782 INT scale, scaled_height;
3783 GdiFont *cachedfont;
3785 /* FIXME: rotation of bitmap fonts is ignored */
3786 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3787 if (ret->aveWidth)
3788 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3789 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3790 dcmat.eM11 = dcmat.eM22 = 1.0;
3791 /* As we changed the matrix, we need to search the cache for the font again,
3792 * otherwise we might explode the cache. */
3793 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3794 TRACE("Found cached font after non-scalable matrix rescale!\n");
3795 free_font( ret );
3796 LeaveCriticalSection( &freetype_cs );
3797 return cachedfont;
3799 calc_hash(&ret->font_desc);
3801 if (height != 0) height = diff;
3802 height += face->size.height;
3804 scale = (height + face->size.height - 1) / face->size.height;
3805 scaled_height = scale * face->size.height;
3806 /* Only jump to the next height if the difference <= 25% original height */
3807 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
3808 /* The jump between unscaled and doubled is delayed by 1 */
3809 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
3810 ret->scale_y = scale;
3812 width = face->size.x_ppem >> 6;
3813 height = face->size.y_ppem >> 6;
3815 else
3816 ret->scale_y = 1.0;
3817 TRACE("font scale y: %f\n", ret->scale_y);
3819 ret->ft_face = OpenFontFace(ret, face, width, height);
3821 if (!ret->ft_face)
3823 free_font( ret );
3824 LeaveCriticalSection( &freetype_cs );
3825 return 0;
3828 ret->ntmFlags = face->ntmFlags;
3830 if (ret->charset == SYMBOL_CHARSET &&
3831 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3832 /* No ops */
3834 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3835 /* No ops */
3837 else {
3838 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3841 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3842 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3843 ret->underline = lf.lfUnderline ? 0xff : 0;
3844 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3845 create_child_font_list(ret);
3847 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3849 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3850 if (length != GDI_ERROR)
3852 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3853 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3854 TRACE("Loaded GSUB table of %i bytes\n",length);
3858 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3860 add_to_cache(ret);
3861 LeaveCriticalSection( &freetype_cs );
3862 return ret;
3865 static void dump_gdi_font_list(void)
3867 GdiFont *gdiFont;
3868 struct list *elem_ptr;
3870 TRACE("---------- gdiFont Cache ----------\n");
3871 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3872 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3873 TRACE("gdiFont=%p %s %d\n",
3874 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3877 TRACE("---------- Unused gdiFont Cache ----------\n");
3878 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3879 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3880 TRACE("gdiFont=%p %s %d\n",
3881 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3885 /*************************************************************
3886 * WineEngDestroyFontInstance
3888 * free the gdiFont associated with this handle
3891 BOOL WineEngDestroyFontInstance(HFONT handle)
3893 GdiFont *gdiFont;
3894 HFONTLIST *hflist;
3895 BOOL ret = FALSE;
3896 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3897 int i = 0;
3899 GDI_CheckNotLock();
3900 EnterCriticalSection( &freetype_cs );
3902 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3904 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3905 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3906 if(hflist->hfont == handle)
3908 TRACE("removing child font %p from child list\n", gdiFont);
3909 list_remove(&gdiFont->entry);
3910 LeaveCriticalSection( &freetype_cs );
3911 return TRUE;
3915 TRACE("destroying hfont=%p\n", handle);
3916 if(TRACE_ON(font))
3917 dump_gdi_font_list();
3919 font_elem_ptr = list_head(&gdi_font_list);
3920 while(font_elem_ptr) {
3921 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3922 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3924 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3925 while(hfontlist_elem_ptr) {
3926 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3927 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3928 if(hflist->hfont == handle) {
3929 list_remove(&hflist->entry);
3930 HeapFree(GetProcessHeap(), 0, hflist);
3931 ret = TRUE;
3934 if(list_empty(&gdiFont->hfontlist)) {
3935 TRACE("Moving to Unused list\n");
3936 list_remove(&gdiFont->entry);
3937 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3942 font_elem_ptr = list_head(&unused_gdi_font_list);
3943 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3944 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3945 while(font_elem_ptr) {
3946 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3947 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3948 TRACE("freeing %p\n", gdiFont);
3949 list_remove(&gdiFont->entry);
3950 free_font(gdiFont);
3952 LeaveCriticalSection( &freetype_cs );
3953 return ret;
3956 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3957 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3959 GdiFont *font;
3960 LONG width, height;
3962 if (face->cached_enum_data)
3964 TRACE("Cached\n");
3965 *pelf = face->cached_enum_data->elf;
3966 *pntm = face->cached_enum_data->ntm;
3967 *ptype = face->cached_enum_data->type;
3968 return;
3971 font = alloc_font();
3973 if(face->scalable) {
3974 height = -2048; /* 2048 is the most common em size */
3975 width = 0;
3976 } else {
3977 height = face->size.y_ppem >> 6;
3978 width = face->size.x_ppem >> 6;
3980 font->scale_y = 1.0;
3982 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3984 free_font(font);
3985 return;
3988 font->name = strdupW(face->family->FamilyName);
3989 font->ntmFlags = face->ntmFlags;
3991 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3993 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3995 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3997 lstrcpynW(pelf->elfLogFont.lfFaceName,
3998 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3999 LF_FACESIZE);
4000 lstrcpynW(pelf->elfFullName,
4001 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
4002 LF_FULLFACESIZE);
4003 lstrcpynW(pelf->elfStyle,
4004 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4005 LF_FACESIZE);
4007 else
4009 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4011 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4013 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4014 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4015 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4018 pntm->ntmTm.ntmFlags = face->ntmFlags;
4019 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4020 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4021 pntm->ntmFontSig = face->fs;
4023 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4025 pelf->elfLogFont.lfEscapement = 0;
4026 pelf->elfLogFont.lfOrientation = 0;
4027 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4028 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4029 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4030 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4031 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4032 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4033 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4034 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4035 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4036 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4037 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4039 *ptype = 0;
4040 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4041 *ptype |= TRUETYPE_FONTTYPE;
4042 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4043 *ptype |= DEVICE_FONTTYPE;
4044 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4045 *ptype |= RASTER_FONTTYPE;
4047 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4048 if (face->cached_enum_data)
4050 face->cached_enum_data->elf = *pelf;
4051 face->cached_enum_data->ntm = *pntm;
4052 face->cached_enum_data->type = *ptype;
4055 free_font(font);
4058 /*************************************************************
4059 * WineEngEnumFonts
4062 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4064 Family *family;
4065 Face *face;
4066 struct list *family_elem_ptr, *face_elem_ptr;
4067 ENUMLOGFONTEXW elf;
4068 NEWTEXTMETRICEXW ntm;
4069 DWORD type;
4070 FONTSIGNATURE fs;
4071 CHARSETINFO csi;
4072 LOGFONTW lf;
4073 int i;
4075 if (!plf)
4077 lf.lfCharSet = DEFAULT_CHARSET;
4078 lf.lfPitchAndFamily = 0;
4079 lf.lfFaceName[0] = 0;
4080 plf = &lf;
4083 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4085 GDI_CheckNotLock();
4086 EnterCriticalSection( &freetype_cs );
4087 if(plf->lfFaceName[0]) {
4088 FontSubst *psub;
4089 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4091 if(psub) {
4092 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4093 debugstr_w(psub->to.name));
4094 lf = *plf;
4095 strcpyW(lf.lfFaceName, psub->to.name);
4096 plf = &lf;
4099 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4100 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4101 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
4102 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4103 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4104 GetEnumStructs(face, &elf, &ntm, &type);
4105 for(i = 0; i < 32; i++) {
4106 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4107 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4108 strcpyW(elf.elfScript, OEM_DOSW);
4109 i = 32; /* break out of loop */
4110 } else if(!(face->fs.fsCsb[0] & (1L << i)))
4111 continue;
4112 else {
4113 fs.fsCsb[0] = 1L << i;
4114 fs.fsCsb[1] = 0;
4115 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
4116 TCI_SRCFONTSIG))
4117 csi.ciCharset = DEFAULT_CHARSET;
4118 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
4119 if(csi.ciCharset != DEFAULT_CHARSET) {
4120 elf.elfLogFont.lfCharSet =
4121 ntm.ntmTm.tmCharSet = csi.ciCharset;
4122 if(ElfScriptsW[i])
4123 strcpyW(elf.elfScript, ElfScriptsW[i]);
4124 else
4125 FIXME("Unknown elfscript for bit %d\n", i);
4128 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
4129 debugstr_w(elf.elfLogFont.lfFaceName),
4130 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4131 csi.ciCharset, type, debugstr_w(elf.elfScript),
4132 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4133 ntm.ntmTm.ntmFlags);
4134 /* release section before callback (FIXME) */
4135 LeaveCriticalSection( &freetype_cs );
4136 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
4137 EnterCriticalSection( &freetype_cs );
4142 } else {
4143 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4144 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4145 face_elem_ptr = list_head(&family->faces);
4146 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4147 GetEnumStructs(face, &elf, &ntm, &type);
4148 for(i = 0; i < 32; i++) {
4149 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4150 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4151 strcpyW(elf.elfScript, OEM_DOSW);
4152 i = 32; /* break out of loop */
4153 } else if(!(face->fs.fsCsb[0] & (1L << i)))
4154 continue;
4155 else {
4156 fs.fsCsb[0] = 1L << i;
4157 fs.fsCsb[1] = 0;
4158 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
4159 TCI_SRCFONTSIG))
4160 csi.ciCharset = DEFAULT_CHARSET;
4161 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
4162 if(csi.ciCharset != DEFAULT_CHARSET) {
4163 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
4164 csi.ciCharset;
4165 if(ElfScriptsW[i])
4166 strcpyW(elf.elfScript, ElfScriptsW[i]);
4167 else
4168 FIXME("Unknown elfscript for bit %d\n", i);
4171 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4172 debugstr_w(elf.elfLogFont.lfFaceName),
4173 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4174 csi.ciCharset, type, debugstr_w(elf.elfScript),
4175 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4176 ntm.ntmTm.ntmFlags);
4177 /* release section before callback (FIXME) */
4178 LeaveCriticalSection( &freetype_cs );
4179 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
4180 EnterCriticalSection( &freetype_cs );
4184 LeaveCriticalSection( &freetype_cs );
4185 return 1;
4188 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4190 pt->x.value = vec->x >> 6;
4191 pt->x.fract = (vec->x & 0x3f) << 10;
4192 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4193 pt->y.value = vec->y >> 6;
4194 pt->y.fract = (vec->y & 0x3f) << 10;
4195 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4196 return;
4199 /***************************************************
4200 * According to the MSDN documentation on WideCharToMultiByte,
4201 * certain codepages cannot set the default_used parameter.
4202 * This returns TRUE if the codepage can set that parameter, false else
4203 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4205 static BOOL codepage_sets_default_used(UINT codepage)
4207 switch (codepage)
4209 case CP_UTF7:
4210 case CP_UTF8:
4211 case CP_SYMBOL:
4212 return FALSE;
4213 default:
4214 return TRUE;
4219 * GSUB Table handling functions
4222 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4224 const GSUB_CoverageFormat1* cf1;
4226 cf1 = table;
4228 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4230 int count = GET_BE_WORD(cf1->GlyphCount);
4231 int i;
4232 TRACE("Coverage Format 1, %i glyphs\n",count);
4233 for (i = 0; i < count; i++)
4234 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4235 return i;
4236 return -1;
4238 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4240 const GSUB_CoverageFormat2* cf2;
4241 int i;
4242 int count;
4243 cf2 = (const GSUB_CoverageFormat2*)cf1;
4245 count = GET_BE_WORD(cf2->RangeCount);
4246 TRACE("Coverage Format 2, %i ranges\n",count);
4247 for (i = 0; i < count; i++)
4249 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4250 return -1;
4251 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4252 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4254 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4255 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4258 return -1;
4260 else
4261 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4263 return -1;
4266 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4268 const GSUB_ScriptList *script;
4269 const GSUB_Script *deflt = NULL;
4270 int i;
4271 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4273 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4274 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4276 const GSUB_Script *scr;
4277 int offset;
4279 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4280 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4282 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4283 return scr;
4284 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4285 deflt = scr;
4287 return deflt;
4290 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4292 int i;
4293 int offset;
4294 const GSUB_LangSys *Lang;
4296 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4298 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4300 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4301 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4303 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4304 return Lang;
4306 offset = GET_BE_WORD(script->DefaultLangSys);
4307 if (offset)
4309 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4310 return Lang;
4312 return NULL;
4315 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4317 int i;
4318 const GSUB_FeatureList *feature;
4319 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4321 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4322 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4324 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4325 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4327 const GSUB_Feature *feat;
4328 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4329 return feat;
4332 return NULL;
4335 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4337 int i;
4338 int offset;
4339 const GSUB_LookupList *lookup;
4340 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4342 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4343 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4345 const GSUB_LookupTable *look;
4346 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4347 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4348 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4349 if (GET_BE_WORD(look->LookupType) != 1)
4350 FIXME("We only handle SubType 1\n");
4351 else
4353 int j;
4355 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4357 const GSUB_SingleSubstFormat1 *ssf1;
4358 offset = GET_BE_WORD(look->SubTable[j]);
4359 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4360 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4362 int offset = GET_BE_WORD(ssf1->Coverage);
4363 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4364 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4366 TRACE(" Glyph 0x%x ->",glyph);
4367 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4368 TRACE(" 0x%x\n",glyph);
4371 else
4373 const GSUB_SingleSubstFormat2 *ssf2;
4374 INT index;
4375 INT offset;
4377 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4378 offset = GET_BE_WORD(ssf1->Coverage);
4379 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4380 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4381 TRACE(" Coverage index %i\n",index);
4382 if (index != -1)
4384 TRACE(" Glyph is 0x%x ->",glyph);
4385 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4386 TRACE("0x%x\n",glyph);
4392 return glyph;
4395 static const char* get_opentype_script(const GdiFont *font)
4398 * I am not sure if this is the correct way to generate our script tag
4401 switch (font->charset)
4403 case ANSI_CHARSET: return "latn";
4404 case BALTIC_CHARSET: return "latn"; /* ?? */
4405 case CHINESEBIG5_CHARSET: return "hani";
4406 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4407 case GB2312_CHARSET: return "hani";
4408 case GREEK_CHARSET: return "grek";
4409 case HANGUL_CHARSET: return "hang";
4410 case RUSSIAN_CHARSET: return "cyrl";
4411 case SHIFTJIS_CHARSET: return "kana";
4412 case TURKISH_CHARSET: return "latn"; /* ?? */
4413 case VIETNAMESE_CHARSET: return "latn";
4414 case JOHAB_CHARSET: return "latn"; /* ?? */
4415 case ARABIC_CHARSET: return "arab";
4416 case HEBREW_CHARSET: return "hebr";
4417 case THAI_CHARSET: return "thai";
4418 default: return "latn";
4422 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4424 const GSUB_Header *header;
4425 const GSUB_Script *script;
4426 const GSUB_LangSys *language;
4427 const GSUB_Feature *feature;
4429 if (!font->GSUB_Table)
4430 return glyph;
4432 header = font->GSUB_Table;
4434 script = GSUB_get_script_table(header, get_opentype_script(font));
4435 if (!script)
4437 TRACE("Script not found\n");
4438 return glyph;
4440 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4441 if (!language)
4443 TRACE("Language not found\n");
4444 return glyph;
4446 feature = GSUB_get_feature(header, language, "vrt2");
4447 if (!feature)
4448 feature = GSUB_get_feature(header, language, "vert");
4449 if (!feature)
4451 TRACE("vrt2/vert feature not found\n");
4452 return glyph;
4454 return GSUB_apply_feature(header, feature, glyph);
4457 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4459 FT_UInt glyphId;
4461 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4462 WCHAR wc = (WCHAR)glyph;
4463 BOOL default_used;
4464 BOOL *default_used_pointer;
4465 FT_UInt ret;
4466 char buf;
4467 default_used_pointer = NULL;
4468 default_used = FALSE;
4469 if (codepage_sets_default_used(font->codepage))
4470 default_used_pointer = &default_used;
4471 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4472 ret = 0;
4473 else
4474 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4475 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4476 return get_GSUB_vert_glyph(font,ret);
4479 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4480 glyph = glyph + 0xf000;
4481 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4482 return get_GSUB_vert_glyph(font,glyphId);
4485 /*************************************************************
4486 * WineEngGetGlyphIndices
4489 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4490 LPWORD pgi, DWORD flags)
4492 int i;
4493 int default_char = -1;
4495 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4497 for(i = 0; i < count; i++)
4499 pgi[i] = get_glyph_index(font, lpstr[i]);
4500 if (pgi[i] == 0)
4502 if (default_char == -1)
4504 if (FT_IS_SFNT(font->ft_face))
4506 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4507 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4509 else
4511 TEXTMETRICW textm;
4512 WineEngGetTextMetrics(font, &textm);
4513 default_char = textm.tmDefaultChar;
4516 pgi[i] = default_char;
4519 return count;
4522 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4524 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4525 return !memcmp(matrix, &identity, sizeof(FMAT2));
4528 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4530 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4531 return !memcmp(matrix, &identity, sizeof(MAT2));
4534 /*************************************************************
4535 * WineEngGetGlyphOutline
4537 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4538 * except that the first parameter is the HWINEENGFONT of the font in
4539 * question rather than an HDC.
4542 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4543 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4544 const MAT2* lpmat)
4546 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4547 FT_Face ft_face = incoming_font->ft_face;
4548 GdiFont *font = incoming_font;
4549 FT_UInt glyph_index;
4550 DWORD width, height, pitch, needed = 0;
4551 FT_Bitmap ft_bitmap;
4552 FT_Error err;
4553 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4554 FT_Angle angle = 0;
4555 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4556 double widthRatio = 1.0;
4557 FT_Matrix transMat = identityMat;
4558 FT_Matrix transMatUnrotated;
4559 BOOL needsTransform = FALSE;
4560 BOOL tategaki = (font->GSUB_Table != NULL);
4561 UINT original_index;
4563 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4564 buflen, buf, lpmat);
4566 TRACE("font transform %f %f %f %f\n",
4567 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4568 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4570 GDI_CheckNotLock();
4571 EnterCriticalSection( &freetype_cs );
4573 if(format & GGO_GLYPH_INDEX) {
4574 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4575 original_index = glyph;
4576 format &= ~GGO_GLYPH_INDEX;
4577 } else {
4578 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4579 ft_face = font->ft_face;
4580 original_index = glyph_index;
4583 if(format & GGO_UNHINTED) {
4584 load_flags |= FT_LOAD_NO_HINTING;
4585 format &= ~GGO_UNHINTED;
4588 /* tategaki never appears to happen to lower glyph index */
4589 if (glyph_index < TATEGAKI_LOWER_BOUND )
4590 tategaki = FALSE;
4592 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4593 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4594 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4595 font->gmsize * sizeof(GM*));
4596 } else {
4597 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4598 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
4600 *lpgm = FONT_GM(font,original_index)->gm;
4601 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4602 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4603 lpgm->gmCellIncX, lpgm->gmCellIncY);
4604 LeaveCriticalSection( &freetype_cs );
4605 return 1; /* FIXME */
4609 if (!font->gm[original_index / GM_BLOCK_SIZE])
4610 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4612 /* Scaling factor */
4613 if (font->aveWidth)
4615 TEXTMETRICW tm;
4617 WineEngGetTextMetrics(font, &tm);
4619 widthRatio = (double)font->aveWidth;
4620 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4622 else
4623 widthRatio = font->scale_y;
4625 /* Scaling transform */
4626 if (widthRatio != 1.0 || font->scale_y != 1.0)
4628 FT_Matrix scaleMat;
4629 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4630 scaleMat.xy = 0;
4631 scaleMat.yx = 0;
4632 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4634 pFT_Matrix_Multiply(&scaleMat, &transMat);
4635 needsTransform = TRUE;
4638 /* Slant transform */
4639 if (font->fake_italic) {
4640 FT_Matrix slantMat;
4642 slantMat.xx = (1 << 16);
4643 slantMat.xy = ((1 << 16) >> 2);
4644 slantMat.yx = 0;
4645 slantMat.yy = (1 << 16);
4646 pFT_Matrix_Multiply(&slantMat, &transMat);
4647 needsTransform = TRUE;
4650 /* Rotation transform */
4651 transMatUnrotated = transMat;
4652 if(font->orientation && !tategaki) {
4653 FT_Matrix rotationMat;
4654 FT_Vector vecAngle;
4655 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4656 pFT_Vector_Unit(&vecAngle, angle);
4657 rotationMat.xx = vecAngle.x;
4658 rotationMat.xy = -vecAngle.y;
4659 rotationMat.yx = -rotationMat.xy;
4660 rotationMat.yy = rotationMat.xx;
4662 pFT_Matrix_Multiply(&rotationMat, &transMat);
4663 needsTransform = TRUE;
4666 /* World transform */
4667 if (!is_identity_FMAT2(&font->font_desc.matrix))
4669 FT_Matrix worldMat;
4670 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4671 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4672 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4673 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4674 pFT_Matrix_Multiply(&worldMat, &transMat);
4675 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4676 needsTransform = TRUE;
4679 /* Extra transformation specified by caller */
4680 if (!is_identity_MAT2(lpmat))
4682 FT_Matrix extraMat;
4683 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4684 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
4685 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
4686 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4687 pFT_Matrix_Multiply(&extraMat, &transMat);
4688 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4689 needsTransform = TRUE;
4692 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
4693 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4694 format == GGO_GRAY8_BITMAP))
4696 load_flags |= FT_LOAD_NO_BITMAP;
4699 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4701 if(err) {
4702 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4703 LeaveCriticalSection( &freetype_cs );
4704 return GDI_ERROR;
4707 if(!needsTransform) {
4708 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4709 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4710 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
4712 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4713 bottom = (ft_face->glyph->metrics.horiBearingY -
4714 ft_face->glyph->metrics.height) & -64;
4715 lpgm->gmCellIncX = adv;
4716 lpgm->gmCellIncY = 0;
4717 } else {
4718 INT xc, yc;
4719 FT_Vector vec;
4721 left = right = 0;
4723 for(xc = 0; xc < 2; xc++) {
4724 for(yc = 0; yc < 2; yc++) {
4725 vec.x = (ft_face->glyph->metrics.horiBearingX +
4726 xc * ft_face->glyph->metrics.width);
4727 vec.y = ft_face->glyph->metrics.horiBearingY -
4728 yc * ft_face->glyph->metrics.height;
4729 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4730 pFT_Vector_Transform(&vec, &transMat);
4731 if(xc == 0 && yc == 0) {
4732 left = right = vec.x;
4733 top = bottom = vec.y;
4734 } else {
4735 if(vec.x < left) left = vec.x;
4736 else if(vec.x > right) right = vec.x;
4737 if(vec.y < bottom) bottom = vec.y;
4738 else if(vec.y > top) top = vec.y;
4742 left = left & -64;
4743 right = (right + 63) & -64;
4744 bottom = bottom & -64;
4745 top = (top + 63) & -64;
4747 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4748 vec.x = ft_face->glyph->metrics.horiAdvance;
4749 vec.y = 0;
4750 pFT_Vector_Transform(&vec, &transMat);
4751 lpgm->gmCellIncX = (vec.x+63) >> 6;
4752 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4754 vec.x = ft_face->glyph->metrics.horiAdvance;
4755 vec.y = 0;
4756 pFT_Vector_Transform(&vec, &transMatUnrotated);
4757 adv = (vec.x+63) >> 6;
4760 lsb = left >> 6;
4761 bbx = (right - left) >> 6;
4762 lpgm->gmBlackBoxX = (right - left) >> 6;
4763 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4764 lpgm->gmptGlyphOrigin.x = left >> 6;
4765 lpgm->gmptGlyphOrigin.y = top >> 6;
4767 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4768 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4769 lpgm->gmCellIncX, lpgm->gmCellIncY);
4771 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4772 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
4774 FONT_GM(font,original_index)->gm = *lpgm;
4775 FONT_GM(font,original_index)->adv = adv;
4776 FONT_GM(font,original_index)->lsb = lsb;
4777 FONT_GM(font,original_index)->bbx = bbx;
4778 FONT_GM(font,original_index)->init = TRUE;
4781 if(format == GGO_METRICS)
4783 LeaveCriticalSection( &freetype_cs );
4784 return 1; /* FIXME */
4787 if(ft_face->glyph->format != ft_glyph_format_outline &&
4788 (format == GGO_NATIVE || format == GGO_BEZIER ||
4789 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4790 format == GGO_GRAY8_BITMAP))
4792 TRACE("loaded a bitmap\n");
4793 LeaveCriticalSection( &freetype_cs );
4794 return GDI_ERROR;
4797 switch(format) {
4798 case GGO_BITMAP:
4799 width = lpgm->gmBlackBoxX;
4800 height = lpgm->gmBlackBoxY;
4801 pitch = ((width + 31) >> 5) << 2;
4802 needed = pitch * height;
4804 if(!buf || !buflen) break;
4806 switch(ft_face->glyph->format) {
4807 case ft_glyph_format_bitmap:
4809 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4810 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4811 INT h = ft_face->glyph->bitmap.rows;
4812 while(h--) {
4813 memcpy(dst, src, w);
4814 src += ft_face->glyph->bitmap.pitch;
4815 dst += pitch;
4817 break;
4820 case ft_glyph_format_outline:
4821 ft_bitmap.width = width;
4822 ft_bitmap.rows = height;
4823 ft_bitmap.pitch = pitch;
4824 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4825 ft_bitmap.buffer = buf;
4827 if(needsTransform)
4828 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4830 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4832 /* Note: FreeType will only set 'black' bits for us. */
4833 memset(buf, 0, needed);
4834 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4835 break;
4837 default:
4838 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4839 LeaveCriticalSection( &freetype_cs );
4840 return GDI_ERROR;
4842 break;
4844 case GGO_GRAY2_BITMAP:
4845 case GGO_GRAY4_BITMAP:
4846 case GGO_GRAY8_BITMAP:
4847 case WINE_GGO_GRAY16_BITMAP:
4849 unsigned int mult, row, col;
4850 BYTE *start, *ptr;
4852 width = lpgm->gmBlackBoxX;
4853 height = lpgm->gmBlackBoxY;
4854 pitch = (width + 3) / 4 * 4;
4855 needed = pitch * height;
4857 if(!buf || !buflen) break;
4859 switch(ft_face->glyph->format) {
4860 case ft_glyph_format_bitmap:
4862 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4863 INT h = ft_face->glyph->bitmap.rows;
4864 INT x;
4865 while(h--) {
4866 for(x = 0; x < pitch; x++)
4868 if(x < ft_face->glyph->bitmap.width)
4869 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4870 else
4871 dst[x] = 0;
4873 src += ft_face->glyph->bitmap.pitch;
4874 dst += pitch;
4876 LeaveCriticalSection( &freetype_cs );
4877 return needed;
4879 case ft_glyph_format_outline:
4881 ft_bitmap.width = width;
4882 ft_bitmap.rows = height;
4883 ft_bitmap.pitch = pitch;
4884 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4885 ft_bitmap.buffer = buf;
4887 if(needsTransform)
4888 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4890 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4892 memset(ft_bitmap.buffer, 0, buflen);
4894 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4896 if(format == GGO_GRAY2_BITMAP)
4897 mult = 4;
4898 else if(format == GGO_GRAY4_BITMAP)
4899 mult = 16;
4900 else if(format == GGO_GRAY8_BITMAP)
4901 mult = 64;
4902 else /* format == WINE_GGO_GRAY16_BITMAP */
4904 LeaveCriticalSection( &freetype_cs );
4905 return needed;
4907 break;
4909 default:
4910 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4911 LeaveCriticalSection( &freetype_cs );
4912 return GDI_ERROR;
4915 start = buf;
4916 for(row = 0; row < height; row++) {
4917 ptr = start;
4918 for(col = 0; col < width; col++, ptr++) {
4919 *ptr = (((int)*ptr) * mult + 128) / 256;
4921 start += pitch;
4923 break;
4926 case WINE_GGO_HRGB_BITMAP:
4927 case WINE_GGO_HBGR_BITMAP:
4928 case WINE_GGO_VRGB_BITMAP:
4929 case WINE_GGO_VBGR_BITMAP:
4930 #ifdef HAVE_FREETYPE_FTLCDFIL_H
4932 switch (ft_face->glyph->format)
4934 case FT_GLYPH_FORMAT_BITMAP:
4936 BYTE *src, *dst;
4937 INT src_pitch, x;
4939 width = lpgm->gmBlackBoxX;
4940 height = lpgm->gmBlackBoxY;
4941 pitch = width * 4;
4942 needed = pitch * height;
4944 if (!buf || !buflen) break;
4946 memset(buf, 0, buflen);
4947 dst = buf;
4948 src = ft_face->glyph->bitmap.buffer;
4949 src_pitch = ft_face->glyph->bitmap.pitch;
4951 while ( height-- )
4953 for (x = 0; x < width; x++)
4955 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
4956 ((unsigned int *)dst)[x] = ~0u;
4958 src += src_pitch;
4959 dst += pitch;
4962 break;
4965 case FT_GLYPH_FORMAT_OUTLINE:
4967 unsigned int *dst;
4968 BYTE *src;
4969 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
4970 INT x_shift, y_shift;
4971 BOOL rgb;
4972 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
4973 FT_Render_Mode render_mode =
4974 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
4975 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
4977 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
4979 if ( render_mode == FT_RENDER_MODE_LCD)
4981 lpgm->gmBlackBoxX += 2;
4982 lpgm->gmptGlyphOrigin.x -= 1;
4984 else
4986 lpgm->gmBlackBoxY += 2;
4987 lpgm->gmptGlyphOrigin.y += 1;
4991 width = lpgm->gmBlackBoxX;
4992 height = lpgm->gmBlackBoxY;
4993 pitch = width * 4;
4994 needed = pitch * height;
4996 if (!buf || !buflen) break;
4998 memset(buf, 0, buflen);
4999 dst = buf;
5000 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5002 if ( needsTransform )
5003 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5005 if ( pFT_Library_SetLcdFilter )
5006 pFT_Library_SetLcdFilter( library, lcdfilter );
5007 pFT_Render_Glyph (ft_face->glyph, render_mode);
5009 src = ft_face->glyph->bitmap.buffer;
5010 src_pitch = ft_face->glyph->bitmap.pitch;
5011 src_width = ft_face->glyph->bitmap.width;
5012 src_height = ft_face->glyph->bitmap.rows;
5014 if ( render_mode == FT_RENDER_MODE_LCD)
5016 rgb_interval = 1;
5017 hmul = 3;
5018 vmul = 1;
5020 else
5022 rgb_interval = src_pitch;
5023 hmul = 1;
5024 vmul = 3;
5027 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5028 if ( x_shift < 0 ) x_shift = 0;
5029 if ( x_shift + (src_width / hmul) > width )
5030 x_shift = width - (src_width / hmul);
5032 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5033 if ( y_shift < 0 ) y_shift = 0;
5034 if ( y_shift + (src_height / vmul) > height )
5035 y_shift = height - (src_height / vmul);
5037 dst += x_shift + y_shift * ( pitch / 4 );
5038 while ( src_height )
5040 for ( x = 0; x < src_width / hmul; x++ )
5042 if ( rgb )
5044 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5045 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5046 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5047 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5049 else
5051 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5052 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5053 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5054 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5057 src += src_pitch * vmul;
5058 dst += pitch / 4;
5059 src_height -= vmul;
5062 break;
5065 default:
5066 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5067 LeaveCriticalSection ( &freetype_cs );
5068 return GDI_ERROR;
5071 break;
5073 #else
5074 LeaveCriticalSection( &freetype_cs );
5075 return GDI_ERROR;
5076 #endif
5078 case GGO_NATIVE:
5080 int contour, point = 0, first_pt;
5081 FT_Outline *outline = &ft_face->glyph->outline;
5082 TTPOLYGONHEADER *pph;
5083 TTPOLYCURVE *ppc;
5084 DWORD pph_start, cpfx, type;
5086 if(buflen == 0) buf = NULL;
5088 if (needsTransform && buf) {
5089 pFT_Outline_Transform(outline, &transMat);
5092 for(contour = 0; contour < outline->n_contours; contour++) {
5093 pph_start = needed;
5094 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5095 first_pt = point;
5096 if(buf) {
5097 pph->dwType = TT_POLYGON_TYPE;
5098 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5100 needed += sizeof(*pph);
5101 point++;
5102 while(point <= outline->contours[contour]) {
5103 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5104 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5105 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5106 cpfx = 0;
5107 do {
5108 if(buf)
5109 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5110 cpfx++;
5111 point++;
5112 } while(point <= outline->contours[contour] &&
5113 (outline->tags[point] & FT_Curve_Tag_On) ==
5114 (outline->tags[point-1] & FT_Curve_Tag_On));
5115 /* At the end of a contour Windows adds the start point, but
5116 only for Beziers */
5117 if(point > outline->contours[contour] &&
5118 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5119 if(buf)
5120 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5121 cpfx++;
5122 } else if(point <= outline->contours[contour] &&
5123 outline->tags[point] & FT_Curve_Tag_On) {
5124 /* add closing pt for bezier */
5125 if(buf)
5126 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5127 cpfx++;
5128 point++;
5130 if(buf) {
5131 ppc->wType = type;
5132 ppc->cpfx = cpfx;
5134 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5136 if(buf)
5137 pph->cb = needed - pph_start;
5139 break;
5141 case GGO_BEZIER:
5143 /* Convert the quadratic Beziers to cubic Beziers.
5144 The parametric eqn for a cubic Bezier is, from PLRM:
5145 r(t) = at^3 + bt^2 + ct + r0
5146 with the control points:
5147 r1 = r0 + c/3
5148 r2 = r1 + (c + b)/3
5149 r3 = r0 + c + b + a
5151 A quadratic Beizer has the form:
5152 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5154 So equating powers of t leads to:
5155 r1 = 2/3 p1 + 1/3 p0
5156 r2 = 2/3 p1 + 1/3 p2
5157 and of course r0 = p0, r3 = p2
5160 int contour, point = 0, first_pt;
5161 FT_Outline *outline = &ft_face->glyph->outline;
5162 TTPOLYGONHEADER *pph;
5163 TTPOLYCURVE *ppc;
5164 DWORD pph_start, cpfx, type;
5165 FT_Vector cubic_control[4];
5166 if(buflen == 0) buf = NULL;
5168 if (needsTransform && buf) {
5169 pFT_Outline_Transform(outline, &transMat);
5172 for(contour = 0; contour < outline->n_contours; contour++) {
5173 pph_start = needed;
5174 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5175 first_pt = point;
5176 if(buf) {
5177 pph->dwType = TT_POLYGON_TYPE;
5178 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5180 needed += sizeof(*pph);
5181 point++;
5182 while(point <= outline->contours[contour]) {
5183 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5184 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5185 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5186 cpfx = 0;
5187 do {
5188 if(type == TT_PRIM_LINE) {
5189 if(buf)
5190 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5191 cpfx++;
5192 point++;
5193 } else {
5194 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5195 so cpfx = 3n */
5197 /* FIXME: Possible optimization in endpoint calculation
5198 if there are two consecutive curves */
5199 cubic_control[0] = outline->points[point-1];
5200 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5201 cubic_control[0].x += outline->points[point].x + 1;
5202 cubic_control[0].y += outline->points[point].y + 1;
5203 cubic_control[0].x >>= 1;
5204 cubic_control[0].y >>= 1;
5206 if(point+1 > outline->contours[contour])
5207 cubic_control[3] = outline->points[first_pt];
5208 else {
5209 cubic_control[3] = outline->points[point+1];
5210 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5211 cubic_control[3].x += outline->points[point].x + 1;
5212 cubic_control[3].y += outline->points[point].y + 1;
5213 cubic_control[3].x >>= 1;
5214 cubic_control[3].y >>= 1;
5217 /* r1 = 1/3 p0 + 2/3 p1
5218 r2 = 1/3 p2 + 2/3 p1 */
5219 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5220 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5221 cubic_control[2] = cubic_control[1];
5222 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5223 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5224 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5225 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5226 if(buf) {
5227 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5228 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5229 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5231 cpfx += 3;
5232 point++;
5234 } while(point <= outline->contours[contour] &&
5235 (outline->tags[point] & FT_Curve_Tag_On) ==
5236 (outline->tags[point-1] & FT_Curve_Tag_On));
5237 /* At the end of a contour Windows adds the start point,
5238 but only for Beziers and we've already done that.
5240 if(point <= outline->contours[contour] &&
5241 outline->tags[point] & FT_Curve_Tag_On) {
5242 /* This is the closing pt of a bezier, but we've already
5243 added it, so just inc point and carry on */
5244 point++;
5246 if(buf) {
5247 ppc->wType = type;
5248 ppc->cpfx = cpfx;
5250 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5252 if(buf)
5253 pph->cb = needed - pph_start;
5255 break;
5258 default:
5259 FIXME("Unsupported format %d\n", format);
5260 LeaveCriticalSection( &freetype_cs );
5261 return GDI_ERROR;
5263 LeaveCriticalSection( &freetype_cs );
5264 return needed;
5267 static BOOL get_bitmap_text_metrics(GdiFont *font)
5269 FT_Face ft_face = font->ft_face;
5270 #ifdef HAVE_FREETYPE_FTWINFNT_H
5271 FT_WinFNT_HeaderRec winfnt_header;
5272 #endif
5273 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5274 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5275 font->potm->otmSize = size;
5277 #define TM font->potm->otmTextMetrics
5278 #ifdef HAVE_FREETYPE_FTWINFNT_H
5279 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5281 TM.tmHeight = winfnt_header.pixel_height;
5282 TM.tmAscent = winfnt_header.ascent;
5283 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5284 TM.tmInternalLeading = winfnt_header.internal_leading;
5285 TM.tmExternalLeading = winfnt_header.external_leading;
5286 TM.tmAveCharWidth = winfnt_header.avg_width;
5287 TM.tmMaxCharWidth = winfnt_header.max_width;
5288 TM.tmWeight = winfnt_header.weight;
5289 TM.tmOverhang = 0;
5290 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5291 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5292 TM.tmFirstChar = winfnt_header.first_char;
5293 TM.tmLastChar = winfnt_header.last_char;
5294 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5295 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5296 TM.tmItalic = winfnt_header.italic;
5297 TM.tmUnderlined = font->underline;
5298 TM.tmStruckOut = font->strikeout;
5299 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5300 TM.tmCharSet = winfnt_header.charset;
5302 else
5303 #endif
5305 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5306 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5307 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5308 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5309 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5310 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5311 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5312 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5313 TM.tmOverhang = 0;
5314 TM.tmDigitizedAspectX = 96; /* FIXME */
5315 TM.tmDigitizedAspectY = 96; /* FIXME */
5316 TM.tmFirstChar = 1;
5317 TM.tmLastChar = 255;
5318 TM.tmDefaultChar = 32;
5319 TM.tmBreakChar = 32;
5320 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5321 TM.tmUnderlined = font->underline;
5322 TM.tmStruckOut = font->strikeout;
5323 /* NB inverted meaning of TMPF_FIXED_PITCH */
5324 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5325 TM.tmCharSet = font->charset;
5327 #undef TM
5329 return TRUE;
5333 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5335 double scale_x, scale_y;
5337 if (font->aveWidth)
5339 scale_x = (double)font->aveWidth;
5340 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5342 else
5343 scale_x = font->scale_y;
5345 scale_x *= fabs(font->font_desc.matrix.eM11);
5346 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5348 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5349 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5351 SCALE_Y(ptm->tmHeight);
5352 SCALE_Y(ptm->tmAscent);
5353 SCALE_Y(ptm->tmDescent);
5354 SCALE_Y(ptm->tmInternalLeading);
5355 SCALE_Y(ptm->tmExternalLeading);
5356 SCALE_Y(ptm->tmOverhang);
5358 SCALE_X(ptm->tmAveCharWidth);
5359 SCALE_X(ptm->tmMaxCharWidth);
5361 #undef SCALE_X
5362 #undef SCALE_Y
5365 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5367 double scale_x, scale_y;
5369 if (font->aveWidth)
5371 scale_x = (double)font->aveWidth;
5372 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5374 else
5375 scale_x = font->scale_y;
5377 scale_x *= fabs(font->font_desc.matrix.eM11);
5378 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5380 scale_font_metrics(font, &potm->otmTextMetrics);
5382 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5383 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5385 SCALE_Y(potm->otmAscent);
5386 SCALE_Y(potm->otmDescent);
5387 SCALE_Y(potm->otmLineGap);
5388 SCALE_Y(potm->otmsCapEmHeight);
5389 SCALE_Y(potm->otmsXHeight);
5390 SCALE_Y(potm->otmrcFontBox.top);
5391 SCALE_Y(potm->otmrcFontBox.bottom);
5392 SCALE_X(potm->otmrcFontBox.left);
5393 SCALE_X(potm->otmrcFontBox.right);
5394 SCALE_Y(potm->otmMacAscent);
5395 SCALE_Y(potm->otmMacDescent);
5396 SCALE_Y(potm->otmMacLineGap);
5397 SCALE_X(potm->otmptSubscriptSize.x);
5398 SCALE_Y(potm->otmptSubscriptSize.y);
5399 SCALE_X(potm->otmptSubscriptOffset.x);
5400 SCALE_Y(potm->otmptSubscriptOffset.y);
5401 SCALE_X(potm->otmptSuperscriptSize.x);
5402 SCALE_Y(potm->otmptSuperscriptSize.y);
5403 SCALE_X(potm->otmptSuperscriptOffset.x);
5404 SCALE_Y(potm->otmptSuperscriptOffset.y);
5405 SCALE_Y(potm->otmsStrikeoutSize);
5406 SCALE_Y(potm->otmsStrikeoutPosition);
5407 SCALE_Y(potm->otmsUnderscoreSize);
5408 SCALE_Y(potm->otmsUnderscorePosition);
5410 #undef SCALE_X
5411 #undef SCALE_Y
5414 /*************************************************************
5415 * WineEngGetTextMetrics
5418 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5420 GDI_CheckNotLock();
5421 EnterCriticalSection( &freetype_cs );
5422 if(!font->potm) {
5423 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5424 if(!get_bitmap_text_metrics(font))
5426 LeaveCriticalSection( &freetype_cs );
5427 return FALSE;
5430 /* Make sure that the font has sane width/height ratio */
5431 if (font->aveWidth)
5433 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5435 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5436 font->aveWidth = 0;
5441 *ptm = font->potm->otmTextMetrics;
5442 scale_font_metrics(font, ptm);
5443 LeaveCriticalSection( &freetype_cs );
5444 return TRUE;
5447 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5449 int i;
5451 for(i = 0; i < ft_face->num_charmaps; i++)
5453 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5454 return TRUE;
5456 return FALSE;
5459 /*************************************************************
5460 * WineEngGetOutlineTextMetrics
5463 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5464 OUTLINETEXTMETRICW *potm)
5466 FT_Face ft_face = font->ft_face;
5467 UINT needed, lenfam, lensty, ret;
5468 TT_OS2 *pOS2;
5469 TT_HoriHeader *pHori;
5470 TT_Postscript *pPost;
5471 FT_Fixed x_scale, y_scale;
5472 WCHAR *family_nameW, *style_nameW;
5473 static const WCHAR spaceW[] = {' ', '\0'};
5474 char *cp;
5475 INT ascent, descent;
5477 TRACE("font=%p\n", font);
5479 if(!FT_IS_SCALABLE(ft_face))
5480 return 0;
5482 GDI_CheckNotLock();
5483 EnterCriticalSection( &freetype_cs );
5485 if(font->potm) {
5486 if(cbSize >= font->potm->otmSize)
5488 memcpy(potm, font->potm, font->potm->otmSize);
5489 scale_outline_font_metrics(font, potm);
5491 LeaveCriticalSection( &freetype_cs );
5492 return font->potm->otmSize;
5496 needed = sizeof(*potm);
5498 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5499 family_nameW = strdupW(font->name);
5501 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5502 * sizeof(WCHAR);
5503 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5504 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5505 style_nameW, lensty/sizeof(WCHAR));
5507 /* These names should be read from the TT name table */
5509 /* length of otmpFamilyName */
5510 needed += lenfam;
5512 /* length of otmpFaceName */
5513 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5514 needed += lenfam; /* just the family name */
5515 } else {
5516 needed += lenfam + lensty; /* family + " " + style */
5519 /* length of otmpStyleName */
5520 needed += lensty;
5522 /* length of otmpFullName */
5523 needed += lenfam + lensty;
5526 x_scale = ft_face->size->metrics.x_scale;
5527 y_scale = ft_face->size->metrics.y_scale;
5529 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5530 if(!pOS2) {
5531 FIXME("Can't find OS/2 table - not TT font?\n");
5532 ret = 0;
5533 goto end;
5536 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5537 if(!pHori) {
5538 FIXME("Can't find HHEA table - not TT font?\n");
5539 ret = 0;
5540 goto end;
5543 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5545 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",
5546 pOS2->usWinAscent, pOS2->usWinDescent,
5547 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5548 ft_face->ascender, ft_face->descender, ft_face->height,
5549 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5550 ft_face->bbox.yMax, ft_face->bbox.yMin);
5552 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5553 font->potm->otmSize = needed;
5555 #define TM font->potm->otmTextMetrics
5557 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5558 ascent = pHori->Ascender;
5559 descent = -pHori->Descender;
5560 } else {
5561 ascent = pOS2->usWinAscent;
5562 descent = pOS2->usWinDescent;
5565 if(font->yMax) {
5566 TM.tmAscent = font->yMax;
5567 TM.tmDescent = -font->yMin;
5568 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5569 } else {
5570 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5571 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5572 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5573 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5576 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5578 /* MSDN says:
5579 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5581 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5582 ((ascent + descent) -
5583 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5585 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5586 if (TM.tmAveCharWidth == 0) {
5587 TM.tmAveCharWidth = 1;
5589 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5590 TM.tmWeight = FW_REGULAR;
5591 if (font->fake_bold)
5592 TM.tmWeight = FW_BOLD;
5593 else
5595 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
5597 if (pOS2->usWeightClass > FW_MEDIUM)
5598 TM.tmWeight = pOS2->usWeightClass;
5600 else if (pOS2->usWeightClass <= FW_MEDIUM)
5601 TM.tmWeight = pOS2->usWeightClass;
5603 TM.tmOverhang = 0;
5604 TM.tmDigitizedAspectX = 300;
5605 TM.tmDigitizedAspectY = 300;
5606 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5607 * symbol range to 0 - f0ff
5610 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
5612 TM.tmFirstChar = 0;
5613 switch(GetACP())
5615 case 1257: /* Baltic */
5616 TM.tmLastChar = 0xf8fd;
5617 break;
5618 default:
5619 TM.tmLastChar = 0xf0ff;
5621 TM.tmBreakChar = 0x20;
5622 TM.tmDefaultChar = 0x1f;
5624 else
5626 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
5627 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
5629 if(pOS2->usFirstCharIndex <= 1)
5630 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
5631 else if (pOS2->usFirstCharIndex > 0xff)
5632 TM.tmBreakChar = 0x20;
5633 else
5634 TM.tmBreakChar = pOS2->usFirstCharIndex;
5635 TM.tmDefaultChar = TM.tmBreakChar - 1;
5637 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5638 TM.tmUnderlined = font->underline;
5639 TM.tmStruckOut = font->strikeout;
5641 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5642 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5643 (pOS2->version == 0xFFFFU ||
5644 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5645 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5646 else
5647 TM.tmPitchAndFamily = 0;
5649 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
5651 case PAN_FAMILY_SCRIPT:
5652 TM.tmPitchAndFamily |= FF_SCRIPT;
5653 break;
5655 case PAN_FAMILY_DECORATIVE:
5656 TM.tmPitchAndFamily |= FF_DECORATIVE;
5657 break;
5659 case PAN_ANY:
5660 case PAN_NO_FIT:
5661 case PAN_FAMILY_TEXT_DISPLAY:
5662 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
5663 /* which is clearly not what the panose spec says. */
5664 default:
5665 if(TM.tmPitchAndFamily == 0 || /* fixed */
5666 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
5667 TM.tmPitchAndFamily = FF_MODERN;
5668 else
5670 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
5672 case PAN_ANY:
5673 case PAN_NO_FIT:
5674 default:
5675 TM.tmPitchAndFamily |= FF_DONTCARE;
5676 break;
5678 case PAN_SERIF_COVE:
5679 case PAN_SERIF_OBTUSE_COVE:
5680 case PAN_SERIF_SQUARE_COVE:
5681 case PAN_SERIF_OBTUSE_SQUARE_COVE:
5682 case PAN_SERIF_SQUARE:
5683 case PAN_SERIF_THIN:
5684 case PAN_SERIF_BONE:
5685 case PAN_SERIF_EXAGGERATED:
5686 case PAN_SERIF_TRIANGLE:
5687 TM.tmPitchAndFamily |= FF_ROMAN;
5688 break;
5690 case PAN_SERIF_NORMAL_SANS:
5691 case PAN_SERIF_OBTUSE_SANS:
5692 case PAN_SERIF_PERP_SANS:
5693 case PAN_SERIF_FLARED:
5694 case PAN_SERIF_ROUNDED:
5695 TM.tmPitchAndFamily |= FF_SWISS;
5696 break;
5699 break;
5702 if(FT_IS_SCALABLE(ft_face))
5703 TM.tmPitchAndFamily |= TMPF_VECTOR;
5705 if(FT_IS_SFNT(ft_face))
5707 if (font->ntmFlags & NTM_PS_OPENTYPE)
5708 TM.tmPitchAndFamily |= TMPF_DEVICE;
5709 else
5710 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5713 TM.tmCharSet = font->charset;
5715 font->potm->otmFiller = 0;
5716 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5717 font->potm->otmfsSelection = pOS2->fsSelection;
5718 font->potm->otmfsType = pOS2->fsType;
5719 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5720 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5721 font->potm->otmItalicAngle = 0; /* POST table */
5722 font->potm->otmEMSquare = ft_face->units_per_EM;
5723 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5724 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5725 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5726 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5727 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5728 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5729 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5730 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5731 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5732 font->potm->otmMacAscent = TM.tmAscent;
5733 font->potm->otmMacDescent = -TM.tmDescent;
5734 font->potm->otmMacLineGap = font->potm->otmLineGap;
5735 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5736 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5737 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5738 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5739 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5740 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5741 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5742 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5743 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5744 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5745 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5746 if(!pPost) {
5747 font->potm->otmsUnderscoreSize = 0;
5748 font->potm->otmsUnderscorePosition = 0;
5749 } else {
5750 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5751 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5753 #undef TM
5755 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5756 cp = (char*)font->potm + sizeof(*font->potm);
5757 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5758 strcpyW((WCHAR*)cp, family_nameW);
5759 cp += lenfam;
5760 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5761 strcpyW((WCHAR*)cp, style_nameW);
5762 cp += lensty;
5763 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5764 strcpyW((WCHAR*)cp, family_nameW);
5765 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5766 strcatW((WCHAR*)cp, spaceW);
5767 strcatW((WCHAR*)cp, style_nameW);
5768 cp += lenfam + lensty;
5769 } else
5770 cp += lenfam;
5771 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5772 strcpyW((WCHAR*)cp, family_nameW);
5773 strcatW((WCHAR*)cp, spaceW);
5774 strcatW((WCHAR*)cp, style_nameW);
5775 ret = needed;
5777 if(potm && needed <= cbSize)
5779 memcpy(potm, font->potm, font->potm->otmSize);
5780 scale_outline_font_metrics(font, potm);
5783 end:
5784 HeapFree(GetProcessHeap(), 0, style_nameW);
5785 HeapFree(GetProcessHeap(), 0, family_nameW);
5787 LeaveCriticalSection( &freetype_cs );
5788 return ret;
5791 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5793 HFONTLIST *hfontlist;
5794 child->font = alloc_font();
5795 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5796 if(!child->font->ft_face)
5798 free_font(child->font);
5799 child->font = NULL;
5800 return FALSE;
5803 child->font->font_desc = font->font_desc;
5804 child->font->ntmFlags = child->face->ntmFlags;
5805 child->font->orientation = font->orientation;
5806 child->font->scale_y = font->scale_y;
5807 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5808 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5809 child->font->name = strdupW(child->face->family->FamilyName);
5810 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5811 child->font->base_font = font;
5812 list_add_head(&child_font_list, &child->font->entry);
5813 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5814 return TRUE;
5817 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5819 FT_UInt g;
5820 CHILD_FONT *child_font;
5822 if(font->base_font)
5823 font = font->base_font;
5825 *linked_font = font;
5827 if((*glyph = get_glyph_index(font, c)))
5828 return TRUE;
5830 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5832 if(!child_font->font)
5833 if(!load_child_font(font, child_font))
5834 continue;
5836 if(!child_font->font->ft_face)
5837 continue;
5838 g = get_glyph_index(child_font->font, c);
5839 if(g)
5841 *glyph = g;
5842 *linked_font = child_font->font;
5843 return TRUE;
5846 return FALSE;
5849 /*************************************************************
5850 * WineEngGetCharWidth
5853 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5854 LPINT buffer)
5856 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5857 UINT c;
5858 GLYPHMETRICS gm;
5859 FT_UInt glyph_index;
5860 GdiFont *linked_font;
5862 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5864 GDI_CheckNotLock();
5865 EnterCriticalSection( &freetype_cs );
5866 for(c = firstChar; c <= lastChar; c++) {
5867 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5868 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5869 &gm, 0, NULL, &identity);
5870 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5872 LeaveCriticalSection( &freetype_cs );
5873 return TRUE;
5876 /*************************************************************
5877 * WineEngGetCharABCWidths
5880 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5881 LPABC buffer)
5883 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5884 UINT c;
5885 GLYPHMETRICS gm;
5886 FT_UInt glyph_index;
5887 GdiFont *linked_font;
5889 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5891 if(!FT_IS_SCALABLE(font->ft_face))
5892 return FALSE;
5894 GDI_CheckNotLock();
5895 EnterCriticalSection( &freetype_cs );
5897 for(c = firstChar; c <= lastChar; c++) {
5898 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5899 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5900 &gm, 0, NULL, &identity);
5901 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5902 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5903 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5904 FONT_GM(linked_font,glyph_index)->bbx;
5906 LeaveCriticalSection( &freetype_cs );
5907 return TRUE;
5910 /*************************************************************
5911 * WineEngGetCharABCWidthsFloat
5914 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
5916 static const MAT2 identity = {{0,1}, {0,0}, {0,0}, {0,1}};
5917 UINT c;
5918 GLYPHMETRICS gm;
5919 FT_UInt glyph_index;
5920 GdiFont *linked_font;
5922 TRACE("%p, %d, %d, %p\n", font, first, last, buffer);
5924 GDI_CheckNotLock();
5925 EnterCriticalSection( &freetype_cs );
5927 for (c = first; c <= last; c++)
5929 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5930 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5931 &gm, 0, NULL, &identity);
5932 buffer[c - first].abcfA = FONT_GM(linked_font, glyph_index)->lsb;
5933 buffer[c - first].abcfB = FONT_GM(linked_font, glyph_index)->bbx;
5934 buffer[c - first].abcfC = FONT_GM(linked_font, glyph_index)->adv -
5935 FONT_GM(linked_font, glyph_index)->lsb -
5936 FONT_GM(linked_font, glyph_index)->bbx;
5938 LeaveCriticalSection( &freetype_cs );
5939 return TRUE;
5942 /*************************************************************
5943 * WineEngGetCharABCWidthsI
5946 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5947 LPABC buffer)
5949 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5950 UINT c;
5951 GLYPHMETRICS gm;
5952 FT_UInt glyph_index;
5953 GdiFont *linked_font;
5955 if(!FT_HAS_HORIZONTAL(font->ft_face))
5956 return FALSE;
5958 GDI_CheckNotLock();
5959 EnterCriticalSection( &freetype_cs );
5961 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5962 if (!pgi)
5963 for(c = firstChar; c < firstChar+count; c++) {
5964 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5965 &gm, 0, NULL, &identity);
5966 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5967 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5968 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5969 - FONT_GM(linked_font,c)->bbx;
5971 else
5972 for(c = 0; c < count; c++) {
5973 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5974 &gm, 0, NULL, &identity);
5975 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5976 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5977 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5978 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5981 LeaveCriticalSection( &freetype_cs );
5982 return TRUE;
5985 /*************************************************************
5986 * WineEngGetTextExtentExPoint
5989 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5990 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5992 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5993 INT idx;
5994 INT nfit = 0, ext;
5995 GLYPHMETRICS gm;
5996 TEXTMETRICW tm;
5997 FT_UInt glyph_index;
5998 GdiFont *linked_font;
6000 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
6001 max_ext, size);
6003 GDI_CheckNotLock();
6004 EnterCriticalSection( &freetype_cs );
6006 size->cx = 0;
6007 WineEngGetTextMetrics(font, &tm);
6008 size->cy = tm.tmHeight;
6010 for(idx = 0; idx < count; idx++) {
6011 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
6012 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6013 &gm, 0, NULL, &identity);
6014 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6015 ext = size->cx;
6016 if (! pnfit || ext <= max_ext) {
6017 ++nfit;
6018 if (dxs)
6019 dxs[idx] = ext;
6023 if (pnfit)
6024 *pnfit = nfit;
6026 LeaveCriticalSection( &freetype_cs );
6027 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6028 return TRUE;
6031 /*************************************************************
6032 * WineEngGetTextExtentExPointI
6035 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6036 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6038 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6039 INT idx;
6040 INT nfit = 0, ext;
6041 GLYPHMETRICS gm;
6042 TEXTMETRICW tm;
6044 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
6046 GDI_CheckNotLock();
6047 EnterCriticalSection( &freetype_cs );
6049 size->cx = 0;
6050 WineEngGetTextMetrics(font, &tm);
6051 size->cy = tm.tmHeight;
6053 for(idx = 0; idx < count; idx++) {
6054 WineEngGetGlyphOutline(font, indices[idx],
6055 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
6056 &identity);
6057 size->cx += FONT_GM(font,indices[idx])->adv;
6058 ext = size->cx;
6059 if (! pnfit || ext <= max_ext) {
6060 ++nfit;
6061 if (dxs)
6062 dxs[idx] = ext;
6066 if (pnfit)
6067 *pnfit = nfit;
6069 LeaveCriticalSection( &freetype_cs );
6070 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6071 return TRUE;
6074 /*************************************************************
6075 * WineEngGetFontData
6078 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6079 DWORD cbData)
6081 FT_Face ft_face = font->ft_face;
6082 FT_ULong len;
6083 FT_Error err;
6085 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6086 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6087 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6089 if(!FT_IS_SFNT(ft_face))
6090 return GDI_ERROR;
6092 if(!buf || !cbData)
6093 len = 0;
6094 else
6095 len = cbData;
6097 if(table) { /* MS tags differ in endianness from FT ones */
6098 table = table >> 24 | table << 24 |
6099 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
6102 /* make sure value of len is the value freetype says it needs */
6103 if(buf && len)
6105 FT_ULong needed = 0;
6106 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
6107 if( !err && needed < len) len = needed;
6109 err = load_sfnt_table(ft_face, table, offset, buf, &len);
6111 if(err) {
6112 TRACE("Can't find table %c%c%c%c\n",
6113 /* bytes were reversed */
6114 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
6115 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
6116 return GDI_ERROR;
6118 return len;
6121 /*************************************************************
6122 * WineEngGetTextFace
6125 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6127 INT n = strlenW(font->name) + 1;
6128 if(str) {
6129 lstrcpynW(str, font->name, count);
6130 return min(count, n);
6131 } else
6132 return n;
6135 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6137 if (fs) *fs = font->fs;
6138 return font->charset;
6141 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6143 GdiFont *font = dc->gdiFont, *linked_font;
6144 struct list *first_hfont;
6145 BOOL ret;
6147 GDI_CheckNotLock();
6148 EnterCriticalSection( &freetype_cs );
6149 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6150 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6151 if(font == linked_font)
6152 *new_hfont = dc->hFont;
6153 else
6155 first_hfont = list_head(&linked_font->hfontlist);
6156 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6158 LeaveCriticalSection( &freetype_cs );
6159 return ret;
6162 /* Retrieve a list of supported Unicode ranges for a given font.
6163 * Can be called with NULL gs to calculate the buffer size. Returns
6164 * the number of ranges found.
6166 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6168 DWORD num_ranges = 0;
6170 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6172 FT_UInt glyph_code;
6173 FT_ULong char_code, char_code_prev;
6175 glyph_code = 0;
6176 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6178 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6179 face->num_glyphs, glyph_code, char_code);
6181 if (!glyph_code) return 0;
6183 if (gs)
6185 gs->ranges[0].wcLow = (USHORT)char_code;
6186 gs->ranges[0].cGlyphs = 0;
6187 gs->cGlyphsSupported = 0;
6190 num_ranges = 1;
6191 while (glyph_code)
6193 if (char_code < char_code_prev)
6195 ERR("expected increasing char code from FT_Get_Next_Char\n");
6196 return 0;
6198 if (char_code - char_code_prev > 1)
6200 num_ranges++;
6201 if (gs)
6203 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6204 gs->ranges[num_ranges - 1].cGlyphs = 1;
6205 gs->cGlyphsSupported++;
6208 else if (gs)
6210 gs->ranges[num_ranges - 1].cGlyphs++;
6211 gs->cGlyphsSupported++;
6213 char_code_prev = char_code;
6214 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6217 else
6218 FIXME("encoding %u not supported\n", face->charmap->encoding);
6220 return num_ranges;
6223 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6225 DWORD size = 0;
6226 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
6228 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6229 if (glyphset)
6231 glyphset->cbThis = size;
6232 glyphset->cRanges = num_ranges;
6234 return size;
6237 /*************************************************************
6238 * FontIsLinked
6240 BOOL WineEngFontIsLinked(GdiFont *font)
6242 BOOL ret;
6243 GDI_CheckNotLock();
6244 EnterCriticalSection( &freetype_cs );
6245 ret = !list_empty(&font->child_fonts);
6246 LeaveCriticalSection( &freetype_cs );
6247 return ret;
6250 static BOOL is_hinting_enabled(void)
6252 /* Use the >= 2.2.0 function if available */
6253 if(pFT_Get_TrueType_Engine_Type)
6255 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6256 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6258 #ifdef FT_DRIVER_HAS_HINTER
6259 else
6261 FT_Module mod;
6263 /* otherwise if we've been compiled with < 2.2.0 headers
6264 use the internal macro */
6265 mod = pFT_Get_Module(library, "truetype");
6266 if(mod && FT_DRIVER_HAS_HINTER(mod))
6267 return TRUE;
6269 #endif
6271 return FALSE;
6274 static BOOL is_subpixel_rendering_enabled( void )
6276 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6277 return pFT_Library_SetLcdFilter &&
6278 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6279 #else
6280 return FALSE;
6281 #endif
6284 /*************************************************************************
6285 * GetRasterizerCaps (GDI32.@)
6287 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6289 static int hinting = -1;
6290 static int subpixel = -1;
6292 if(hinting == -1)
6294 hinting = is_hinting_enabled();
6295 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6298 if ( subpixel == -1 )
6300 subpixel = is_subpixel_rendering_enabled();
6301 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6304 lprs->nSize = sizeof(RASTERIZER_STATUS);
6305 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6306 if ( subpixel )
6307 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6308 lprs->nLanguageID = 0;
6309 return TRUE;
6312 /*************************************************************
6313 * WineEngRealizationInfo
6315 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6317 FIXME("(%p, %p): stub!\n", font, info);
6319 info->flags = 1;
6320 if(FT_IS_SCALABLE(font->ft_face))
6321 info->flags |= 2;
6323 info->cache_num = font->cache_num;
6324 info->unknown2 = -1;
6325 return TRUE;
6328 /*************************************************************************
6329 * Kerning support for TrueType fonts
6331 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6333 struct TT_kern_table
6335 USHORT version;
6336 USHORT nTables;
6339 struct TT_kern_subtable
6341 USHORT version;
6342 USHORT length;
6343 union
6345 USHORT word;
6346 struct
6348 USHORT horizontal : 1;
6349 USHORT minimum : 1;
6350 USHORT cross_stream: 1;
6351 USHORT override : 1;
6352 USHORT reserved1 : 4;
6353 USHORT format : 8;
6354 } bits;
6355 } coverage;
6358 struct TT_format0_kern_subtable
6360 USHORT nPairs;
6361 USHORT searchRange;
6362 USHORT entrySelector;
6363 USHORT rangeShift;
6366 struct TT_kern_pair
6368 USHORT left;
6369 USHORT right;
6370 short value;
6373 static DWORD parse_format0_kern_subtable(GdiFont *font,
6374 const struct TT_format0_kern_subtable *tt_f0_ks,
6375 const USHORT *glyph_to_char,
6376 KERNINGPAIR *kern_pair, DWORD cPairs)
6378 USHORT i, nPairs;
6379 const struct TT_kern_pair *tt_kern_pair;
6381 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6383 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6385 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6386 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6387 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6389 if (!kern_pair || !cPairs)
6390 return nPairs;
6392 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6394 nPairs = min(nPairs, cPairs);
6396 for (i = 0; i < nPairs; i++)
6398 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6399 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6400 /* this algorithm appears to better match what Windows does */
6401 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6402 if (kern_pair->iKernAmount < 0)
6404 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6405 kern_pair->iKernAmount -= font->ppem;
6407 else if (kern_pair->iKernAmount > 0)
6409 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6410 kern_pair->iKernAmount += font->ppem;
6412 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6414 TRACE("left %u right %u value %d\n",
6415 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6417 kern_pair++;
6419 TRACE("copied %u entries\n", nPairs);
6420 return nPairs;
6423 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6425 DWORD length;
6426 void *buf;
6427 const struct TT_kern_table *tt_kern_table;
6428 const struct TT_kern_subtable *tt_kern_subtable;
6429 USHORT i, nTables;
6430 USHORT *glyph_to_char;
6432 GDI_CheckNotLock();
6433 EnterCriticalSection( &freetype_cs );
6434 if (font->total_kern_pairs != (DWORD)-1)
6436 if (cPairs && kern_pair)
6438 cPairs = min(cPairs, font->total_kern_pairs);
6439 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6440 LeaveCriticalSection( &freetype_cs );
6441 return cPairs;
6443 LeaveCriticalSection( &freetype_cs );
6444 return font->total_kern_pairs;
6447 font->total_kern_pairs = 0;
6449 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6451 if (length == GDI_ERROR)
6453 TRACE("no kerning data in the font\n");
6454 LeaveCriticalSection( &freetype_cs );
6455 return 0;
6458 buf = HeapAlloc(GetProcessHeap(), 0, length);
6459 if (!buf)
6461 WARN("Out of memory\n");
6462 LeaveCriticalSection( &freetype_cs );
6463 return 0;
6466 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6468 /* build a glyph index to char code map */
6469 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6470 if (!glyph_to_char)
6472 WARN("Out of memory allocating a glyph index to char code map\n");
6473 HeapFree(GetProcessHeap(), 0, buf);
6474 LeaveCriticalSection( &freetype_cs );
6475 return 0;
6478 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6480 FT_UInt glyph_code;
6481 FT_ULong char_code;
6483 glyph_code = 0;
6484 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6486 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6487 font->ft_face->num_glyphs, glyph_code, char_code);
6489 while (glyph_code)
6491 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6493 /* FIXME: This doesn't match what Windows does: it does some fancy
6494 * things with duplicate glyph index to char code mappings, while
6495 * we just avoid overriding existing entries.
6497 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6498 glyph_to_char[glyph_code] = (USHORT)char_code;
6500 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6503 else
6505 ULONG n;
6507 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6508 for (n = 0; n <= 65535; n++)
6509 glyph_to_char[n] = (USHORT)n;
6512 tt_kern_table = buf;
6513 nTables = GET_BE_WORD(tt_kern_table->nTables);
6514 TRACE("version %u, nTables %u\n",
6515 GET_BE_WORD(tt_kern_table->version), nTables);
6517 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6519 for (i = 0; i < nTables; i++)
6521 struct TT_kern_subtable tt_kern_subtable_copy;
6523 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6524 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6525 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6527 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6528 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6529 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6531 /* According to the TrueType specification this is the only format
6532 * that will be properly interpreted by Windows and OS/2
6534 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6536 DWORD new_chunk, old_total = font->total_kern_pairs;
6538 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6539 glyph_to_char, NULL, 0);
6540 font->total_kern_pairs += new_chunk;
6542 if (!font->kern_pairs)
6543 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6544 font->total_kern_pairs * sizeof(*font->kern_pairs));
6545 else
6546 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6547 font->total_kern_pairs * sizeof(*font->kern_pairs));
6549 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6550 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6552 else
6553 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6555 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6558 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6559 HeapFree(GetProcessHeap(), 0, buf);
6561 if (cPairs && kern_pair)
6563 cPairs = min(cPairs, font->total_kern_pairs);
6564 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6565 LeaveCriticalSection( &freetype_cs );
6566 return cPairs;
6568 LeaveCriticalSection( &freetype_cs );
6569 return font->total_kern_pairs;
6572 #else /* HAVE_FREETYPE */
6574 /*************************************************************************/
6576 BOOL WineEngInit(void)
6578 return FALSE;
6580 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6582 return NULL;
6584 BOOL WineEngDestroyFontInstance(HFONT hfont)
6586 return FALSE;
6589 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6591 return 1;
6594 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6595 LPWORD pgi, DWORD flags)
6597 return GDI_ERROR;
6600 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6601 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6602 const MAT2* lpmat)
6604 ERR("called but we don't have FreeType\n");
6605 return GDI_ERROR;
6608 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6610 ERR("called but we don't have FreeType\n");
6611 return FALSE;
6614 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6615 OUTLINETEXTMETRICW *potm)
6617 ERR("called but we don't have FreeType\n");
6618 return 0;
6621 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6622 LPINT buffer)
6624 ERR("called but we don't have FreeType\n");
6625 return FALSE;
6628 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6629 LPABC buffer)
6631 ERR("called but we don't have FreeType\n");
6632 return FALSE;
6635 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6637 ERR("called but we don't have FreeType\n");
6638 return FALSE;
6641 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6642 LPABC buffer)
6644 ERR("called but we don't have FreeType\n");
6645 return FALSE;
6648 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6649 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6651 ERR("called but we don't have FreeType\n");
6652 return FALSE;
6655 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6656 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6658 ERR("called but we don't have FreeType\n");
6659 return FALSE;
6662 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6663 DWORD cbData)
6665 ERR("called but we don't have FreeType\n");
6666 return GDI_ERROR;
6669 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6671 ERR("called but we don't have FreeType\n");
6672 return 0;
6675 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6677 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6678 return 1;
6681 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6683 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
6684 return TRUE;
6687 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6689 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
6690 return NULL;
6693 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6695 FIXME("(%p, %p, %u): stub\n", font, fs, flags);
6696 return DEFAULT_CHARSET;
6699 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6701 return FALSE;
6704 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6706 FIXME("(%p, %p): stub\n", font, glyphset);
6707 return 0;
6710 BOOL WineEngFontIsLinked(GdiFont *font)
6712 return FALSE;
6715 /*************************************************************************
6716 * GetRasterizerCaps (GDI32.@)
6718 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6720 lprs->nSize = sizeof(RASTERIZER_STATUS);
6721 lprs->wFlags = 0;
6722 lprs->nLanguageID = 0;
6723 return TRUE;
6726 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6728 ERR("called but we don't have FreeType\n");
6729 return 0;
6732 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6734 ERR("called but we don't have FreeType\n");
6735 return FALSE;
6738 #endif /* HAVE_FREETYPE */