gdi32: Avoid hardcoding the Unicode string literal lengths.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blob9b07b97d3140e291b76c0d3d78aaa2497b568570
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 #include "resource.h"
94 WINE_DEFAULT_DEBUG_CHANNEL(font);
96 #ifdef HAVE_FREETYPE
98 #ifdef HAVE_FT2BUILD_H
99 #include <ft2build.h>
100 #endif
101 #ifdef HAVE_FREETYPE_FREETYPE_H
102 #include <freetype/freetype.h>
103 #endif
104 #ifdef HAVE_FREETYPE_FTGLYPH_H
105 #include <freetype/ftglyph.h>
106 #endif
107 #ifdef HAVE_FREETYPE_TTTABLES_H
108 #include <freetype/tttables.h>
109 #endif
110 #ifdef HAVE_FREETYPE_FTTYPES_H
111 #include <freetype/fttypes.h>
112 #endif
113 #ifdef HAVE_FREETYPE_FTSNAMES_H
114 #include <freetype/ftsnames.h>
115 #endif
116 #ifdef HAVE_FREETYPE_TTNAMEID_H
117 #include <freetype/ttnameid.h>
118 #endif
119 #ifdef HAVE_FREETYPE_FTOUTLN_H
120 #include <freetype/ftoutln.h>
121 #endif
122 #ifdef HAVE_FREETYPE_FTTRIGON_H
123 #include <freetype/fttrigon.h>
124 #endif
125 #ifdef HAVE_FREETYPE_FTWINFNT_H
126 #include <freetype/ftwinfnt.h>
127 #endif
128 #ifdef HAVE_FREETYPE_FTMODAPI_H
129 #include <freetype/ftmodapi.h>
130 #endif
131 #ifdef HAVE_FREETYPE_FTLCDFIL_H
132 #include <freetype/ftlcdfil.h>
133 #endif
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
136 typedef enum
138 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType;
142 #endif
144 static FT_Library library = 0;
145 typedef struct
147 FT_Int major;
148 FT_Int minor;
149 FT_Int patch;
150 } FT_Version_t;
151 static FT_Version_t FT_Version;
152 static DWORD FT_SimpleVersion;
154 static void *ft_handle = NULL;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_First_Char);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Next_Char);
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_Get_WinFNT_Header);
166 MAKE_FUNCPTR(FT_Init_FreeType);
167 MAKE_FUNCPTR(FT_Library_Version);
168 MAKE_FUNCPTR(FT_Load_Glyph);
169 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
170 MAKE_FUNCPTR(FT_Matrix_Multiply);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
173 #else
174 MAKE_FUNCPTR(FT_MulFix);
175 #endif
176 MAKE_FUNCPTR(FT_New_Face);
177 MAKE_FUNCPTR(FT_New_Memory_Face);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
179 MAKE_FUNCPTR(FT_Outline_Transform);
180 MAKE_FUNCPTR(FT_Outline_Translate);
181 MAKE_FUNCPTR(FT_Render_Glyph);
182 MAKE_FUNCPTR(FT_Select_Charmap);
183 MAKE_FUNCPTR(FT_Set_Charmap);
184 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
185 MAKE_FUNCPTR(FT_Vector_Transform);
186 MAKE_FUNCPTR(FT_Vector_Unit);
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
192 #ifdef SONAME_LIBFONTCONFIG
193 #include <fontconfig/fontconfig.h>
194 MAKE_FUNCPTR(FcConfigGetCurrent);
195 MAKE_FUNCPTR(FcFontList);
196 MAKE_FUNCPTR(FcFontSetDestroy);
197 MAKE_FUNCPTR(FcInit);
198 MAKE_FUNCPTR(FcObjectSetAdd);
199 MAKE_FUNCPTR(FcObjectSetCreate);
200 MAKE_FUNCPTR(FcObjectSetDestroy);
201 MAKE_FUNCPTR(FcPatternCreate);
202 MAKE_FUNCPTR(FcPatternDestroy);
203 MAKE_FUNCPTR(FcPatternGetBool);
204 MAKE_FUNCPTR(FcPatternGetString);
205 #endif
207 #undef MAKE_FUNCPTR
209 #ifndef FT_MAKE_TAG
210 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
211 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
212 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
213 #endif
215 #ifndef ft_encoding_none
216 #define FT_ENCODING_NONE ft_encoding_none
217 #endif
218 #ifndef ft_encoding_ms_symbol
219 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
220 #endif
221 #ifndef ft_encoding_unicode
222 #define FT_ENCODING_UNICODE ft_encoding_unicode
223 #endif
224 #ifndef ft_encoding_apple_roman
225 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
226 #endif
228 #ifdef WORDS_BIGENDIAN
229 #define GET_BE_WORD(x) (x)
230 #else
231 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
232 #endif
234 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
235 typedef struct {
236 FT_Short height;
237 FT_Short width;
238 FT_Pos size;
239 FT_Pos x_ppem;
240 FT_Pos y_ppem;
241 FT_Short internal_leading;
242 } Bitmap_Size;
244 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
245 So to let this compile on older versions of FreeType we'll define the
246 new structure here. */
247 typedef struct {
248 FT_Short height, width;
249 FT_Pos size, x_ppem, y_ppem;
250 } My_FT_Bitmap_Size;
252 struct enum_data
254 ENUMLOGFONTEXW elf;
255 NEWTEXTMETRICEXW ntm;
256 DWORD type;
259 typedef struct tagFace {
260 struct list entry;
261 WCHAR *StyleName;
262 WCHAR *FullName;
263 char *file;
264 void *font_data_ptr;
265 DWORD font_data_size;
266 FT_Long face_index;
267 FONTSIGNATURE fs;
268 FONTSIGNATURE fs_links;
269 DWORD ntmFlags;
270 FT_Fixed font_version;
271 BOOL scalable;
272 Bitmap_Size size; /* set if face is a bitmap */
273 BOOL external; /* TRUE if we should manually add this font to the registry */
274 struct tagFamily *family;
275 /* Cached data for Enum */
276 struct enum_data *cached_enum_data;
277 } Face;
279 typedef struct tagFamily {
280 struct list entry;
281 const WCHAR *FamilyName;
282 const WCHAR *EnglishName;
283 struct list faces;
284 } Family;
286 typedef struct {
287 GLYPHMETRICS gm;
288 INT adv; /* These three hold to widths of the unrotated chars */
289 INT lsb;
290 INT bbx;
291 BOOL init;
292 } GM;
294 typedef struct {
295 FLOAT eM11, eM12;
296 FLOAT eM21, eM22;
297 } FMAT2;
299 typedef struct {
300 DWORD hash;
301 LOGFONTW lf;
302 FMAT2 matrix;
303 BOOL can_use_bitmap;
304 } FONT_DESC;
306 typedef struct tagHFONTLIST {
307 struct list entry;
308 HFONT hfont;
309 } HFONTLIST;
311 typedef struct {
312 struct list entry;
313 Face *face;
314 GdiFont *font;
315 } CHILD_FONT;
317 struct tagGdiFont {
318 struct list entry;
319 GM **gm;
320 DWORD gmsize;
321 struct list hfontlist;
322 OUTLINETEXTMETRICW *potm;
323 DWORD total_kern_pairs;
324 KERNINGPAIR *kern_pairs;
325 struct list child_fonts;
327 /* the following members can be accessed without locking, they are never modified after creation */
328 FT_Face ft_face;
329 struct font_mapping *mapping;
330 LPWSTR name;
331 int charset;
332 int codepage;
333 BOOL fake_italic;
334 BOOL fake_bold;
335 BYTE underline;
336 BYTE strikeout;
337 INT orientation;
338 FONT_DESC font_desc;
339 LONG aveWidth, ppem;
340 double scale_y;
341 SHORT yMax;
342 SHORT yMin;
343 DWORD ntmFlags;
344 FONTSIGNATURE fs;
345 GdiFont *base_font;
346 VOID *GSUB_Table;
347 DWORD cache_num;
350 typedef struct {
351 struct list entry;
352 const WCHAR *font_name;
353 struct list links;
354 } SYSTEM_LINKS;
356 struct enum_charset_element {
357 DWORD mask;
358 DWORD charset;
359 WCHAR name[LF_FACESIZE];
362 struct enum_charset_list {
363 DWORD total;
364 struct enum_charset_element element[32];
367 #define GM_BLOCK_SIZE 128
368 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
370 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
371 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
372 #define UNUSED_CACHE_SIZE 10
373 static struct list child_font_list = LIST_INIT(child_font_list);
374 static struct list system_links = LIST_INIT(system_links);
376 static struct list font_subst_list = LIST_INIT(font_subst_list);
378 static struct list font_list = LIST_INIT(font_list);
380 struct freetype_physdev
382 struct gdi_physdev dev;
383 GdiFont *font;
386 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
388 return (struct freetype_physdev *)dev;
391 static const struct gdi_dc_funcs freetype_funcs;
393 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
394 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
395 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
397 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
398 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
399 'W','i','n','d','o','w','s','\\',
400 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
401 'F','o','n','t','s','\0'};
403 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
404 'W','i','n','d','o','w','s',' ','N','T','\\',
405 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
406 'F','o','n','t','s','\0'};
408 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
409 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
410 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
411 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
413 static const WCHAR * const SystemFontValues[] = {
414 System_Value,
415 OEMFont_Value,
416 FixedSys_Value,
417 NULL
420 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
421 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
423 /* Interesting and well-known (frequently-assumed!) font names */
424 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
425 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 };
426 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
427 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
428 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
429 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
430 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
431 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
433 static const WCHAR arial[] = {'A','r','i','a','l',0};
434 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
435 static const WCHAR bitstream_vera_sans_mono[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',' ','M','o','n','o',0};
436 static const WCHAR bitstream_vera_serif[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','e','r','i','f',0};
437 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
438 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
439 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
440 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
441 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
442 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
444 static const WCHAR *default_serif_list[] =
446 times_new_roman,
447 liberation_serif,
448 bitstream_vera_serif,
449 NULL
452 static const WCHAR *default_fixed_list[] =
454 courier_new,
455 liberation_mono,
456 bitstream_vera_sans_mono,
457 NULL
460 static const WCHAR *default_sans_list[] =
462 arial,
463 liberation_sans,
464 bitstream_vera_sans,
465 NULL
468 typedef struct {
469 WCHAR *name;
470 INT charset;
471 } NameCs;
473 typedef struct tagFontSubst {
474 struct list entry;
475 NameCs from;
476 NameCs to;
477 } FontSubst;
479 /* Registry font cache key and value names */
480 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
481 'F','o','n','t','s',0};
482 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
483 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
484 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
485 static const WCHAR face_italic_value[] = {'I','t','a','l','i','c',0};
486 static const WCHAR face_bold_value[] = {'B','o','l','d',0};
487 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
488 static const WCHAR face_external_value[] = {'E','x','t','e','r','n','a','l',0};
489 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
490 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
491 static const WCHAR face_size_value[] = {'S','i','z','e',0};
492 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
493 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
494 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
495 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
496 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
499 struct font_mapping
501 struct list entry;
502 int refcount;
503 dev_t dev;
504 ino_t ino;
505 void *data;
506 size_t size;
509 static struct list mappings_list = LIST_INIT( mappings_list );
511 static CRITICAL_SECTION freetype_cs;
512 static CRITICAL_SECTION_DEBUG critsect_debug =
514 0, 0, &freetype_cs,
515 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
516 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
518 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
520 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
522 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
523 static BOOL use_default_fallback = FALSE;
525 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
526 static BOOL get_outline_text_metrics(GdiFont *font);
527 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
529 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
530 'W','i','n','d','o','w','s',' ','N','T','\\',
531 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
532 'S','y','s','t','e','m','L','i','n','k',0};
534 /****************************************
535 * Notes on .fon files
537 * The fonts System, FixedSys and Terminal are special. There are typically multiple
538 * versions installed for different resolutions and codepages. Windows stores which one to use
539 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
540 * Key Meaning
541 * FIXEDFON.FON FixedSys
542 * FONTS.FON System
543 * OEMFONT.FON Terminal
544 * LogPixels Current dpi set by the display control panel applet
545 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
546 * also has a LogPixels value that appears to mirror this)
548 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
549 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
550 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
551 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
552 * so that makes sense.
554 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
555 * to be mapped into the registry on Windows 2000 at least).
556 * I have
557 * woafont=app850.fon
558 * ega80woa.fon=ega80850.fon
559 * ega40woa.fon=ega40850.fon
560 * cga80woa.fon=cga80850.fon
561 * cga40woa.fon=cga40850.fon
564 /* These are all structures needed for the GSUB table */
566 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
567 #define TATEGAKI_LOWER_BOUND 0x02F1
569 typedef struct {
570 DWORD version;
571 WORD ScriptList;
572 WORD FeatureList;
573 WORD LookupList;
574 } GSUB_Header;
576 typedef struct {
577 CHAR ScriptTag[4];
578 WORD Script;
579 } GSUB_ScriptRecord;
581 typedef struct {
582 WORD ScriptCount;
583 GSUB_ScriptRecord ScriptRecord[1];
584 } GSUB_ScriptList;
586 typedef struct {
587 CHAR LangSysTag[4];
588 WORD LangSys;
589 } GSUB_LangSysRecord;
591 typedef struct {
592 WORD DefaultLangSys;
593 WORD LangSysCount;
594 GSUB_LangSysRecord LangSysRecord[1];
595 } GSUB_Script;
597 typedef struct {
598 WORD LookupOrder; /* Reserved */
599 WORD ReqFeatureIndex;
600 WORD FeatureCount;
601 WORD FeatureIndex[1];
602 } GSUB_LangSys;
604 typedef struct {
605 CHAR FeatureTag[4];
606 WORD Feature;
607 } GSUB_FeatureRecord;
609 typedef struct {
610 WORD FeatureCount;
611 GSUB_FeatureRecord FeatureRecord[1];
612 } GSUB_FeatureList;
614 typedef struct {
615 WORD FeatureParams; /* Reserved */
616 WORD LookupCount;
617 WORD LookupListIndex[1];
618 } GSUB_Feature;
620 typedef struct {
621 WORD LookupCount;
622 WORD Lookup[1];
623 } GSUB_LookupList;
625 typedef struct {
626 WORD LookupType;
627 WORD LookupFlag;
628 WORD SubTableCount;
629 WORD SubTable[1];
630 } GSUB_LookupTable;
632 typedef struct {
633 WORD CoverageFormat;
634 WORD GlyphCount;
635 WORD GlyphArray[1];
636 } GSUB_CoverageFormat1;
638 typedef struct {
639 WORD Start;
640 WORD End;
641 WORD StartCoverageIndex;
642 } GSUB_RangeRecord;
644 typedef struct {
645 WORD CoverageFormat;
646 WORD RangeCount;
647 GSUB_RangeRecord RangeRecord[1];
648 } GSUB_CoverageFormat2;
650 typedef struct {
651 WORD SubstFormat; /* = 1 */
652 WORD Coverage;
653 WORD DeltaGlyphID;
654 } GSUB_SingleSubstFormat1;
656 typedef struct {
657 WORD SubstFormat; /* = 2 */
658 WORD Coverage;
659 WORD GlyphCount;
660 WORD Substitute[1];
661 }GSUB_SingleSubstFormat2;
663 #ifdef HAVE_CARBON_CARBON_H
664 static char *find_cache_dir(void)
666 FSRef ref;
667 OSErr err;
668 static char cached_path[MAX_PATH];
669 static const char *wine = "/Wine", *fonts = "/Fonts";
671 if(*cached_path) return cached_path;
673 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
674 if(err != noErr)
676 WARN("can't create cached data folder\n");
677 return NULL;
679 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
680 if(err != noErr)
682 WARN("can't create cached data path\n");
683 *cached_path = '\0';
684 return NULL;
686 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
688 ERR("Could not create full path\n");
689 *cached_path = '\0';
690 return NULL;
692 strcat(cached_path, wine);
694 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
696 WARN("Couldn't mkdir %s\n", cached_path);
697 *cached_path = '\0';
698 return NULL;
700 strcat(cached_path, fonts);
701 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
703 WARN("Couldn't mkdir %s\n", cached_path);
704 *cached_path = '\0';
705 return NULL;
707 return cached_path;
710 /******************************************************************
711 * expand_mac_font
713 * Extracts individual TrueType font files from a Mac suitcase font
714 * and saves them into the user's caches directory (see
715 * find_cache_dir()).
716 * Returns a NULL terminated array of filenames.
718 * We do this because they are apps that try to read ttf files
719 * themselves and they don't like Mac suitcase files.
721 static char **expand_mac_font(const char *path)
723 FSRef ref;
724 SInt16 res_ref;
725 OSStatus s;
726 unsigned int idx;
727 const char *out_dir;
728 const char *filename;
729 int output_len;
730 struct {
731 char **array;
732 unsigned int size, max_size;
733 } ret;
735 TRACE("path %s\n", path);
737 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
738 if(s != noErr)
740 WARN("failed to get ref\n");
741 return NULL;
744 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
745 if(s != noErr)
747 TRACE("no data fork, so trying resource fork\n");
748 res_ref = FSOpenResFile(&ref, fsRdPerm);
749 if(res_ref == -1)
751 TRACE("unable to open resource fork\n");
752 return NULL;
756 ret.size = 0;
757 ret.max_size = 10;
758 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
759 if(!ret.array)
761 CloseResFile(res_ref);
762 return NULL;
765 out_dir = find_cache_dir();
767 filename = strrchr(path, '/');
768 if(!filename) filename = path;
769 else filename++;
771 /* output filename has the form out_dir/filename_%04x.ttf */
772 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
774 UseResFile(res_ref);
775 idx = 1;
776 while(1)
778 FamRec *fam_rec;
779 unsigned short *num_faces_ptr, num_faces, face;
780 AsscEntry *assoc;
781 Handle fond;
782 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
784 fond = Get1IndResource(fond_res, idx);
785 if(!fond) break;
786 TRACE("got fond resource %d\n", idx);
787 HLock(fond);
789 fam_rec = *(FamRec**)fond;
790 num_faces_ptr = (unsigned short *)(fam_rec + 1);
791 num_faces = GET_BE_WORD(*num_faces_ptr);
792 num_faces++;
793 assoc = (AsscEntry*)(num_faces_ptr + 1);
794 TRACE("num faces %04x\n", num_faces);
795 for(face = 0; face < num_faces; face++, assoc++)
797 Handle sfnt;
798 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
799 unsigned short size, font_id;
800 char *output;
802 size = GET_BE_WORD(assoc->fontSize);
803 font_id = GET_BE_WORD(assoc->fontID);
804 if(size != 0)
806 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
807 continue;
810 TRACE("trying to load sfnt id %04x\n", font_id);
811 sfnt = GetResource(sfnt_res, font_id);
812 if(!sfnt)
814 TRACE("can't get sfnt resource %04x\n", font_id);
815 continue;
818 output = HeapAlloc(GetProcessHeap(), 0, output_len);
819 if(output)
821 int fd;
823 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
825 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
826 if(fd != -1 || errno == EEXIST)
828 if(fd != -1)
830 unsigned char *sfnt_data;
832 HLock(sfnt);
833 sfnt_data = *(unsigned char**)sfnt;
834 write(fd, sfnt_data, GetHandleSize(sfnt));
835 HUnlock(sfnt);
836 close(fd);
838 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
840 ret.max_size *= 2;
841 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
843 ret.array[ret.size++] = output;
845 else
847 WARN("unable to create %s\n", output);
848 HeapFree(GetProcessHeap(), 0, output);
851 ReleaseResource(sfnt);
853 HUnlock(fond);
854 ReleaseResource(fond);
855 idx++;
857 CloseResFile(res_ref);
859 return ret.array;
862 #endif /* HAVE_CARBON_CARBON_H */
864 static inline BOOL is_win9x(void)
866 return GetVersion() & 0x80000000;
869 This function builds an FT_Fixed from a double. It fails if the absolute
870 value of the float number is greater than 32768.
872 static inline FT_Fixed FT_FixedFromFloat(double f)
874 return f * 0x10000;
878 This function builds an FT_Fixed from a FIXED. It simply put f.value
879 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
881 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
883 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
887 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
889 Family *family;
890 Face *face;
891 const char *file;
892 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
893 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
895 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
896 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
898 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
900 if(face_name && strcmpiW(face_name, family->FamilyName))
901 continue;
902 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
904 if (!face->file)
905 continue;
906 file = strrchr(face->file, '/');
907 if(!file)
908 file = face->file;
909 else
910 file++;
911 if(!strcasecmp(file, file_nameA))
913 HeapFree(GetProcessHeap(), 0, file_nameA);
914 return face;
918 HeapFree(GetProcessHeap(), 0, file_nameA);
919 return NULL;
922 static Family *find_family_from_name(const WCHAR *name)
924 Family *family;
926 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
928 if(!strcmpiW(family->FamilyName, name))
929 return family;
932 return NULL;
935 static void DumpSubstList(void)
937 FontSubst *psub;
939 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
941 if(psub->from.charset != -1 || psub->to.charset != -1)
942 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
943 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
944 else
945 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
946 debugstr_w(psub->to.name));
948 return;
951 static LPWSTR strdupW(LPCWSTR p)
953 LPWSTR ret;
954 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
955 ret = HeapAlloc(GetProcessHeap(), 0, len);
956 memcpy(ret, p, len);
957 return ret;
960 static LPSTR strdupA(LPCSTR p)
962 LPSTR ret;
963 DWORD len = (strlen(p) + 1);
964 ret = HeapAlloc(GetProcessHeap(), 0, len);
965 memcpy(ret, p, len);
966 return ret;
969 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
970 INT from_charset)
972 FontSubst *element;
974 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
976 if(!strcmpiW(element->from.name, from_name) &&
977 (element->from.charset == from_charset ||
978 element->from.charset == -1))
979 return element;
982 return NULL;
985 #define ADD_FONT_SUBST_FORCE 1
987 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
989 FontSubst *from_exist, *to_exist;
991 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
993 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
995 list_remove(&from_exist->entry);
996 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
997 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
998 HeapFree(GetProcessHeap(), 0, from_exist);
999 from_exist = NULL;
1002 if(!from_exist)
1004 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1006 if(to_exist)
1008 HeapFree(GetProcessHeap(), 0, subst->to.name);
1009 subst->to.name = strdupW(to_exist->to.name);
1012 list_add_tail(subst_list, &subst->entry);
1014 return TRUE;
1017 HeapFree(GetProcessHeap(), 0, subst->from.name);
1018 HeapFree(GetProcessHeap(), 0, subst->to.name);
1019 HeapFree(GetProcessHeap(), 0, subst);
1020 return FALSE;
1023 static void split_subst_info(NameCs *nc, LPSTR str)
1025 CHAR *p = strrchr(str, ',');
1026 DWORD len;
1028 nc->charset = -1;
1029 if(p && *(p+1)) {
1030 nc->charset = strtol(p+1, NULL, 10);
1031 *p = '\0';
1033 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
1034 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1035 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
1038 static void LoadSubstList(void)
1040 FontSubst *psub;
1041 HKEY hkey;
1042 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1043 LPSTR value;
1044 LPVOID data;
1046 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1047 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1048 &hkey) == ERROR_SUCCESS) {
1050 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1051 &valuelen, &datalen, NULL, NULL);
1053 valuelen++; /* returned value doesn't include room for '\0' */
1054 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1055 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1057 dlen = datalen;
1058 vlen = valuelen;
1059 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1060 &dlen) == ERROR_SUCCESS) {
1061 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1063 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1064 split_subst_info(&psub->from, value);
1065 split_subst_info(&psub->to, data);
1067 /* Win 2000 doesn't allow mapping between different charsets
1068 or mapping of DEFAULT_CHARSET */
1069 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1070 psub->to.charset == DEFAULT_CHARSET) {
1071 HeapFree(GetProcessHeap(), 0, psub->to.name);
1072 HeapFree(GetProcessHeap(), 0, psub->from.name);
1073 HeapFree(GetProcessHeap(), 0, psub);
1074 } else {
1075 add_font_subst(&font_subst_list, psub, 0);
1077 /* reset dlen and vlen */
1078 dlen = datalen;
1079 vlen = valuelen;
1081 HeapFree(GetProcessHeap(), 0, data);
1082 HeapFree(GetProcessHeap(), 0, value);
1083 RegCloseKey(hkey);
1088 /*****************************************************************
1089 * get_name_table_entry
1091 * Supply the platform, encoding, language and name ids in req
1092 * and if the name exists the function will fill in the string
1093 * and string_len members. The string is owned by FreeType so
1094 * don't free it. Returns TRUE if the name is found else FALSE.
1096 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1098 FT_SfntName name;
1099 FT_UInt num_names, name_index;
1101 if(FT_IS_SFNT(ft_face))
1103 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1105 for(name_index = 0; name_index < num_names; name_index++)
1107 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1109 if((name.platform_id == req->platform_id) &&
1110 (name.encoding_id == req->encoding_id) &&
1111 (name.language_id == req->language_id) &&
1112 (name.name_id == req->name_id))
1114 req->string = name.string;
1115 req->string_len = name.string_len;
1116 return TRUE;
1121 req->string = NULL;
1122 req->string_len = 0;
1123 return FALSE;
1126 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1128 WCHAR *ret = NULL;
1129 FT_SfntName name;
1131 name.platform_id = TT_PLATFORM_MICROSOFT;
1132 name.encoding_id = TT_MS_ID_UNICODE_CS;
1133 name.language_id = language_id;
1134 name.name_id = name_id;
1136 if(get_name_table_entry(ft_face, &name))
1138 FT_UInt i;
1140 /* String is not nul terminated and string_len is a byte length. */
1141 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1142 for(i = 0; i < name.string_len / 2; i++)
1144 WORD *tmp = (WORD *)&name.string[i * 2];
1145 ret[i] = GET_BE_WORD(*tmp);
1147 ret[i] = 0;
1148 TRACE("Got localised name %s\n", debugstr_w(ret));
1151 return ret;
1154 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1156 DWORD type, needed;
1157 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1158 if(r != ERROR_SUCCESS) return r;
1159 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1160 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1163 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1165 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1168 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1170 DWORD needed;
1171 DWORD num_strikes, max_strike_key_len;
1173 /* If we have a File Name key then this is a real font, not just the parent
1174 key of a bunch of non-scalable strikes */
1175 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1177 DWORD italic, bold;
1178 Face *face;
1179 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1180 face->cached_enum_data = NULL;
1182 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1183 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1185 face->StyleName = strdupW(face_name);
1186 face->family = family;
1188 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1190 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1191 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1192 face->FullName = fullName;
1194 else
1195 face->FullName = NULL;
1197 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1198 reg_load_dword(hkey_face, face_italic_value, &italic);
1199 reg_load_dword(hkey_face, face_bold_value, &bold);
1200 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1201 reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external);
1203 needed = sizeof(face->fs);
1204 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1205 memset(&face->fs_links, 0, sizeof(face->fs_links));
1207 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1209 face->scalable = TRUE;
1210 memset(&face->size, 0, sizeof(face->size));
1212 else
1214 face->scalable = FALSE;
1215 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1216 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1217 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1218 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1219 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1221 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1222 face->size.height, face->size.width, face->size.size >> 6,
1223 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1226 face->ntmFlags = 0;
1227 if (italic) face->ntmFlags |= NTM_ITALIC;
1228 if (bold) face->ntmFlags |= NTM_BOLD;
1229 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1231 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1232 face->fs.fsCsb[0], face->fs.fsCsb[1],
1233 face->fs.fsUsb[0], face->fs.fsUsb[1],
1234 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1236 if(!italic && !bold)
1237 list_add_head(&family->faces, &face->entry);
1238 else
1239 list_add_tail(&family->faces, &face->entry);
1241 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1244 /* do we have any bitmap strikes? */
1245 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1246 NULL, NULL, NULL, NULL);
1247 if(num_strikes != 0)
1249 WCHAR strike_name[10];
1250 DWORD strike_index = 0;
1252 needed = sizeof(strike_name) / sizeof(WCHAR);
1253 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1254 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1256 HKEY hkey_strike;
1257 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1258 load_face(hkey_strike, face_name, family);
1259 RegCloseKey(hkey_strike);
1260 needed = sizeof(strike_name) / sizeof(WCHAR);
1265 static void load_font_list_from_cache(HKEY hkey_font_cache)
1267 DWORD max_family_key_len, size;
1268 WCHAR *family_name;
1269 DWORD family_index = 0;
1270 Family *family;
1271 HKEY hkey_family;
1273 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1274 NULL, NULL, NULL, NULL);
1275 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1277 size = max_family_key_len + 1;
1278 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1279 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1281 WCHAR *english_family = NULL;
1282 DWORD face_index = 0;
1283 WCHAR *face_name;
1284 DWORD max_face_key_len;
1286 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1287 TRACE("opened family key %s\n", debugstr_w(family_name));
1288 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1290 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1291 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1294 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1295 family->FamilyName = strdupW(family_name);
1296 family->EnglishName = english_family;
1297 list_init(&family->faces);
1298 list_add_tail(&font_list, &family->entry);
1300 if(english_family)
1302 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1303 subst->from.name = strdupW(english_family);
1304 subst->from.charset = -1;
1305 subst->to.name = strdupW(family_name);
1306 subst->to.charset = -1;
1307 add_font_subst(&font_subst_list, subst, 0);
1310 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1311 NULL, NULL, NULL, NULL);
1313 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1314 size = max_face_key_len + 1;
1315 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1316 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1318 HKEY hkey_face;
1320 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1321 load_face(hkey_face, face_name, family);
1322 RegCloseKey(hkey_face);
1323 size = max_face_key_len + 1;
1325 HeapFree(GetProcessHeap(), 0, face_name);
1326 RegCloseKey(hkey_family);
1327 size = max_family_key_len + 1;
1330 HeapFree(GetProcessHeap(), 0, family_name);
1333 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1335 LONG ret;
1336 HKEY hkey_wine_fonts;
1338 /* We don't want to create the fonts key as volatile, so open this first */
1339 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1340 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1341 if(ret != ERROR_SUCCESS)
1343 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1344 return ret;
1347 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1348 KEY_ALL_ACCESS, NULL, hkey, disposition);
1349 RegCloseKey(hkey_wine_fonts);
1350 return ret;
1353 static void add_face_to_cache(Face *face)
1355 HKEY hkey_font_cache, hkey_family, hkey_face;
1356 WCHAR *face_key_name;
1358 create_font_cache_key(&hkey_font_cache, NULL);
1360 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1361 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1362 if(face->family->EnglishName)
1363 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1364 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1366 if(face->scalable)
1367 face_key_name = face->StyleName;
1368 else
1370 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1371 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1372 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1374 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1375 &hkey_face, NULL);
1376 if(!face->scalable)
1377 HeapFree(GetProcessHeap(), 0, face_key_name);
1379 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1380 if (face->FullName)
1381 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1382 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1384 reg_save_dword(hkey_face, face_index_value, face->face_index);
1385 reg_save_dword(hkey_face, face_italic_value, (face->ntmFlags & NTM_ITALIC) != 0);
1386 reg_save_dword(hkey_face, face_bold_value, (face->ntmFlags & NTM_BOLD) != 0);
1387 reg_save_dword(hkey_face, face_version_value, face->font_version);
1388 reg_save_dword(hkey_face, face_external_value, face->external);
1390 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1392 if(!face->scalable)
1394 reg_save_dword(hkey_face, face_height_value, face->size.height);
1395 reg_save_dword(hkey_face, face_width_value, face->size.width);
1396 reg_save_dword(hkey_face, face_size_value, face->size.size);
1397 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1398 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1399 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1401 RegCloseKey(hkey_face);
1402 RegCloseKey(hkey_family);
1403 RegCloseKey(hkey_font_cache);
1406 static inline int TestStyles(DWORD flags, DWORD styles)
1408 return (flags & styles) == styles;
1411 static int StyleOrdering(Face *face)
1413 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1414 return 3;
1415 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1416 return 2;
1417 if (TestStyles(face->ntmFlags, NTM_BOLD))
1418 return 1;
1419 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1420 return 0;
1422 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1423 debugstr_w(face->family->FamilyName),
1424 debugstr_w(face->StyleName),
1425 face->ntmFlags);
1427 return 9999;
1430 /* Add a style of face to a font family using an ordering of the list such
1431 that regular fonts come before bold and italic, and single styles come
1432 before compound styles. */
1433 static void AddFaceToFamily(Face *face, Family *family)
1435 struct list *entry;
1437 LIST_FOR_EACH( entry, &family->faces )
1439 Face *ent = LIST_ENTRY(entry, Face, entry);
1440 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1442 list_add_before( entry, &face->entry );
1445 #define ADDFONT_EXTERNAL_FONT 0x01
1446 #define ADDFONT_FORCE_BITMAP 0x02
1447 #define ADDFONT_ADD_TO_CACHE 0x04
1449 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1451 FT_Face ft_face;
1452 TT_OS2 *pOS2;
1453 TT_Header *pHeader = NULL;
1454 WCHAR *english_family, *localised_family, *StyleW;
1455 DWORD len;
1456 Family *family;
1457 Face *face;
1458 struct list *family_elem_ptr, *face_elem_ptr;
1459 FT_Error err;
1460 FT_Long face_index = 0, num_faces;
1461 FT_WinFNT_HeaderRec winfnt_header;
1462 int i, bitmap_num, internal_leading;
1463 FONTSIGNATURE fs;
1465 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1466 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1468 #ifdef HAVE_CARBON_CARBON_H
1469 if(file && !fake_family)
1471 char **mac_list = expand_mac_font(file);
1472 if(mac_list)
1474 BOOL had_one = FALSE;
1475 char **cursor;
1476 for(cursor = mac_list; *cursor; cursor++)
1478 had_one = TRUE;
1479 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1480 HeapFree(GetProcessHeap(), 0, *cursor);
1482 HeapFree(GetProcessHeap(), 0, mac_list);
1483 if(had_one)
1484 return 1;
1487 #endif /* HAVE_CARBON_CARBON_H */
1489 do {
1490 if (file)
1492 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1493 err = pFT_New_Face(library, file, face_index, &ft_face);
1494 } else
1496 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1497 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1500 if(err != 0) {
1501 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1502 return 0;
1505 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*/
1506 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1507 pFT_Done_Face(ft_face);
1508 return 0;
1511 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1512 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1513 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1514 pFT_Done_Face(ft_face);
1515 return 0;
1518 if(FT_IS_SFNT(ft_face))
1520 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1521 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1522 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1524 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1525 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1526 pFT_Done_Face(ft_face);
1527 return 0;
1530 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1531 we don't want to load these. */
1532 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1534 FT_ULong len = 0;
1536 if(!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1538 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1539 pFT_Done_Face(ft_face);
1540 return 0;
1545 if(!ft_face->family_name || !ft_face->style_name) {
1546 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1547 pFT_Done_Face(ft_face);
1548 return 0;
1551 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1553 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1554 pFT_Done_Face(ft_face);
1555 return 0;
1558 if (target_family)
1560 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1561 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1563 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1564 HeapFree(GetProcessHeap(), 0, localised_family);
1565 num_faces = ft_face->num_faces;
1566 pFT_Done_Face(ft_face);
1567 continue;
1569 HeapFree(GetProcessHeap(), 0, localised_family);
1572 bitmap_num = 0;
1573 do {
1574 My_FT_Bitmap_Size *size = NULL;
1575 FT_ULong tmp_size;
1577 if(!FT_IS_SCALABLE(ft_face))
1578 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1580 if(fake_family)
1582 len = MultiByteToWideChar(CP_ACP, 0, fake_family, -1, NULL, 0);
1583 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1584 MultiByteToWideChar(CP_ACP, 0, fake_family, -1, english_family, len);
1586 else
1588 english_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1589 if(!english_family)
1591 len = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0);
1592 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1593 MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, english_family, len);
1597 localised_family = NULL;
1598 if(!fake_family) {
1599 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1600 if(localised_family && !strcmpiW(localised_family, english_family)) {
1601 HeapFree(GetProcessHeap(), 0, localised_family);
1602 localised_family = NULL;
1606 family = NULL;
1607 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1608 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1609 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1610 break;
1611 family = NULL;
1613 if(!family) {
1614 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1615 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1616 family->EnglishName = localised_family ? strdupW(english_family) : NULL;
1617 list_init(&family->faces);
1618 list_add_tail(&font_list, &family->entry);
1620 if(localised_family) {
1621 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1622 subst->from.name = strdupW(english_family);
1623 subst->from.charset = -1;
1624 subst->to.name = strdupW(localised_family);
1625 subst->to.charset = -1;
1626 add_font_subst(&font_subst_list, subst, 0);
1629 HeapFree(GetProcessHeap(), 0, localised_family);
1630 HeapFree(GetProcessHeap(), 0, english_family);
1632 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1633 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1634 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1636 internal_leading = 0;
1637 memset(&fs, 0, sizeof(fs));
1639 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1640 if(pOS2) {
1641 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1642 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1643 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1644 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1645 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1646 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1647 if(pOS2->version == 0) {
1648 FT_UInt dummy;
1650 if(pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1651 fs.fsCsb[0] |= FS_LATIN1;
1652 else
1653 fs.fsCsb[0] |= FS_SYMBOL;
1656 else if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1657 CHARSETINFO csi;
1658 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1659 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1660 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1661 fs = csi.fs;
1662 internal_leading = winfnt_header.internal_leading;
1665 face_elem_ptr = list_head(&family->faces);
1666 while(face_elem_ptr) {
1667 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1668 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1669 if(!strcmpiW(face->StyleName, StyleW) &&
1670 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1671 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1672 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1673 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1675 if(fake_family) {
1676 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1677 HeapFree(GetProcessHeap(), 0, StyleW);
1678 pFT_Done_Face(ft_face);
1679 return 1;
1681 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1682 TRACE("Original font is newer so skipping this one\n");
1683 HeapFree(GetProcessHeap(), 0, StyleW);
1684 pFT_Done_Face(ft_face);
1685 return 1;
1686 } else {
1687 TRACE("Replacing original with this one\n");
1688 list_remove(&face->entry);
1689 HeapFree(GetProcessHeap(), 0, face->file);
1690 HeapFree(GetProcessHeap(), 0, face->StyleName);
1691 HeapFree(GetProcessHeap(), 0, face->FullName);
1692 HeapFree(GetProcessHeap(), 0, face);
1693 break;
1697 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1698 face->cached_enum_data = NULL;
1699 face->StyleName = StyleW;
1700 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1701 if (file)
1703 face->file = strdupA(file);
1704 face->font_data_ptr = NULL;
1705 face->font_data_size = 0;
1707 else
1709 face->file = NULL;
1710 face->font_data_ptr = font_data_ptr;
1711 face->font_data_size = font_data_size;
1713 face->face_index = face_index;
1714 face->ntmFlags = 0;
1715 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1716 face->ntmFlags |= NTM_ITALIC;
1717 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1718 face->ntmFlags |= NTM_BOLD;
1719 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1720 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1721 face->family = family;
1722 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1723 face->fs = fs;
1724 memset(&face->fs_links, 0, sizeof(face->fs_links));
1726 if(FT_IS_SCALABLE(ft_face)) {
1727 memset(&face->size, 0, sizeof(face->size));
1728 face->scalable = TRUE;
1729 } else {
1730 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1731 size->height, size->width, size->size >> 6,
1732 size->x_ppem >> 6, size->y_ppem >> 6);
1733 face->size.height = size->height;
1734 face->size.width = size->width;
1735 face->size.size = size->size;
1736 face->size.x_ppem = size->x_ppem;
1737 face->size.y_ppem = size->y_ppem;
1738 face->size.internal_leading = internal_leading;
1739 face->scalable = FALSE;
1742 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1743 tmp_size = 0;
1744 if (!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1746 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1747 face->ntmFlags |= NTM_PS_OPENTYPE;
1750 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1751 face->fs.fsCsb[0], face->fs.fsCsb[1],
1752 face->fs.fsUsb[0], face->fs.fsUsb[1],
1753 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1756 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1757 for(i = 0; i < ft_face->num_charmaps; i++) {
1758 switch(ft_face->charmaps[i]->encoding) {
1759 case FT_ENCODING_UNICODE:
1760 case FT_ENCODING_APPLE_ROMAN:
1761 face->fs.fsCsb[0] |= FS_LATIN1;
1762 break;
1763 case FT_ENCODING_MS_SYMBOL:
1764 face->fs.fsCsb[0] |= FS_SYMBOL;
1765 break;
1766 default:
1767 break;
1772 if(flags & ADDFONT_ADD_TO_CACHE)
1773 add_face_to_cache(face);
1775 AddFaceToFamily(face, family);
1777 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1779 num_faces = ft_face->num_faces;
1780 pFT_Done_Face(ft_face);
1781 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1782 debugstr_w(StyleW));
1783 } while(num_faces > ++face_index);
1784 return num_faces;
1787 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1789 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1792 static void DumpFontList(void)
1794 Family *family;
1795 Face *face;
1796 struct list *family_elem_ptr, *face_elem_ptr;
1798 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1799 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1800 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1801 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1802 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1803 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1804 if(!face->scalable)
1805 TRACE(" %d", face->size.height);
1806 TRACE("\n");
1809 return;
1812 /***********************************************************
1813 * The replacement list is a way to map an entire font
1814 * family onto another family. For example adding
1816 * [HKCU\Software\Wine\Fonts\Replacements]
1817 * "Wingdings"="Winedings"
1819 * would enumerate the Winedings font both as Winedings and
1820 * Wingdings. However if a real Wingdings font is present the
1821 * replacement does not take place.
1824 static void LoadReplaceList(void)
1826 HKEY hkey;
1827 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1828 LPWSTR value;
1829 LPVOID data;
1830 Family *family;
1831 Face *face;
1832 struct list *family_elem_ptr, *face_elem_ptr;
1833 CHAR familyA[400];
1835 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1836 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1838 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1839 &valuelen, &datalen, NULL, NULL);
1841 valuelen++; /* returned value doesn't include room for '\0' */
1842 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1843 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1845 dlen = datalen;
1846 vlen = valuelen;
1847 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1848 &dlen) == ERROR_SUCCESS) {
1849 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1850 /* "NewName"="Oldname" */
1851 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1853 if(!find_family_from_name(value))
1855 /* Find the old family and hence all of the font files
1856 in that family */
1857 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1858 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1859 if(!strcmpiW(family->FamilyName, data)) {
1860 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1861 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1862 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1863 debugstr_w(face->StyleName), familyA);
1864 /* Now add a new entry with the new family name */
1865 AddFontToList(face->file, face->font_data_ptr, face->font_data_size,
1866 familyA, family->FamilyName,
1867 ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1869 break;
1873 /* reset dlen and vlen */
1874 dlen = datalen;
1875 vlen = valuelen;
1877 HeapFree(GetProcessHeap(), 0, data);
1878 HeapFree(GetProcessHeap(), 0, value);
1879 RegCloseKey(hkey);
1883 /*************************************************************
1884 * init_system_links
1886 static BOOL init_system_links(void)
1888 HKEY hkey;
1889 BOOL ret = FALSE;
1890 DWORD type, max_val, max_data, val_len, data_len, index;
1891 WCHAR *value, *data;
1892 WCHAR *entry, *next;
1893 SYSTEM_LINKS *font_link, *system_font_link;
1894 CHILD_FONT *child_font;
1895 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1896 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1897 FONTSIGNATURE fs;
1898 Family *family;
1899 Face *face;
1900 FontSubst *psub;
1902 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1904 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1905 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1906 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1907 val_len = max_val + 1;
1908 data_len = max_data;
1909 index = 0;
1910 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1912 memset(&fs, 0, sizeof(fs));
1913 psub = get_font_subst(&font_subst_list, value, -1);
1914 /* Don't store fonts that are only substitutes for other fonts */
1915 if(psub)
1917 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1918 goto next;
1920 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1921 font_link->font_name = strdupW(value);
1922 list_init(&font_link->links);
1923 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1925 WCHAR *face_name;
1926 CHILD_FONT *child_font;
1928 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1930 next = entry + strlenW(entry) + 1;
1932 face_name = strchrW(entry, ',');
1933 if(face_name)
1935 *face_name++ = 0;
1936 while(isspaceW(*face_name))
1937 face_name++;
1939 psub = get_font_subst(&font_subst_list, face_name, -1);
1940 if(psub)
1941 face_name = psub->to.name;
1943 face = find_face_from_filename(entry, face_name);
1944 if(!face)
1946 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1947 continue;
1950 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1951 child_font->face = face;
1952 child_font->font = NULL;
1953 fs.fsCsb[0] |= face->fs.fsCsb[0];
1954 fs.fsCsb[1] |= face->fs.fsCsb[1];
1955 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1956 list_add_tail(&font_link->links, &child_font->entry);
1958 family = find_family_from_name(font_link->font_name);
1959 if(family)
1961 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1963 face->fs_links = fs;
1966 list_add_tail(&system_links, &font_link->entry);
1967 next:
1968 val_len = max_val + 1;
1969 data_len = max_data;
1972 HeapFree(GetProcessHeap(), 0, value);
1973 HeapFree(GetProcessHeap(), 0, data);
1974 RegCloseKey(hkey);
1977 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1978 that Tahoma has */
1980 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1981 system_font_link->font_name = strdupW(System);
1982 list_init(&system_font_link->links);
1984 face = find_face_from_filename(tahoma_ttf, Tahoma);
1985 if(face)
1987 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1988 child_font->face = face;
1989 child_font->font = NULL;
1990 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1991 list_add_tail(&system_font_link->links, &child_font->entry);
1993 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1995 if(!strcmpiW(font_link->font_name, Tahoma))
1997 CHILD_FONT *font_link_entry;
1998 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2000 CHILD_FONT *new_child;
2001 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2002 new_child->face = font_link_entry->face;
2003 new_child->font = NULL;
2004 list_add_tail(&system_font_link->links, &new_child->entry);
2006 break;
2009 list_add_tail(&system_links, &system_font_link->entry);
2010 return ret;
2013 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2015 DIR *dir;
2016 struct dirent *dent;
2017 char path[MAX_PATH];
2019 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2021 dir = opendir(dirname);
2022 if(!dir) {
2023 WARN("Can't open directory %s\n", debugstr_a(dirname));
2024 return FALSE;
2026 while((dent = readdir(dir)) != NULL) {
2027 struct stat statbuf;
2029 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2030 continue;
2032 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2034 sprintf(path, "%s/%s", dirname, dent->d_name);
2036 if(stat(path, &statbuf) == -1)
2038 WARN("Can't stat %s\n", debugstr_a(path));
2039 continue;
2041 if(S_ISDIR(statbuf.st_mode))
2042 ReadFontDir(path, external_fonts);
2043 else
2045 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2046 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2047 AddFontFileToList(path, NULL, NULL, addfont_flags);
2050 closedir(dir);
2051 return TRUE;
2054 static void load_fontconfig_fonts(void)
2056 #ifdef SONAME_LIBFONTCONFIG
2057 void *fc_handle = NULL;
2058 FcConfig *config;
2059 FcPattern *pat;
2060 FcObjectSet *os;
2061 FcFontSet *fontset;
2062 int i, len;
2063 char *file;
2064 const char *ext;
2066 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2067 if(!fc_handle) {
2068 TRACE("Wine cannot find the fontconfig library (%s).\n",
2069 SONAME_LIBFONTCONFIG);
2070 return;
2072 #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;}
2073 LOAD_FUNCPTR(FcConfigGetCurrent);
2074 LOAD_FUNCPTR(FcFontList);
2075 LOAD_FUNCPTR(FcFontSetDestroy);
2076 LOAD_FUNCPTR(FcInit);
2077 LOAD_FUNCPTR(FcObjectSetAdd);
2078 LOAD_FUNCPTR(FcObjectSetCreate);
2079 LOAD_FUNCPTR(FcObjectSetDestroy);
2080 LOAD_FUNCPTR(FcPatternCreate);
2081 LOAD_FUNCPTR(FcPatternDestroy);
2082 LOAD_FUNCPTR(FcPatternGetBool);
2083 LOAD_FUNCPTR(FcPatternGetString);
2084 #undef LOAD_FUNCPTR
2086 if(!pFcInit()) return;
2088 config = pFcConfigGetCurrent();
2089 pat = pFcPatternCreate();
2090 os = pFcObjectSetCreate();
2091 pFcObjectSetAdd(os, FC_FILE);
2092 pFcObjectSetAdd(os, FC_SCALABLE);
2093 fontset = pFcFontList(config, pat, os);
2094 if(!fontset) return;
2095 for(i = 0; i < fontset->nfont; i++) {
2096 FcBool scalable;
2098 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2099 continue;
2100 TRACE("fontconfig: %s\n", file);
2102 /* We're just interested in OT/TT fonts for now, so this hack just
2103 picks up the scalable fonts without extensions .pf[ab] to save time
2104 loading every other font */
2106 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2108 TRACE("not scalable\n");
2109 continue;
2112 len = strlen( file );
2113 if(len < 4) continue;
2114 ext = &file[ len - 3 ];
2115 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2116 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2118 pFcFontSetDestroy(fontset);
2119 pFcObjectSetDestroy(os);
2120 pFcPatternDestroy(pat);
2121 sym_not_found:
2122 #endif
2123 return;
2126 static BOOL load_font_from_data_dir(LPCWSTR file)
2128 BOOL ret = FALSE;
2129 const char *data_dir = wine_get_data_dir();
2131 if (!data_dir) data_dir = wine_get_build_dir();
2133 if (data_dir)
2135 INT len;
2136 char *unix_name;
2138 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2140 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2142 strcpy(unix_name, data_dir);
2143 strcat(unix_name, "/fonts/");
2145 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2147 EnterCriticalSection( &freetype_cs );
2148 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2149 LeaveCriticalSection( &freetype_cs );
2150 HeapFree(GetProcessHeap(), 0, unix_name);
2152 return ret;
2155 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2157 static const WCHAR slashW[] = {'\\','\0'};
2158 BOOL ret = FALSE;
2159 WCHAR windowsdir[MAX_PATH];
2160 char *unixname;
2162 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2163 strcatW(windowsdir, fontsW);
2164 strcatW(windowsdir, slashW);
2165 strcatW(windowsdir, file);
2166 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2167 EnterCriticalSection( &freetype_cs );
2168 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2169 LeaveCriticalSection( &freetype_cs );
2170 HeapFree(GetProcessHeap(), 0, unixname);
2172 return ret;
2175 static void load_system_fonts(void)
2177 HKEY hkey;
2178 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2179 const WCHAR * const *value;
2180 DWORD dlen, type;
2181 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2182 char *unixname;
2184 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2185 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2186 strcatW(windowsdir, fontsW);
2187 for(value = SystemFontValues; *value; value++) {
2188 dlen = sizeof(data);
2189 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2190 type == REG_SZ) {
2191 BOOL added = FALSE;
2193 sprintfW(pathW, fmtW, windowsdir, data);
2194 if((unixname = wine_get_unix_file_name(pathW))) {
2195 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2196 HeapFree(GetProcessHeap(), 0, unixname);
2198 if (!added)
2199 load_font_from_data_dir(data);
2202 RegCloseKey(hkey);
2206 /*************************************************************
2208 * This adds registry entries for any externally loaded fonts
2209 * (fonts from fontconfig or FontDirs). It also deletes entries
2210 * of no longer existing fonts.
2213 static void update_reg_entries(void)
2215 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2216 LPWSTR valueW;
2217 DWORD len, len_fam;
2218 Family *family;
2219 Face *face;
2220 struct list *family_elem_ptr, *face_elem_ptr;
2221 WCHAR *file;
2222 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2223 static const WCHAR spaceW[] = {' ', '\0'};
2224 char *path;
2226 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2227 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2228 ERR("Can't create Windows font reg key\n");
2229 goto end;
2232 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2233 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2234 ERR("Can't create Windows font reg key\n");
2235 goto end;
2238 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2239 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2240 ERR("Can't create external font reg key\n");
2241 goto end;
2244 /* enumerate the fonts and add external ones to the two keys */
2246 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2247 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2248 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2249 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2250 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2251 if(!face->external) continue;
2252 len = len_fam;
2253 if (!(face->ntmFlags & NTM_REGULAR))
2254 len = len_fam + strlenW(face->StyleName) + 1;
2255 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2256 strcpyW(valueW, family->FamilyName);
2257 if(len != len_fam) {
2258 strcatW(valueW, spaceW);
2259 strcatW(valueW, face->StyleName);
2261 strcatW(valueW, TrueType);
2263 file = wine_get_dos_file_name(face->file);
2264 if(file)
2265 len = strlenW(file) + 1;
2266 else
2268 if((path = strrchr(face->file, '/')) == NULL)
2269 path = face->file;
2270 else
2271 path++;
2272 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2274 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2275 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2277 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2278 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2279 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2281 HeapFree(GetProcessHeap(), 0, file);
2282 HeapFree(GetProcessHeap(), 0, valueW);
2285 end:
2286 if(external_key) RegCloseKey(external_key);
2287 if(win9x_key) RegCloseKey(win9x_key);
2288 if(winnt_key) RegCloseKey(winnt_key);
2289 return;
2292 static void delete_external_font_keys(void)
2294 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2295 DWORD dlen, vlen, datalen, valuelen, i, type;
2296 LPWSTR valueW;
2297 LPVOID data;
2299 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2300 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2301 ERR("Can't create Windows font reg key\n");
2302 goto end;
2305 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2306 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2307 ERR("Can't create Windows font reg key\n");
2308 goto end;
2311 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2312 ERR("Can't create external font reg key\n");
2313 goto end;
2316 /* Delete all external fonts added last time */
2318 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2319 &valuelen, &datalen, NULL, NULL);
2320 valuelen++; /* returned value doesn't include room for '\0' */
2321 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2322 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2324 dlen = datalen * sizeof(WCHAR);
2325 vlen = valuelen;
2326 i = 0;
2327 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2328 &dlen) == ERROR_SUCCESS) {
2330 RegDeleteValueW(winnt_key, valueW);
2331 RegDeleteValueW(win9x_key, valueW);
2332 /* reset dlen and vlen */
2333 dlen = datalen;
2334 vlen = valuelen;
2336 HeapFree(GetProcessHeap(), 0, data);
2337 HeapFree(GetProcessHeap(), 0, valueW);
2339 /* Delete the old external fonts key */
2340 RegCloseKey(external_key);
2341 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2343 end:
2344 if(win9x_key) RegCloseKey(win9x_key);
2345 if(winnt_key) RegCloseKey(winnt_key);
2348 /*************************************************************
2349 * WineEngAddFontResourceEx
2352 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2354 INT ret = 0;
2356 GDI_CheckNotLock();
2358 if (ft_handle) /* do it only if we have freetype up and running */
2360 char *unixname;
2362 if(flags)
2363 FIXME("Ignoring flags %x\n", flags);
2365 if((unixname = wine_get_unix_file_name(file)))
2367 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2369 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2370 EnterCriticalSection( &freetype_cs );
2371 ret = AddFontFileToList(unixname, NULL, NULL, addfont_flags);
2372 LeaveCriticalSection( &freetype_cs );
2373 HeapFree(GetProcessHeap(), 0, unixname);
2375 if (!ret && !strchrW(file, '\\')) {
2376 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2377 ret = load_font_from_winfonts_dir(file);
2378 if (!ret) {
2379 /* Try in datadir/fonts (or builddir/fonts),
2380 * needed for Magic the Gathering Online
2382 ret = load_font_from_data_dir(file);
2386 return ret;
2389 /*************************************************************
2390 * WineEngAddFontMemResourceEx
2393 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2395 GDI_CheckNotLock();
2397 if (ft_handle) /* do it only if we have freetype up and running */
2399 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2401 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2402 memcpy(pFontCopy, pbFont, cbFont);
2404 EnterCriticalSection( &freetype_cs );
2405 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2406 LeaveCriticalSection( &freetype_cs );
2408 if (*pcFonts == 0)
2410 TRACE("AddFontToList failed\n");
2411 HeapFree(GetProcessHeap(), 0, pFontCopy);
2412 return 0;
2414 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2415 * For now return something unique but quite random
2417 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2418 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2421 *pcFonts = 0;
2422 return 0;
2425 /*************************************************************
2426 * WineEngRemoveFontResourceEx
2429 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2431 GDI_CheckNotLock();
2432 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2433 return TRUE;
2436 static const struct nls_update_font_list
2438 UINT ansi_cp, oem_cp;
2439 const char *oem, *fixed, *system;
2440 const char *courier, *serif, *small, *sserif;
2441 /* these are for font substitutes */
2442 const char *shelldlg, *tmsrmn;
2443 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2444 *helv_0, *tmsrmn_0;
2445 const struct subst
2447 const char *from, *to;
2448 } arial_0, courier_new_0, times_new_roman_0;
2449 } nls_update_font_list[] =
2451 /* Latin 1 (United States) */
2452 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2453 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2454 "Tahoma","Times New Roman",
2455 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2456 { 0 }, { 0 }, { 0 }
2458 /* Latin 1 (Multilingual) */
2459 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2460 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2461 "Tahoma","Times New Roman", /* FIXME unverified */
2462 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2463 { 0 }, { 0 }, { 0 }
2465 /* Eastern Europe */
2466 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2467 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2468 "Tahoma","Times New Roman", /* FIXME unverified */
2469 "Fixedsys,238", "System,238",
2470 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2471 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2472 { "Arial CE,0", "Arial,238" },
2473 { "Courier New CE,0", "Courier New,238" },
2474 { "Times New Roman CE,0", "Times New Roman,238" }
2476 /* Cyrillic */
2477 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2478 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2479 "Tahoma","Times New Roman", /* FIXME unverified */
2480 "Fixedsys,204", "System,204",
2481 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2482 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2483 { "Arial Cyr,0", "Arial,204" },
2484 { "Courier New Cyr,0", "Courier New,204" },
2485 { "Times New Roman Cyr,0", "Times New Roman,204" }
2487 /* Greek */
2488 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2489 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2490 "Tahoma","Times New Roman", /* FIXME unverified */
2491 "Fixedsys,161", "System,161",
2492 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2493 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2494 { "Arial Greek,0", "Arial,161" },
2495 { "Courier New Greek,0", "Courier New,161" },
2496 { "Times New Roman Greek,0", "Times New Roman,161" }
2498 /* Turkish */
2499 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2500 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2501 "Tahoma","Times New Roman", /* FIXME unverified */
2502 "Fixedsys,162", "System,162",
2503 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2504 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2505 { "Arial Tur,0", "Arial,162" },
2506 { "Courier New Tur,0", "Courier New,162" },
2507 { "Times New Roman Tur,0", "Times New Roman,162" }
2509 /* Hebrew */
2510 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2511 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2512 "Tahoma","Times New Roman", /* FIXME unverified */
2513 "Fixedsys,177", "System,177",
2514 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2515 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2516 { 0 }, { 0 }, { 0 }
2518 /* Arabic */
2519 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2520 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2521 "Tahoma","Times New Roman", /* FIXME unverified */
2522 "Fixedsys,178", "System,178",
2523 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2524 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2525 { 0 }, { 0 }, { 0 }
2527 /* Baltic */
2528 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2529 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2530 "Tahoma","Times New Roman", /* FIXME unverified */
2531 "Fixedsys,186", "System,186",
2532 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2533 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2534 { "Arial Baltic,0", "Arial,186" },
2535 { "Courier New Baltic,0", "Courier New,186" },
2536 { "Times New Roman Baltic,0", "Times New Roman,186" }
2538 /* Vietnamese */
2539 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2540 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2541 "Tahoma","Times New Roman", /* FIXME unverified */
2542 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2543 { 0 }, { 0 }, { 0 }
2545 /* Thai */
2546 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2547 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2548 "Tahoma","Times New Roman", /* FIXME unverified */
2549 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2550 { 0 }, { 0 }, { 0 }
2552 /* Japanese */
2553 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2554 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2555 "MS UI Gothic","MS Serif",
2556 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2557 { 0 }, { 0 }, { 0 }
2559 /* Chinese Simplified */
2560 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2561 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2562 "SimSun", "NSimSun",
2563 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2564 { 0 }, { 0 }, { 0 }
2566 /* Korean */
2567 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2568 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2569 "Gulim", "Batang",
2570 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2571 { 0 }, { 0 }, { 0 }
2573 /* Chinese Traditional */
2574 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2575 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2576 "PMingLiU", "MingLiU",
2577 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2578 { 0 }, { 0 }, { 0 }
2582 static const WCHAR *font_links_list[] =
2584 Lucida_Sans_Unicode,
2585 Microsoft_Sans_Serif,
2586 Tahoma
2589 static const struct font_links_defaults_list
2591 /* Keyed off substitution for "MS Shell Dlg" */
2592 const WCHAR *shelldlg;
2593 /* Maximum of four substitutes, plus terminating NULL pointer */
2594 const WCHAR *substitutes[5];
2595 } font_links_defaults_list[] =
2597 /* Non East-Asian */
2598 { Tahoma, /* FIXME unverified ordering */
2599 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2601 /* Below lists are courtesy of
2602 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2604 /* Japanese */
2605 { MS_UI_Gothic,
2606 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2608 /* Chinese Simplified */
2609 { SimSun,
2610 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2612 /* Korean */
2613 { Gulim,
2614 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2616 /* Chinese Traditional */
2617 { PMingLiU,
2618 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2622 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2624 return ( ansi_cp == 932 /* CP932 for Japanese */
2625 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2626 || ansi_cp == 949 /* CP949 for Korean */
2627 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2630 static inline HKEY create_fonts_NT_registry_key(void)
2632 HKEY hkey = 0;
2634 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2635 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2636 return hkey;
2639 static inline HKEY create_fonts_9x_registry_key(void)
2641 HKEY hkey = 0;
2643 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2644 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2645 return hkey;
2648 static inline HKEY create_config_fonts_registry_key(void)
2650 HKEY hkey = 0;
2652 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2653 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2654 return hkey;
2657 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2659 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2660 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2661 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2662 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2665 static void set_value_key(HKEY hkey, const char *name, const char *value)
2667 if (value)
2668 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2669 else if (name)
2670 RegDeleteValueA(hkey, name);
2673 static void update_font_info(void)
2675 char buf[40], cpbuf[40];
2676 DWORD len, type;
2677 HKEY hkey = 0;
2678 UINT i, ansi_cp = 0, oem_cp = 0;
2679 BOOL done = FALSE;
2681 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2682 return;
2684 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2685 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2686 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2687 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2688 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2690 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2691 if (is_dbcs_ansi_cp(ansi_cp))
2692 use_default_fallback = TRUE;
2694 len = sizeof(buf);
2695 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2697 if (!strcmp( buf, cpbuf )) /* already set correctly */
2699 RegCloseKey(hkey);
2700 return;
2702 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2704 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2706 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2707 RegCloseKey(hkey);
2709 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2711 HKEY hkey;
2713 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2714 nls_update_font_list[i].oem_cp == oem_cp)
2716 hkey = create_config_fonts_registry_key();
2717 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2718 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2719 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2720 RegCloseKey(hkey);
2722 hkey = create_fonts_NT_registry_key();
2723 add_font_list(hkey, &nls_update_font_list[i]);
2724 RegCloseKey(hkey);
2726 hkey = create_fonts_9x_registry_key();
2727 add_font_list(hkey, &nls_update_font_list[i]);
2728 RegCloseKey(hkey);
2730 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2732 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2733 strlen(nls_update_font_list[i].shelldlg)+1);
2734 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2735 strlen(nls_update_font_list[i].tmsrmn)+1);
2737 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2738 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2739 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2740 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2741 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2742 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2743 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2744 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2746 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2747 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2748 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2750 RegCloseKey(hkey);
2752 done = TRUE;
2754 else
2756 /* Delete the FontSubstitutes from other locales */
2757 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2759 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2760 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2761 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2762 RegCloseKey(hkey);
2766 if (!done)
2767 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2769 /* Clear out system links */
2770 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2773 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2775 const WCHAR *value;
2776 int i;
2777 FontSubst *psub;
2778 Family *family;
2779 Face *face;
2780 const char *file;
2781 WCHAR *fileW;
2782 int fileLen;
2783 WCHAR buff[MAX_PATH];
2784 WCHAR *data;
2785 int entryLen;
2787 static const WCHAR comma[] = {',',0};
2789 RegDeleteValueW(hkey, name);
2790 if (values)
2792 data = buff;
2793 data[0] = '\0';
2794 for (i = 0; values[i] != NULL; i++)
2796 value = values[i];
2797 if (!strcmpiW(name,value))
2798 continue;
2799 psub = get_font_subst(&font_subst_list, value, -1);
2800 if(psub)
2801 value = psub->to.name;
2802 family = find_family_from_name(value);
2803 if (!family)
2804 continue;
2805 file = NULL;
2806 /* Use first extant filename for this Family */
2807 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2809 if (!face->file)
2810 continue;
2811 file = strrchr(face->file, '/');
2812 if (!file)
2813 file = face->file;
2814 else
2815 file++;
2816 break;
2818 if (!file)
2819 continue;
2820 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2821 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2822 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2823 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2824 if (sizeof(buff)-(data-buff) < entryLen + 1)
2826 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2827 HeapFree(GetProcessHeap(), 0, fileW);
2828 break;
2830 strcpyW(data, fileW);
2831 strcatW(data, comma);
2832 strcatW(data, value);
2833 data += entryLen;
2834 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2835 HeapFree(GetProcessHeap(), 0, fileW);
2837 if (data != buff)
2839 *data='\0';
2840 data++;
2841 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2842 } else
2843 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2844 } else
2845 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2848 static void update_system_links(void)
2850 HKEY hkey = 0;
2851 UINT i, j;
2852 BOOL done = FALSE;
2853 DWORD disposition;
2854 FontSubst *psub;
2856 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2858 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2860 if (disposition == REG_OPENED_EXISTING_KEY)
2862 TRACE("SystemLink key already exists, doing nothing\n");
2863 RegCloseKey(hkey);
2864 return;
2867 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2868 if (!psub) {
2869 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2870 RegCloseKey(hkey);
2871 return;
2874 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2876 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2878 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2879 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2881 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2882 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2883 done = TRUE;
2885 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2887 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2890 RegCloseKey(hkey);
2891 if (!done)
2892 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2893 } else
2894 WARN("failed to create SystemLink key\n");
2898 static BOOL init_freetype(void)
2900 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2901 if(!ft_handle) {
2902 WINE_MESSAGE(
2903 "Wine cannot find the FreeType font library. To enable Wine to\n"
2904 "use TrueType fonts please install a version of FreeType greater than\n"
2905 "or equal to 2.0.5.\n"
2906 "http://www.freetype.org\n");
2907 return FALSE;
2910 #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;}
2912 LOAD_FUNCPTR(FT_Done_Face)
2913 LOAD_FUNCPTR(FT_Get_Char_Index)
2914 LOAD_FUNCPTR(FT_Get_First_Char)
2915 LOAD_FUNCPTR(FT_Get_Module)
2916 LOAD_FUNCPTR(FT_Get_Next_Char)
2917 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2918 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2919 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2920 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
2921 LOAD_FUNCPTR(FT_Init_FreeType)
2922 LOAD_FUNCPTR(FT_Library_Version)
2923 LOAD_FUNCPTR(FT_Load_Glyph)
2924 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
2925 LOAD_FUNCPTR(FT_Matrix_Multiply)
2926 #ifndef FT_MULFIX_INLINED
2927 LOAD_FUNCPTR(FT_MulFix)
2928 #endif
2929 LOAD_FUNCPTR(FT_New_Face)
2930 LOAD_FUNCPTR(FT_New_Memory_Face)
2931 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2932 LOAD_FUNCPTR(FT_Outline_Transform)
2933 LOAD_FUNCPTR(FT_Outline_Translate)
2934 LOAD_FUNCPTR(FT_Render_Glyph)
2935 LOAD_FUNCPTR(FT_Select_Charmap)
2936 LOAD_FUNCPTR(FT_Set_Charmap)
2937 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2938 LOAD_FUNCPTR(FT_Vector_Transform)
2939 LOAD_FUNCPTR(FT_Vector_Unit)
2940 #undef LOAD_FUNCPTR
2941 /* Don't warn if these ones are missing */
2942 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2943 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2944 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2945 #endif
2947 if(pFT_Init_FreeType(&library) != 0) {
2948 ERR("Can't init FreeType library\n");
2949 wine_dlclose(ft_handle, NULL, 0);
2950 ft_handle = NULL;
2951 return FALSE;
2953 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2955 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2956 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2957 ((FT_Version.minor << 8) & 0x00ff00) |
2958 ((FT_Version.patch ) & 0x0000ff);
2960 font_driver = &freetype_funcs;
2961 return TRUE;
2963 sym_not_found:
2964 WINE_MESSAGE(
2965 "Wine cannot find certain functions that it needs inside the FreeType\n"
2966 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2967 "FreeType to at least version 2.1.4.\n"
2968 "http://www.freetype.org\n");
2969 wine_dlclose(ft_handle, NULL, 0);
2970 ft_handle = NULL;
2971 return FALSE;
2974 static void init_font_list(void)
2976 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2977 static const WCHAR pathW[] = {'P','a','t','h',0};
2978 HKEY hkey;
2979 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2980 WCHAR windowsdir[MAX_PATH];
2981 char *unixname;
2982 const char *data_dir;
2984 delete_external_font_keys();
2986 /* load the system bitmap fonts */
2987 load_system_fonts();
2989 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2990 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2991 strcatW(windowsdir, fontsW);
2992 if((unixname = wine_get_unix_file_name(windowsdir)))
2994 ReadFontDir(unixname, FALSE);
2995 HeapFree(GetProcessHeap(), 0, unixname);
2998 /* load the system truetype fonts */
2999 data_dir = wine_get_data_dir();
3000 if (!data_dir) data_dir = wine_get_build_dir();
3001 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3003 strcpy(unixname, data_dir);
3004 strcat(unixname, "/fonts/");
3005 ReadFontDir(unixname, TRUE);
3006 HeapFree(GetProcessHeap(), 0, unixname);
3009 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3010 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3011 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3012 will skip these. */
3013 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3014 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3015 &hkey) == ERROR_SUCCESS)
3017 LPWSTR data, valueW;
3018 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3019 &valuelen, &datalen, NULL, NULL);
3021 valuelen++; /* returned value doesn't include room for '\0' */
3022 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3023 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3024 if (valueW && data)
3026 dlen = datalen * sizeof(WCHAR);
3027 vlen = valuelen;
3028 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3029 &dlen) == ERROR_SUCCESS)
3031 if(data[0] && (data[1] == ':'))
3033 if((unixname = wine_get_unix_file_name(data)))
3035 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3036 HeapFree(GetProcessHeap(), 0, unixname);
3039 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3041 WCHAR pathW[MAX_PATH];
3042 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3043 BOOL added = FALSE;
3045 sprintfW(pathW, fmtW, windowsdir, data);
3046 if((unixname = wine_get_unix_file_name(pathW)))
3048 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3049 HeapFree(GetProcessHeap(), 0, unixname);
3051 if (!added)
3052 load_font_from_data_dir(data);
3054 /* reset dlen and vlen */
3055 dlen = datalen;
3056 vlen = valuelen;
3059 HeapFree(GetProcessHeap(), 0, data);
3060 HeapFree(GetProcessHeap(), 0, valueW);
3061 RegCloseKey(hkey);
3064 load_fontconfig_fonts();
3066 /* then look in any directories that we've specified in the config file */
3067 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3068 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3070 DWORD len;
3071 LPWSTR valueW;
3072 LPSTR valueA, ptr;
3074 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3076 len += sizeof(WCHAR);
3077 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3078 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3080 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3081 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3082 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3083 TRACE( "got font path %s\n", debugstr_a(valueA) );
3084 ptr = valueA;
3085 while (ptr)
3087 const char* home;
3088 LPSTR next = strchr( ptr, ':' );
3089 if (next) *next++ = 0;
3090 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3091 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3093 strcpy( unixname, home );
3094 strcat( unixname, ptr + 1 );
3095 ReadFontDir( unixname, TRUE );
3096 HeapFree( GetProcessHeap(), 0, unixname );
3098 else
3099 ReadFontDir( ptr, TRUE );
3100 ptr = next;
3102 HeapFree( GetProcessHeap(), 0, valueA );
3104 HeapFree( GetProcessHeap(), 0, valueW );
3106 RegCloseKey(hkey);
3110 static BOOL move_to_front(const WCHAR *name)
3112 Family *family, *cursor2;
3113 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3115 if(!strcmpiW(family->FamilyName, name))
3117 list_remove(&family->entry);
3118 list_add_head(&font_list, &family->entry);
3119 return TRUE;
3122 return FALSE;
3125 static BOOL set_default(const WCHAR **name_list)
3127 while (*name_list)
3129 if (move_to_front(*name_list)) return TRUE;
3130 name_list++;
3133 return FALSE;
3136 static void reorder_font_list(void)
3138 set_default( default_serif_list );
3139 set_default( default_fixed_list );
3140 set_default( default_sans_list );
3143 /*************************************************************
3144 * WineEngInit
3146 * Initialize FreeType library and create a list of available faces
3148 BOOL WineEngInit(void)
3150 HKEY hkey_font_cache;
3151 DWORD disposition;
3152 HANDLE font_mutex;
3154 /* update locale dependent font info in registry */
3155 update_font_info();
3157 if(!init_freetype()) return FALSE;
3159 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3161 ERR("Failed to create font mutex\n");
3162 return FALSE;
3164 WaitForSingleObject(font_mutex, INFINITE);
3166 create_font_cache_key(&hkey_font_cache, &disposition);
3168 if(disposition == REG_CREATED_NEW_KEY)
3169 init_font_list();
3170 else
3171 load_font_list_from_cache(hkey_font_cache);
3173 RegCloseKey(hkey_font_cache);
3175 reorder_font_list();
3177 DumpFontList();
3178 LoadSubstList();
3179 DumpSubstList();
3180 LoadReplaceList();
3182 if(disposition == REG_CREATED_NEW_KEY)
3183 update_reg_entries();
3185 update_system_links();
3186 init_system_links();
3188 ReleaseMutex(font_mutex);
3189 return TRUE;
3193 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3195 TT_OS2 *pOS2;
3196 TT_HoriHeader *pHori;
3198 LONG ppem;
3200 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3201 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3203 if(height == 0) height = 16;
3205 /* Calc. height of EM square:
3207 * For +ve lfHeight we have
3208 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3209 * Re-arranging gives:
3210 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3212 * For -ve lfHeight we have
3213 * |lfHeight| = ppem
3214 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3215 * with il = winAscent + winDescent - units_per_em]
3219 if(height > 0) {
3220 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3221 ppem = MulDiv(ft_face->units_per_EM, height,
3222 pHori->Ascender - pHori->Descender);
3223 else
3224 ppem = MulDiv(ft_face->units_per_EM, height,
3225 pOS2->usWinAscent + pOS2->usWinDescent);
3227 else
3228 ppem = -height;
3230 return ppem;
3233 static struct font_mapping *map_font_file( const char *name )
3235 struct font_mapping *mapping;
3236 struct stat st;
3237 int fd;
3239 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3240 if (fstat( fd, &st ) == -1) goto error;
3242 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3244 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3246 mapping->refcount++;
3247 close( fd );
3248 return mapping;
3251 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3252 goto error;
3254 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3255 close( fd );
3257 if (mapping->data == MAP_FAILED)
3259 HeapFree( GetProcessHeap(), 0, mapping );
3260 return NULL;
3262 mapping->refcount = 1;
3263 mapping->dev = st.st_dev;
3264 mapping->ino = st.st_ino;
3265 mapping->size = st.st_size;
3266 list_add_tail( &mappings_list, &mapping->entry );
3267 return mapping;
3269 error:
3270 close( fd );
3271 return NULL;
3274 static void unmap_font_file( struct font_mapping *mapping )
3276 if (!--mapping->refcount)
3278 list_remove( &mapping->entry );
3279 munmap( mapping->data, mapping->size );
3280 HeapFree( GetProcessHeap(), 0, mapping );
3284 static LONG load_VDMX(GdiFont*, LONG);
3286 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3288 FT_Error err;
3289 FT_Face ft_face;
3290 void *data_ptr;
3291 DWORD data_size;
3293 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3295 if (face->file)
3297 if (!(font->mapping = map_font_file( face->file )))
3299 WARN("failed to map %s\n", debugstr_a(face->file));
3300 return 0;
3302 data_ptr = font->mapping->data;
3303 data_size = font->mapping->size;
3305 else
3307 data_ptr = face->font_data_ptr;
3308 data_size = face->font_data_size;
3311 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3312 if(err) {
3313 ERR("FT_New_Face rets %d\n", err);
3314 return 0;
3317 /* set it here, as load_VDMX needs it */
3318 font->ft_face = ft_face;
3320 if(FT_IS_SCALABLE(ft_face)) {
3321 /* load the VDMX table if we have one */
3322 font->ppem = load_VDMX(font, height);
3323 if(font->ppem == 0)
3324 font->ppem = calc_ppem_for_height(ft_face, height);
3325 TRACE("height %d => ppem %d\n", height, font->ppem);
3327 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3328 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3329 } else {
3330 font->ppem = height;
3331 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3332 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3334 return ft_face;
3338 static int get_nearest_charset(Face *face, int *cp)
3340 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3341 a single face with the requested charset. The idea is to check if
3342 the selected font supports the current ANSI codepage, if it does
3343 return the corresponding charset, else return the first charset */
3345 CHARSETINFO csi;
3346 int acp = GetACP(), i;
3347 DWORD fs0;
3349 *cp = acp;
3350 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3351 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3352 return csi.ciCharset;
3354 for(i = 0; i < 32; i++) {
3355 fs0 = 1L << i;
3356 if(face->fs.fsCsb[0] & fs0) {
3357 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3358 *cp = csi.ciACP;
3359 return csi.ciCharset;
3361 else
3362 FIXME("TCI failing on %x\n", fs0);
3366 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3367 face->fs.fsCsb[0], face->file);
3368 *cp = acp;
3369 return DEFAULT_CHARSET;
3372 static GdiFont *alloc_font(void)
3374 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3375 ret->gmsize = 1;
3376 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3377 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3378 ret->potm = NULL;
3379 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3380 ret->total_kern_pairs = (DWORD)-1;
3381 ret->kern_pairs = NULL;
3382 list_init(&ret->hfontlist);
3383 list_init(&ret->child_fonts);
3384 return ret;
3387 static void free_font(GdiFont *font)
3389 struct list *cursor, *cursor2;
3390 DWORD i;
3392 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3394 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3395 list_remove(cursor);
3396 if(child->font)
3397 free_font(child->font);
3398 HeapFree(GetProcessHeap(), 0, child);
3401 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3403 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3404 DeleteObject(hfontlist->hfont);
3405 list_remove(&hfontlist->entry);
3406 HeapFree(GetProcessHeap(), 0, hfontlist);
3409 if (font->ft_face) pFT_Done_Face(font->ft_face);
3410 if (font->mapping) unmap_font_file( font->mapping );
3411 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3412 HeapFree(GetProcessHeap(), 0, font->potm);
3413 HeapFree(GetProcessHeap(), 0, font->name);
3414 for (i = 0; i < font->gmsize; i++)
3415 HeapFree(GetProcessHeap(),0,font->gm[i]);
3416 HeapFree(GetProcessHeap(), 0, font->gm);
3417 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3418 HeapFree(GetProcessHeap(), 0, font);
3422 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3424 FT_Face ft_face = font->ft_face;
3425 FT_ULong len;
3426 FT_Error err;
3428 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3430 if(!buf)
3431 len = 0;
3432 else
3433 len = cbData;
3435 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3437 /* make sure value of len is the value freetype says it needs */
3438 if (buf && len)
3440 FT_ULong needed = 0;
3441 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3442 if( !err && needed < len) len = needed;
3444 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3445 if (err)
3447 TRACE("Can't find table %c%c%c%c\n",
3448 /* bytes were reversed */
3449 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
3450 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
3451 return GDI_ERROR;
3453 return len;
3456 /*************************************************************
3457 * load_VDMX
3459 * load the vdmx entry for the specified height
3462 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3463 ( ( (FT_ULong)_x4 << 24 ) | \
3464 ( (FT_ULong)_x3 << 16 ) | \
3465 ( (FT_ULong)_x2 << 8 ) | \
3466 (FT_ULong)_x1 )
3468 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3470 typedef struct {
3471 BYTE bCharSet;
3472 BYTE xRatio;
3473 BYTE yStartRatio;
3474 BYTE yEndRatio;
3475 } Ratios;
3477 typedef struct {
3478 WORD recs;
3479 BYTE startsz;
3480 BYTE endsz;
3481 } VDMX_group;
3483 static LONG load_VDMX(GdiFont *font, LONG height)
3485 WORD hdr[3], tmp;
3486 VDMX_group group;
3487 BYTE devXRatio, devYRatio;
3488 USHORT numRecs, numRatios;
3489 DWORD result, offset = -1;
3490 LONG ppem = 0;
3491 int i;
3493 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
3495 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3496 return ppem;
3498 /* FIXME: need the real device aspect ratio */
3499 devXRatio = 1;
3500 devYRatio = 1;
3502 numRecs = GET_BE_WORD(hdr[1]);
3503 numRatios = GET_BE_WORD(hdr[2]);
3505 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3506 for(i = 0; i < numRatios; i++) {
3507 Ratios ratio;
3509 offset = (3 * 2) + (i * sizeof(Ratios));
3510 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3511 offset = -1;
3513 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3515 if((ratio.xRatio == 0 &&
3516 ratio.yStartRatio == 0 &&
3517 ratio.yEndRatio == 0) ||
3518 (devXRatio == ratio.xRatio &&
3519 devYRatio >= ratio.yStartRatio &&
3520 devYRatio <= ratio.yEndRatio))
3522 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3523 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
3524 offset = GET_BE_WORD(tmp);
3525 break;
3529 if(offset == -1) {
3530 FIXME("No suitable ratio found\n");
3531 return ppem;
3534 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3535 USHORT recs;
3536 BYTE startsz, endsz;
3537 WORD *vTable;
3539 recs = GET_BE_WORD(group.recs);
3540 startsz = group.startsz;
3541 endsz = group.endsz;
3543 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3545 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3546 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3547 if(result == GDI_ERROR) {
3548 FIXME("Failed to retrieve vTable\n");
3549 goto end;
3552 if(height > 0) {
3553 for(i = 0; i < recs; i++) {
3554 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3555 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3556 ppem = GET_BE_WORD(vTable[i * 3]);
3558 if(yMax + -yMin == height) {
3559 font->yMax = yMax;
3560 font->yMin = yMin;
3561 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3562 break;
3564 if(yMax + -yMin > height) {
3565 if(--i < 0) {
3566 ppem = 0;
3567 goto end; /* failed */
3569 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3570 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3571 ppem = GET_BE_WORD(vTable[i * 3]);
3572 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3573 break;
3576 if(!font->yMax) {
3577 ppem = 0;
3578 TRACE("ppem not found for height %d\n", height);
3581 end:
3582 HeapFree(GetProcessHeap(), 0, vTable);
3585 return ppem;
3588 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3590 if(font->font_desc.hash != fd->hash) return TRUE;
3591 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3592 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3593 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3594 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3597 static void calc_hash(FONT_DESC *pfd)
3599 DWORD hash = 0, *ptr, two_chars;
3600 WORD *pwc;
3601 unsigned int i;
3603 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3604 hash ^= *ptr;
3605 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3606 hash ^= *ptr;
3607 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3608 two_chars = *ptr;
3609 pwc = (WCHAR *)&two_chars;
3610 if(!*pwc) break;
3611 *pwc = toupperW(*pwc);
3612 pwc++;
3613 *pwc = toupperW(*pwc);
3614 hash ^= two_chars;
3615 if(!*pwc) break;
3617 hash ^= !pfd->can_use_bitmap;
3618 pfd->hash = hash;
3619 return;
3622 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3624 GdiFont *ret;
3625 FONT_DESC fd;
3626 HFONTLIST *hflist;
3627 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3629 fd.lf = *plf;
3630 fd.matrix = *pmat;
3631 fd.can_use_bitmap = can_use_bitmap;
3632 calc_hash(&fd);
3634 /* try the child list */
3635 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3636 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3637 if(!fontcmp(ret, &fd)) {
3638 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3639 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3640 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3641 if(hflist->hfont == hfont)
3642 return ret;
3647 /* try the in-use list */
3648 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3649 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3650 if(!fontcmp(ret, &fd)) {
3651 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3652 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3653 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3654 if(hflist->hfont == hfont)
3655 return ret;
3657 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3658 hflist->hfont = hfont;
3659 list_add_head(&ret->hfontlist, &hflist->entry);
3660 return ret;
3664 /* then the unused list */
3665 font_elem_ptr = list_head(&unused_gdi_font_list);
3666 while(font_elem_ptr) {
3667 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3668 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3669 if(!fontcmp(ret, &fd)) {
3670 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3671 assert(list_empty(&ret->hfontlist));
3672 TRACE("Found %p in unused list\n", ret);
3673 list_remove(&ret->entry);
3674 list_add_head(&gdi_font_list, &ret->entry);
3675 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3676 hflist->hfont = hfont;
3677 list_add_head(&ret->hfontlist, &hflist->entry);
3678 return ret;
3681 return NULL;
3684 static void add_to_cache(GdiFont *font)
3686 static DWORD cache_num = 1;
3688 font->cache_num = cache_num++;
3689 list_add_head(&gdi_font_list, &font->entry);
3692 /*************************************************************
3693 * create_child_font_list
3695 static BOOL create_child_font_list(GdiFont *font)
3697 BOOL ret = FALSE;
3698 SYSTEM_LINKS *font_link;
3699 CHILD_FONT *font_link_entry, *new_child;
3700 FontSubst *psub;
3701 WCHAR* font_name;
3703 psub = get_font_subst(&font_subst_list, font->name, -1);
3704 font_name = psub ? psub->to.name : font->name;
3705 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3707 if(!strcmpiW(font_link->font_name, font_name))
3709 TRACE("found entry in system list\n");
3710 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3712 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3713 new_child->face = font_link_entry->face;
3714 new_child->font = NULL;
3715 list_add_tail(&font->child_fonts, &new_child->entry);
3716 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3718 ret = TRUE;
3719 break;
3723 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3724 * Sans Serif. This is how asian windows get default fallbacks for fonts
3726 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3727 font->charset != OEM_CHARSET &&
3728 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3729 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3731 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3733 TRACE("found entry in default fallback list\n");
3734 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3736 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3737 new_child->face = font_link_entry->face;
3738 new_child->font = NULL;
3739 list_add_tail(&font->child_fonts, &new_child->entry);
3740 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3742 ret = TRUE;
3743 break;
3747 return ret;
3750 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3752 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3754 if (pFT_Set_Charmap)
3756 FT_Int i;
3757 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3759 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3761 for (i = 0; i < ft_face->num_charmaps; i++)
3763 if (ft_face->charmaps[i]->encoding == encoding)
3765 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3766 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3768 switch (ft_face->charmaps[i]->platform_id)
3770 default:
3771 cmap_def = ft_face->charmaps[i];
3772 break;
3773 case 0: /* Apple Unicode */
3774 cmap0 = ft_face->charmaps[i];
3775 break;
3776 case 1: /* Macintosh */
3777 cmap1 = ft_face->charmaps[i];
3778 break;
3779 case 2: /* ISO */
3780 cmap2 = ft_face->charmaps[i];
3781 break;
3782 case 3: /* Microsoft */
3783 cmap3 = ft_face->charmaps[i];
3784 break;
3788 if (cmap3) /* prefer Microsoft cmap table */
3789 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3790 else if (cmap1)
3791 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3792 else if (cmap2)
3793 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3794 else if (cmap0)
3795 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3796 else if (cmap_def)
3797 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3799 return ft_err == FT_Err_Ok;
3802 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3806 /*************************************************************
3807 * freetype_CreateDC
3809 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3810 LPCWSTR output, const DEVMODEW *devmode )
3812 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3814 if (!physdev) return FALSE;
3815 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3816 return TRUE;
3820 /*************************************************************
3821 * freetype_DeleteDC
3823 static BOOL freetype_DeleteDC( PHYSDEV dev )
3825 struct freetype_physdev *physdev = get_freetype_dev( dev );
3826 HeapFree( GetProcessHeap(), 0, physdev );
3827 return TRUE;
3831 /*************************************************************
3832 * freetype_SelectFont
3834 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3836 struct freetype_physdev *physdev = get_freetype_dev( dev );
3837 GdiFont *ret;
3838 Face *face, *best, *best_bitmap;
3839 Family *family, *last_resort_family;
3840 struct list *family_elem_ptr, *face_elem_ptr;
3841 INT height, width = 0;
3842 unsigned int score = 0, new_score;
3843 signed int diff = 0, newdiff;
3844 BOOL bd, it, can_use_bitmap;
3845 LOGFONTW lf;
3846 CHARSETINFO csi;
3847 HFONTLIST *hflist;
3848 FMAT2 dcmat;
3849 FontSubst *psub = NULL;
3850 DC *dc = get_dc_ptr( dev->hdc );
3852 if (!hfont) /* notification that the font has been changed by another driver */
3854 dc->gdiFont = NULL;
3855 physdev->font = NULL;
3856 release_dc_ptr( dc );
3857 return 0;
3860 GetObjectW( hfont, sizeof(lf), &lf );
3861 lf.lfWidth = abs(lf.lfWidth);
3863 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
3865 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3866 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3867 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3868 lf.lfEscapement);
3870 if(dc->GraphicsMode == GM_ADVANCED)
3871 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3872 else
3874 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3875 font scaling abilities. */
3876 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3877 dcmat.eM21 = dcmat.eM12 = 0;
3880 /* Try to avoid not necessary glyph transformations */
3881 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3883 lf.lfHeight *= fabs(dcmat.eM11);
3884 lf.lfWidth *= fabs(dcmat.eM11);
3885 dcmat.eM11 = dcmat.eM22 = 1.0;
3888 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3889 dcmat.eM21, dcmat.eM22);
3891 GDI_CheckNotLock();
3892 EnterCriticalSection( &freetype_cs );
3894 /* check the cache first */
3895 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3896 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3897 goto done;
3900 if(list_empty(&font_list)) /* No fonts installed */
3902 TRACE("No fonts installed\n");
3903 goto done;
3906 TRACE("not in cache\n");
3907 ret = alloc_font();
3909 ret->font_desc.matrix = dcmat;
3910 ret->font_desc.lf = lf;
3911 ret->font_desc.can_use_bitmap = can_use_bitmap;
3912 calc_hash(&ret->font_desc);
3913 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3914 hflist->hfont = hfont;
3915 list_add_head(&ret->hfontlist, &hflist->entry);
3917 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3918 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3919 original value lfCharSet. Note this is a special case for
3920 Symbol and doesn't happen at least for "Wingdings*" */
3922 if(!strcmpiW(lf.lfFaceName, SymbolW))
3923 lf.lfCharSet = SYMBOL_CHARSET;
3925 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3926 switch(lf.lfCharSet) {
3927 case DEFAULT_CHARSET:
3928 csi.fs.fsCsb[0] = 0;
3929 break;
3930 default:
3931 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3932 csi.fs.fsCsb[0] = 0;
3933 break;
3937 family = NULL;
3938 if(lf.lfFaceName[0] != '\0') {
3939 SYSTEM_LINKS *font_link;
3940 CHILD_FONT *font_link_entry;
3941 LPWSTR FaceName = lf.lfFaceName;
3943 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3945 if(psub) {
3946 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3947 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3948 if (psub->to.charset != -1)
3949 lf.lfCharSet = psub->to.charset;
3952 /* We want a match on name and charset or just name if
3953 charset was DEFAULT_CHARSET. If the latter then
3954 we fixup the returned charset later in get_nearest_charset
3955 where we'll either use the charset of the current ansi codepage
3956 or if that's unavailable the first charset that the font supports.
3958 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3959 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3960 if (!strcmpiW(family->FamilyName, FaceName) ||
3961 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3963 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3964 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3965 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3966 if(face->scalable || can_use_bitmap)
3967 goto found;
3972 /* Search by full face name. */
3973 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3974 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3975 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3976 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3977 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
3978 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
3980 if(face->scalable || can_use_bitmap)
3981 goto found_face;
3987 * Try check the SystemLink list first for a replacement font.
3988 * We may find good replacements there.
3990 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3992 if(!strcmpiW(font_link->font_name, FaceName) ||
3993 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3995 TRACE("found entry in system list\n");
3996 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3998 face = font_link_entry->face;
3999 family = face->family;
4000 if(csi.fs.fsCsb[0] &
4001 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
4003 if(face->scalable || can_use_bitmap)
4004 goto found;
4011 psub = NULL; /* substitution is no more relevant */
4013 /* If requested charset was DEFAULT_CHARSET then try using charset
4014 corresponding to the current ansi codepage */
4015 if (!csi.fs.fsCsb[0])
4017 INT acp = GetACP();
4018 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4019 FIXME("TCI failed on codepage %d\n", acp);
4020 csi.fs.fsCsb[0] = 0;
4021 } else
4022 lf.lfCharSet = csi.ciCharset;
4025 /* Face families are in the top 4 bits of lfPitchAndFamily,
4026 so mask with 0xF0 before testing */
4028 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4029 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4030 strcpyW(lf.lfFaceName, defFixed);
4031 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4032 strcpyW(lf.lfFaceName, defSerif);
4033 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4034 strcpyW(lf.lfFaceName, defSans);
4035 else
4036 strcpyW(lf.lfFaceName, defSans);
4037 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4038 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4039 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4040 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4041 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4042 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
4043 if(face->scalable || can_use_bitmap)
4044 goto found;
4049 last_resort_family = NULL;
4050 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4051 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4052 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4053 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4054 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
4055 if(face->scalable)
4056 goto found;
4057 if(can_use_bitmap && !last_resort_family)
4058 last_resort_family = family;
4063 if(last_resort_family) {
4064 family = last_resort_family;
4065 csi.fs.fsCsb[0] = 0;
4066 goto found;
4069 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4070 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4071 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4072 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4073 if(face->scalable) {
4074 csi.fs.fsCsb[0] = 0;
4075 WARN("just using first face for now\n");
4076 goto found;
4078 if(can_use_bitmap && !last_resort_family)
4079 last_resort_family = family;
4082 if(!last_resort_family) {
4083 FIXME("can't find a single appropriate font - bailing\n");
4084 free_font(ret);
4085 ret = NULL;
4086 goto done;
4089 WARN("could only find a bitmap font - this will probably look awful!\n");
4090 family = last_resort_family;
4091 csi.fs.fsCsb[0] = 0;
4093 found:
4094 it = lf.lfItalic ? 1 : 0;
4095 bd = lf.lfWeight > 550 ? 1 : 0;
4097 height = lf.lfHeight;
4099 face = best = best_bitmap = NULL;
4100 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
4102 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4104 BOOL italic, bold;
4106 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4107 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4108 new_score = (italic ^ it) + (bold ^ bd);
4109 if(!best || new_score <= score)
4111 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4112 italic, bold, it, bd);
4113 score = new_score;
4114 best = face;
4115 if(best->scalable && score == 0) break;
4116 if(!best->scalable)
4118 if(height > 0)
4119 newdiff = height - (signed int)(best->size.height);
4120 else
4121 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4122 if(!best_bitmap || new_score < score ||
4123 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4125 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4126 diff = newdiff;
4127 best_bitmap = best;
4128 if(score == 0 && diff == 0) break;
4134 if(best)
4135 face = best->scalable ? best : best_bitmap;
4136 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4137 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4139 found_face:
4140 height = lf.lfHeight;
4142 ret->fs = face->fs;
4144 if(csi.fs.fsCsb[0]) {
4145 ret->charset = lf.lfCharSet;
4146 ret->codepage = csi.ciACP;
4148 else
4149 ret->charset = get_nearest_charset(face, &ret->codepage);
4151 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4152 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4154 ret->aveWidth = height ? lf.lfWidth : 0;
4156 if(!face->scalable) {
4157 /* Windows uses integer scaling factors for bitmap fonts */
4158 INT scale, scaled_height;
4159 GdiFont *cachedfont;
4161 /* FIXME: rotation of bitmap fonts is ignored */
4162 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4163 if (ret->aveWidth)
4164 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4165 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4166 dcmat.eM11 = dcmat.eM22 = 1.0;
4167 /* As we changed the matrix, we need to search the cache for the font again,
4168 * otherwise we might explode the cache. */
4169 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4170 TRACE("Found cached font after non-scalable matrix rescale!\n");
4171 free_font( ret );
4172 ret = cachedfont;
4173 goto done;
4175 calc_hash(&ret->font_desc);
4177 if (height != 0) height = diff;
4178 height += face->size.height;
4180 scale = (height + face->size.height - 1) / face->size.height;
4181 scaled_height = scale * face->size.height;
4182 /* Only jump to the next height if the difference <= 25% original height */
4183 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4184 /* The jump between unscaled and doubled is delayed by 1 */
4185 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4186 ret->scale_y = scale;
4188 width = face->size.x_ppem >> 6;
4189 height = face->size.y_ppem >> 6;
4191 else
4192 ret->scale_y = 1.0;
4193 TRACE("font scale y: %f\n", ret->scale_y);
4195 ret->ft_face = OpenFontFace(ret, face, width, height);
4197 if (!ret->ft_face)
4199 free_font( ret );
4200 ret = NULL;
4201 goto done;
4204 ret->ntmFlags = face->ntmFlags;
4206 if (ret->charset == SYMBOL_CHARSET &&
4207 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4208 /* No ops */
4210 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4211 /* No ops */
4213 else {
4214 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4217 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4218 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4219 ret->underline = lf.lfUnderline ? 0xff : 0;
4220 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4221 create_child_font_list(ret);
4223 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
4225 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4226 if (length != GDI_ERROR)
4228 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4229 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4230 TRACE("Loaded GSUB table of %i bytes\n",length);
4234 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4236 add_to_cache(ret);
4237 done:
4238 if (ret)
4240 dc->gdiFont = ret;
4241 physdev->font = ret;
4243 LeaveCriticalSection( &freetype_cs );
4244 release_dc_ptr( dc );
4245 return ret ? hfont : 0;
4248 static void dump_gdi_font_list(void)
4250 GdiFont *gdiFont;
4251 struct list *elem_ptr;
4253 TRACE("---------- gdiFont Cache ----------\n");
4254 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4255 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4256 TRACE("gdiFont=%p %s %d\n",
4257 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4260 TRACE("---------- Unused gdiFont Cache ----------\n");
4261 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4262 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4263 TRACE("gdiFont=%p %s %d\n",
4264 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4267 TRACE("---------- Child gdiFont Cache ----------\n");
4268 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4269 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4270 TRACE("gdiFont=%p %s %d\n",
4271 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4275 /*************************************************************
4276 * WineEngDestroyFontInstance
4278 * free the gdiFont associated with this handle
4281 BOOL WineEngDestroyFontInstance(HFONT handle)
4283 GdiFont *gdiFont;
4284 HFONTLIST *hflist;
4285 BOOL ret = FALSE;
4286 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4287 int i = 0;
4289 GDI_CheckNotLock();
4290 EnterCriticalSection( &freetype_cs );
4292 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4294 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4295 while(hfontlist_elem_ptr) {
4296 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4297 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4298 if(hflist->hfont == handle) {
4299 TRACE("removing child font %p from child list\n", gdiFont);
4300 list_remove(&gdiFont->entry);
4301 LeaveCriticalSection( &freetype_cs );
4302 return TRUE;
4307 TRACE("destroying hfont=%p\n", handle);
4308 if(TRACE_ON(font))
4309 dump_gdi_font_list();
4311 font_elem_ptr = list_head(&gdi_font_list);
4312 while(font_elem_ptr) {
4313 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4314 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4316 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4317 while(hfontlist_elem_ptr) {
4318 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4319 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4320 if(hflist->hfont == handle) {
4321 list_remove(&hflist->entry);
4322 HeapFree(GetProcessHeap(), 0, hflist);
4323 ret = TRUE;
4326 if(list_empty(&gdiFont->hfontlist)) {
4327 TRACE("Moving to Unused list\n");
4328 list_remove(&gdiFont->entry);
4329 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4334 font_elem_ptr = list_head(&unused_gdi_font_list);
4335 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4336 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4337 while(font_elem_ptr) {
4338 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4339 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4340 TRACE("freeing %p\n", gdiFont);
4341 list_remove(&gdiFont->entry);
4342 free_font(gdiFont);
4344 LeaveCriticalSection( &freetype_cs );
4345 return ret;
4348 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4350 HRSRC rsrc;
4351 HGLOBAL hMem;
4352 WCHAR *p;
4353 int i;
4355 id += IDS_FIRST_SCRIPT;
4356 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4357 if (!rsrc) return 0;
4358 hMem = LoadResource( gdi32_module, rsrc );
4359 if (!hMem) return 0;
4361 p = LockResource( hMem );
4362 id &= 0x000f;
4363 while (id--) p += *p + 1;
4365 i = min(LF_FACESIZE - 1, *p);
4366 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4367 buffer[i] = 0;
4368 return i;
4372 /***************************************************
4373 * create_enum_charset_list
4375 * This function creates charset enumeration list because in DEFAULT_CHARSET
4376 * case, the ANSI codepage's charset takes precedence over other charsets.
4377 * This function works as a filter other than DEFAULT_CHARSET case.
4379 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4381 CHARSETINFO csi;
4382 DWORD n = 0;
4384 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4385 csi.fs.fsCsb[0] != 0) {
4386 list->element[n].mask = csi.fs.fsCsb[0];
4387 list->element[n].charset = csi.ciCharset;
4388 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4389 n++;
4391 else { /* charset is DEFAULT_CHARSET or invalid. */
4392 INT acp, i;
4394 /* Set the current codepage's charset as the first element. */
4395 acp = GetACP();
4396 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4397 csi.fs.fsCsb[0] != 0) {
4398 list->element[n].mask = csi.fs.fsCsb[0];
4399 list->element[n].charset = csi.ciCharset;
4400 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4401 n++;
4404 /* Fill out left elements. */
4405 for (i = 0; i < 32; i++) {
4406 FONTSIGNATURE fs;
4407 fs.fsCsb[0] = 1L << i;
4408 fs.fsCsb[1] = 0;
4409 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4410 continue; /* skip, already added. */
4411 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4412 continue; /* skip, this is an invalid fsCsb bit. */
4414 list->element[n].mask = fs.fsCsb[0];
4415 list->element[n].charset = csi.ciCharset;
4416 load_script_name( i, list->element[n].name );
4417 n++;
4420 list->total = n;
4422 return n;
4425 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4426 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4428 GdiFont *font;
4429 LONG width, height;
4431 if (face->cached_enum_data)
4433 TRACE("Cached\n");
4434 *pelf = face->cached_enum_data->elf;
4435 *pntm = face->cached_enum_data->ntm;
4436 *ptype = face->cached_enum_data->type;
4437 return;
4440 font = alloc_font();
4442 if(face->scalable) {
4443 height = -2048; /* 2048 is the most common em size */
4444 width = 0;
4445 } else {
4446 height = face->size.y_ppem >> 6;
4447 width = face->size.x_ppem >> 6;
4449 font->scale_y = 1.0;
4451 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4453 free_font(font);
4454 return;
4457 font->name = strdupW(face->family->FamilyName);
4458 font->ntmFlags = face->ntmFlags;
4460 if (get_outline_text_metrics(font))
4462 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4464 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4466 lstrcpynW(pelf->elfLogFont.lfFaceName,
4467 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4468 LF_FACESIZE);
4469 lstrcpynW(pelf->elfFullName,
4470 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4471 LF_FULLFACESIZE);
4472 lstrcpynW(pelf->elfStyle,
4473 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4474 LF_FACESIZE);
4476 else
4478 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4480 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4482 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4483 if (face->FullName)
4484 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4485 else
4486 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4487 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4490 pntm->ntmTm.ntmFlags = face->ntmFlags;
4491 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4492 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4493 pntm->ntmFontSig = face->fs;
4495 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4497 pelf->elfLogFont.lfEscapement = 0;
4498 pelf->elfLogFont.lfOrientation = 0;
4499 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4500 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4501 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4502 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4503 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4504 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4505 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4506 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4507 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4508 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4509 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4511 *ptype = 0;
4512 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4513 *ptype |= TRUETYPE_FONTTYPE;
4514 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4515 *ptype |= DEVICE_FONTTYPE;
4516 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4517 *ptype |= RASTER_FONTTYPE;
4519 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4520 if (face->cached_enum_data)
4522 face->cached_enum_data->elf = *pelf;
4523 face->cached_enum_data->ntm = *pntm;
4524 face->cached_enum_data->type = *ptype;
4527 free_font(font);
4530 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4532 struct list *face_elem_ptr;
4534 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4536 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4538 static const WCHAR spaceW[] = { ' ',0 };
4539 WCHAR full_family_name[LF_FULLFACESIZE];
4540 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4542 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4544 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4545 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4546 continue;
4549 strcpyW(full_family_name, family->FamilyName);
4550 strcatW(full_family_name, spaceW);
4551 strcatW(full_family_name, face->StyleName);
4552 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4555 return FALSE;
4558 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4560 static const WCHAR spaceW[] = { ' ',0 };
4561 WCHAR full_family_name[LF_FULLFACESIZE];
4563 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4565 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4567 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4568 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4569 return FALSE;
4572 strcpyW(full_family_name, face->family->FamilyName);
4573 strcatW(full_family_name, spaceW);
4574 strcatW(full_family_name, face->StyleName);
4575 return !strcmpiW(lf->lfFaceName, full_family_name);
4578 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4579 FONTENUMPROCW proc, LPARAM lparam)
4581 ENUMLOGFONTEXW elf;
4582 NEWTEXTMETRICEXW ntm;
4583 DWORD type = 0;
4584 int i;
4586 GetEnumStructs(face, &elf, &ntm, &type);
4587 for(i = 0; i < list->total; i++) {
4588 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4589 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4590 load_script_name( IDS_OEM_DOS, elf.elfScript );
4591 i = list->total; /* break out of loop after enumeration */
4592 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4593 continue;
4594 else {
4595 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4596 strcpyW(elf.elfScript, list->element[i].name);
4597 if (!elf.elfScript[0])
4598 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4600 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4601 debugstr_w(elf.elfLogFont.lfFaceName),
4602 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4603 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
4604 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4605 ntm.ntmTm.ntmFlags);
4606 /* release section before callback (FIXME) */
4607 LeaveCriticalSection( &freetype_cs );
4608 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4609 EnterCriticalSection( &freetype_cs );
4611 return TRUE;
4614 /*************************************************************
4615 * freetype_EnumFonts
4617 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4619 Family *family;
4620 Face *face;
4621 struct list *family_elem_ptr, *face_elem_ptr;
4622 LOGFONTW lf;
4623 struct enum_charset_list enum_charsets;
4625 if (!plf)
4627 lf.lfCharSet = DEFAULT_CHARSET;
4628 lf.lfPitchAndFamily = 0;
4629 lf.lfFaceName[0] = 0;
4630 plf = &lf;
4633 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4635 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4637 GDI_CheckNotLock();
4638 EnterCriticalSection( &freetype_cs );
4639 if(plf->lfFaceName[0]) {
4640 FontSubst *psub;
4641 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4643 if(psub) {
4644 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4645 debugstr_w(psub->to.name));
4646 lf = *plf;
4647 strcpyW(lf.lfFaceName, psub->to.name);
4648 plf = &lf;
4651 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4652 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4653 if(family_matches(family, plf)) {
4654 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4655 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4656 if (!face_matches(face, plf)) continue;
4657 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4661 } else {
4662 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4663 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4664 face_elem_ptr = list_head(&family->faces);
4665 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4666 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4669 LeaveCriticalSection( &freetype_cs );
4670 return TRUE;
4673 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4675 pt->x.value = vec->x >> 6;
4676 pt->x.fract = (vec->x & 0x3f) << 10;
4677 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4678 pt->y.value = vec->y >> 6;
4679 pt->y.fract = (vec->y & 0x3f) << 10;
4680 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4681 return;
4684 /***************************************************
4685 * According to the MSDN documentation on WideCharToMultiByte,
4686 * certain codepages cannot set the default_used parameter.
4687 * This returns TRUE if the codepage can set that parameter, false else
4688 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4690 static BOOL codepage_sets_default_used(UINT codepage)
4692 switch (codepage)
4694 case CP_UTF7:
4695 case CP_UTF8:
4696 case CP_SYMBOL:
4697 return FALSE;
4698 default:
4699 return TRUE;
4704 * GSUB Table handling functions
4707 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4709 const GSUB_CoverageFormat1* cf1;
4711 cf1 = table;
4713 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4715 int count = GET_BE_WORD(cf1->GlyphCount);
4716 int i;
4717 TRACE("Coverage Format 1, %i glyphs\n",count);
4718 for (i = 0; i < count; i++)
4719 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4720 return i;
4721 return -1;
4723 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4725 const GSUB_CoverageFormat2* cf2;
4726 int i;
4727 int count;
4728 cf2 = (const GSUB_CoverageFormat2*)cf1;
4730 count = GET_BE_WORD(cf2->RangeCount);
4731 TRACE("Coverage Format 2, %i ranges\n",count);
4732 for (i = 0; i < count; i++)
4734 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4735 return -1;
4736 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4737 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4739 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4740 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4743 return -1;
4745 else
4746 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4748 return -1;
4751 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4753 const GSUB_ScriptList *script;
4754 const GSUB_Script *deflt = NULL;
4755 int i;
4756 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4758 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4759 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4761 const GSUB_Script *scr;
4762 int offset;
4764 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4765 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4767 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4768 return scr;
4769 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4770 deflt = scr;
4772 return deflt;
4775 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4777 int i;
4778 int offset;
4779 const GSUB_LangSys *Lang;
4781 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4783 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4785 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4786 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4788 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4789 return Lang;
4791 offset = GET_BE_WORD(script->DefaultLangSys);
4792 if (offset)
4794 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4795 return Lang;
4797 return NULL;
4800 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4802 int i;
4803 const GSUB_FeatureList *feature;
4804 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4806 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4807 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4809 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4810 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4812 const GSUB_Feature *feat;
4813 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4814 return feat;
4817 return NULL;
4820 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4822 int i;
4823 int offset;
4824 const GSUB_LookupList *lookup;
4825 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4827 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4828 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4830 const GSUB_LookupTable *look;
4831 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4832 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4833 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4834 if (GET_BE_WORD(look->LookupType) != 1)
4835 FIXME("We only handle SubType 1\n");
4836 else
4838 int j;
4840 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4842 const GSUB_SingleSubstFormat1 *ssf1;
4843 offset = GET_BE_WORD(look->SubTable[j]);
4844 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4845 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4847 int offset = GET_BE_WORD(ssf1->Coverage);
4848 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4849 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4851 TRACE(" Glyph 0x%x ->",glyph);
4852 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4853 TRACE(" 0x%x\n",glyph);
4856 else
4858 const GSUB_SingleSubstFormat2 *ssf2;
4859 INT index;
4860 INT offset;
4862 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4863 offset = GET_BE_WORD(ssf1->Coverage);
4864 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4865 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4866 TRACE(" Coverage index %i\n",index);
4867 if (index != -1)
4869 TRACE(" Glyph is 0x%x ->",glyph);
4870 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4871 TRACE("0x%x\n",glyph);
4877 return glyph;
4880 static const char* get_opentype_script(const GdiFont *font)
4883 * I am not sure if this is the correct way to generate our script tag
4886 switch (font->charset)
4888 case ANSI_CHARSET: return "latn";
4889 case BALTIC_CHARSET: return "latn"; /* ?? */
4890 case CHINESEBIG5_CHARSET: return "hani";
4891 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4892 case GB2312_CHARSET: return "hani";
4893 case GREEK_CHARSET: return "grek";
4894 case HANGUL_CHARSET: return "hang";
4895 case RUSSIAN_CHARSET: return "cyrl";
4896 case SHIFTJIS_CHARSET: return "kana";
4897 case TURKISH_CHARSET: return "latn"; /* ?? */
4898 case VIETNAMESE_CHARSET: return "latn";
4899 case JOHAB_CHARSET: return "latn"; /* ?? */
4900 case ARABIC_CHARSET: return "arab";
4901 case HEBREW_CHARSET: return "hebr";
4902 case THAI_CHARSET: return "thai";
4903 default: return "latn";
4907 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4909 const GSUB_Header *header;
4910 const GSUB_Script *script;
4911 const GSUB_LangSys *language;
4912 const GSUB_Feature *feature;
4914 if (!font->GSUB_Table)
4915 return glyph;
4917 header = font->GSUB_Table;
4919 script = GSUB_get_script_table(header, get_opentype_script(font));
4920 if (!script)
4922 TRACE("Script not found\n");
4923 return glyph;
4925 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4926 if (!language)
4928 TRACE("Language not found\n");
4929 return glyph;
4931 feature = GSUB_get_feature(header, language, "vrt2");
4932 if (!feature)
4933 feature = GSUB_get_feature(header, language, "vert");
4934 if (!feature)
4936 TRACE("vrt2/vert feature not found\n");
4937 return glyph;
4939 return GSUB_apply_feature(header, feature, glyph);
4942 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4944 FT_UInt glyphId;
4946 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4947 WCHAR wc = (WCHAR)glyph;
4948 BOOL default_used;
4949 BOOL *default_used_pointer;
4950 FT_UInt ret;
4951 char buf;
4952 default_used_pointer = NULL;
4953 default_used = FALSE;
4954 if (codepage_sets_default_used(font->codepage))
4955 default_used_pointer = &default_used;
4956 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4957 ret = 0;
4958 else
4959 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4960 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4961 return get_GSUB_vert_glyph(font,ret);
4964 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
4966 if (glyph < 0x100) glyph += 0xf000;
4967 /* there is a number of old pre-Unicode "broken" TTFs, which
4968 do have symbols at U+00XX instead of U+f0XX */
4969 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
4970 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
4972 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4974 return get_GSUB_vert_glyph(font,glyphId);
4977 /*************************************************************
4978 * freetype_GetGlyphIndices
4980 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
4982 struct freetype_physdev *physdev = get_freetype_dev( dev );
4983 int i;
4984 WORD default_char;
4985 BOOL got_default = FALSE;
4987 if (!physdev->font)
4989 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
4990 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
4993 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
4995 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4996 got_default = TRUE;
4999 GDI_CheckNotLock();
5000 EnterCriticalSection( &freetype_cs );
5002 for(i = 0; i < count; i++)
5004 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5005 if (pgi[i] == 0)
5007 if (!got_default)
5009 if (FT_IS_SFNT(physdev->font->ft_face))
5011 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5012 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5014 else
5016 TEXTMETRICW textm;
5017 get_text_metrics(physdev->font, &textm);
5018 default_char = textm.tmDefaultChar;
5020 got_default = TRUE;
5022 pgi[i] = default_char;
5025 LeaveCriticalSection( &freetype_cs );
5026 return count;
5029 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5031 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5032 return !memcmp(matrix, &identity, sizeof(FMAT2));
5035 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5037 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5038 return !memcmp(matrix, &identity, sizeof(MAT2));
5041 static inline BYTE get_max_level( UINT format )
5043 switch( format )
5045 case GGO_GRAY2_BITMAP: return 4;
5046 case GGO_GRAY4_BITMAP: return 16;
5047 case GGO_GRAY8_BITMAP: return 64;
5049 return 255;
5052 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5054 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5055 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5056 const MAT2* lpmat)
5058 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5059 FT_Face ft_face = incoming_font->ft_face;
5060 GdiFont *font = incoming_font;
5061 FT_UInt glyph_index;
5062 DWORD width, height, pitch, needed = 0;
5063 FT_Bitmap ft_bitmap;
5064 FT_Error err;
5065 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5066 FT_Angle angle = 0;
5067 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5068 double widthRatio = 1.0;
5069 FT_Matrix transMat = identityMat;
5070 FT_Matrix transMatUnrotated;
5071 BOOL needsTransform = FALSE;
5072 BOOL tategaki = (font->GSUB_Table != NULL);
5073 UINT original_index;
5075 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5076 buflen, buf, lpmat);
5078 TRACE("font transform %f %f %f %f\n",
5079 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5080 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5082 if(format & GGO_GLYPH_INDEX) {
5083 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5084 original_index = glyph;
5085 format &= ~GGO_GLYPH_INDEX;
5086 } else {
5087 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5088 ft_face = font->ft_face;
5089 original_index = glyph_index;
5092 if(format & GGO_UNHINTED) {
5093 load_flags |= FT_LOAD_NO_HINTING;
5094 format &= ~GGO_UNHINTED;
5097 /* tategaki never appears to happen to lower glyph index */
5098 if (glyph_index < TATEGAKI_LOWER_BOUND )
5099 tategaki = FALSE;
5101 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5102 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5103 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5104 font->gmsize * sizeof(GM*));
5105 } else {
5106 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5107 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5109 *lpgm = FONT_GM(font,original_index)->gm;
5110 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5111 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5112 lpgm->gmCellIncX, lpgm->gmCellIncY);
5113 return 1; /* FIXME */
5117 if (!font->gm[original_index / GM_BLOCK_SIZE])
5118 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5120 /* Scaling factor */
5121 if (font->aveWidth)
5123 TEXTMETRICW tm;
5125 get_text_metrics(font, &tm);
5127 widthRatio = (double)font->aveWidth;
5128 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5130 else
5131 widthRatio = font->scale_y;
5133 /* Scaling transform */
5134 if (widthRatio != 1.0 || font->scale_y != 1.0)
5136 FT_Matrix scaleMat;
5137 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5138 scaleMat.xy = 0;
5139 scaleMat.yx = 0;
5140 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5142 pFT_Matrix_Multiply(&scaleMat, &transMat);
5143 needsTransform = TRUE;
5146 /* Slant transform */
5147 if (font->fake_italic) {
5148 FT_Matrix slantMat;
5150 slantMat.xx = (1 << 16);
5151 slantMat.xy = ((1 << 16) >> 2);
5152 slantMat.yx = 0;
5153 slantMat.yy = (1 << 16);
5154 pFT_Matrix_Multiply(&slantMat, &transMat);
5155 needsTransform = TRUE;
5158 /* Rotation transform */
5159 transMatUnrotated = transMat;
5160 if(font->orientation && !tategaki) {
5161 FT_Matrix rotationMat;
5162 FT_Vector vecAngle;
5163 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5164 pFT_Vector_Unit(&vecAngle, angle);
5165 rotationMat.xx = vecAngle.x;
5166 rotationMat.xy = -vecAngle.y;
5167 rotationMat.yx = -rotationMat.xy;
5168 rotationMat.yy = rotationMat.xx;
5170 pFT_Matrix_Multiply(&rotationMat, &transMat);
5171 needsTransform = TRUE;
5174 /* World transform */
5175 if (!is_identity_FMAT2(&font->font_desc.matrix))
5177 FT_Matrix worldMat;
5178 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5179 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5180 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5181 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5182 pFT_Matrix_Multiply(&worldMat, &transMat);
5183 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5184 needsTransform = TRUE;
5187 /* Extra transformation specified by caller */
5188 if (!is_identity_MAT2(lpmat))
5190 FT_Matrix extraMat;
5191 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5192 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5193 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5194 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5195 pFT_Matrix_Multiply(&extraMat, &transMat);
5196 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5197 needsTransform = TRUE;
5200 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5201 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5202 format == GGO_GRAY8_BITMAP))
5204 load_flags |= FT_LOAD_NO_BITMAP;
5207 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5209 if(err) {
5210 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5211 return GDI_ERROR;
5214 if(!needsTransform) {
5215 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5216 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5217 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5219 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5220 bottom = (ft_face->glyph->metrics.horiBearingY -
5221 ft_face->glyph->metrics.height) & -64;
5222 lpgm->gmCellIncX = adv;
5223 lpgm->gmCellIncY = 0;
5224 } else {
5225 INT xc, yc;
5226 FT_Vector vec;
5228 left = right = 0;
5230 for(xc = 0; xc < 2; xc++) {
5231 for(yc = 0; yc < 2; yc++) {
5232 vec.x = (ft_face->glyph->metrics.horiBearingX +
5233 xc * ft_face->glyph->metrics.width);
5234 vec.y = ft_face->glyph->metrics.horiBearingY -
5235 yc * ft_face->glyph->metrics.height;
5236 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5237 pFT_Vector_Transform(&vec, &transMat);
5238 if(xc == 0 && yc == 0) {
5239 left = right = vec.x;
5240 top = bottom = vec.y;
5241 } else {
5242 if(vec.x < left) left = vec.x;
5243 else if(vec.x > right) right = vec.x;
5244 if(vec.y < bottom) bottom = vec.y;
5245 else if(vec.y > top) top = vec.y;
5249 left = left & -64;
5250 right = (right + 63) & -64;
5251 bottom = bottom & -64;
5252 top = (top + 63) & -64;
5254 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5255 vec.x = ft_face->glyph->metrics.horiAdvance;
5256 vec.y = 0;
5257 pFT_Vector_Transform(&vec, &transMat);
5258 lpgm->gmCellIncX = (vec.x+63) >> 6;
5259 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5261 vec.x = ft_face->glyph->metrics.horiAdvance;
5262 vec.y = 0;
5263 pFT_Vector_Transform(&vec, &transMatUnrotated);
5264 adv = (vec.x+63) >> 6;
5267 lsb = left >> 6;
5268 bbx = (right - left) >> 6;
5269 lpgm->gmBlackBoxX = (right - left) >> 6;
5270 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5271 lpgm->gmptGlyphOrigin.x = left >> 6;
5272 lpgm->gmptGlyphOrigin.y = top >> 6;
5274 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5275 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5276 lpgm->gmCellIncX, lpgm->gmCellIncY);
5278 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5279 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5281 FONT_GM(font,original_index)->gm = *lpgm;
5282 FONT_GM(font,original_index)->adv = adv;
5283 FONT_GM(font,original_index)->lsb = lsb;
5284 FONT_GM(font,original_index)->bbx = bbx;
5285 FONT_GM(font,original_index)->init = TRUE;
5288 if(format == GGO_METRICS)
5290 return 1; /* FIXME */
5293 if(ft_face->glyph->format != ft_glyph_format_outline &&
5294 (format == GGO_NATIVE || format == GGO_BEZIER))
5296 TRACE("loaded a bitmap\n");
5297 return GDI_ERROR;
5300 switch(format) {
5301 case GGO_BITMAP:
5302 width = lpgm->gmBlackBoxX;
5303 height = lpgm->gmBlackBoxY;
5304 pitch = ((width + 31) >> 5) << 2;
5305 needed = pitch * height;
5307 if(!buf || !buflen) break;
5309 switch(ft_face->glyph->format) {
5310 case ft_glyph_format_bitmap:
5312 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5313 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5314 INT h = ft_face->glyph->bitmap.rows;
5315 while(h--) {
5316 memcpy(dst, src, w);
5317 src += ft_face->glyph->bitmap.pitch;
5318 dst += pitch;
5320 break;
5323 case ft_glyph_format_outline:
5324 ft_bitmap.width = width;
5325 ft_bitmap.rows = height;
5326 ft_bitmap.pitch = pitch;
5327 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5328 ft_bitmap.buffer = buf;
5330 if(needsTransform)
5331 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5333 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5335 /* Note: FreeType will only set 'black' bits for us. */
5336 memset(buf, 0, needed);
5337 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5338 break;
5340 default:
5341 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5342 return GDI_ERROR;
5344 break;
5346 case GGO_GRAY2_BITMAP:
5347 case GGO_GRAY4_BITMAP:
5348 case GGO_GRAY8_BITMAP:
5349 case WINE_GGO_GRAY16_BITMAP:
5351 unsigned int max_level, row, col;
5352 BYTE *start, *ptr;
5354 width = lpgm->gmBlackBoxX;
5355 height = lpgm->gmBlackBoxY;
5356 pitch = (width + 3) / 4 * 4;
5357 needed = pitch * height;
5359 if(!buf || !buflen) break;
5361 max_level = get_max_level( format );
5363 switch(ft_face->glyph->format) {
5364 case ft_glyph_format_bitmap:
5366 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5367 INT h = ft_face->glyph->bitmap.rows;
5368 INT x;
5369 memset( buf, 0, needed );
5370 while(h--) {
5371 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5372 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5373 src += ft_face->glyph->bitmap.pitch;
5374 dst += pitch;
5376 return needed;
5378 case ft_glyph_format_outline:
5380 ft_bitmap.width = width;
5381 ft_bitmap.rows = height;
5382 ft_bitmap.pitch = pitch;
5383 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5384 ft_bitmap.buffer = buf;
5386 if(needsTransform)
5387 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5389 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5391 memset(ft_bitmap.buffer, 0, buflen);
5393 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5395 if (max_level != 255)
5397 for (row = 0, start = buf; row < height; row++)
5399 for (col = 0, ptr = start; col < width; col++, ptr++)
5400 *ptr = (((int)*ptr) * max_level + 128) / 256;
5401 start += pitch;
5404 return needed;
5407 default:
5408 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5409 return GDI_ERROR;
5411 break;
5414 case WINE_GGO_HRGB_BITMAP:
5415 case WINE_GGO_HBGR_BITMAP:
5416 case WINE_GGO_VRGB_BITMAP:
5417 case WINE_GGO_VBGR_BITMAP:
5418 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5420 switch (ft_face->glyph->format)
5422 case FT_GLYPH_FORMAT_BITMAP:
5424 BYTE *src, *dst;
5425 INT src_pitch, x;
5427 width = lpgm->gmBlackBoxX;
5428 height = lpgm->gmBlackBoxY;
5429 pitch = width * 4;
5430 needed = pitch * height;
5432 if (!buf || !buflen) break;
5434 memset(buf, 0, buflen);
5435 dst = buf;
5436 src = ft_face->glyph->bitmap.buffer;
5437 src_pitch = ft_face->glyph->bitmap.pitch;
5439 height = min( height, ft_face->glyph->bitmap.rows );
5440 while ( height-- )
5442 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5444 if ( src[x / 8] & masks[x % 8] )
5445 ((unsigned int *)dst)[x] = ~0u;
5447 src += src_pitch;
5448 dst += pitch;
5451 break;
5454 case FT_GLYPH_FORMAT_OUTLINE:
5456 unsigned int *dst;
5457 BYTE *src;
5458 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5459 INT x_shift, y_shift;
5460 BOOL rgb;
5461 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5462 FT_Render_Mode render_mode =
5463 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5464 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5466 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5468 if ( render_mode == FT_RENDER_MODE_LCD)
5470 lpgm->gmBlackBoxX += 2;
5471 lpgm->gmptGlyphOrigin.x -= 1;
5473 else
5475 lpgm->gmBlackBoxY += 2;
5476 lpgm->gmptGlyphOrigin.y += 1;
5480 width = lpgm->gmBlackBoxX;
5481 height = lpgm->gmBlackBoxY;
5482 pitch = width * 4;
5483 needed = pitch * height;
5485 if (!buf || !buflen) break;
5487 memset(buf, 0, buflen);
5488 dst = buf;
5489 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5491 if ( needsTransform )
5492 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5494 if ( pFT_Library_SetLcdFilter )
5495 pFT_Library_SetLcdFilter( library, lcdfilter );
5496 pFT_Render_Glyph (ft_face->glyph, render_mode);
5498 src = ft_face->glyph->bitmap.buffer;
5499 src_pitch = ft_face->glyph->bitmap.pitch;
5500 src_width = ft_face->glyph->bitmap.width;
5501 src_height = ft_face->glyph->bitmap.rows;
5503 if ( render_mode == FT_RENDER_MODE_LCD)
5505 rgb_interval = 1;
5506 hmul = 3;
5507 vmul = 1;
5509 else
5511 rgb_interval = src_pitch;
5512 hmul = 1;
5513 vmul = 3;
5516 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5517 if ( x_shift < 0 ) x_shift = 0;
5518 if ( x_shift + (src_width / hmul) > width )
5519 x_shift = width - (src_width / hmul);
5521 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5522 if ( y_shift < 0 ) y_shift = 0;
5523 if ( y_shift + (src_height / vmul) > height )
5524 y_shift = height - (src_height / vmul);
5526 dst += x_shift + y_shift * ( pitch / 4 );
5527 while ( src_height )
5529 for ( x = 0; x < src_width / hmul; x++ )
5531 if ( rgb )
5533 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5534 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5535 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5536 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5538 else
5540 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5541 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5542 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5543 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5546 src += src_pitch * vmul;
5547 dst += pitch / 4;
5548 src_height -= vmul;
5551 break;
5554 default:
5555 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5556 return GDI_ERROR;
5559 break;
5561 #else
5562 return GDI_ERROR;
5563 #endif
5565 case GGO_NATIVE:
5567 int contour, point = 0, first_pt;
5568 FT_Outline *outline = &ft_face->glyph->outline;
5569 TTPOLYGONHEADER *pph;
5570 TTPOLYCURVE *ppc;
5571 DWORD pph_start, cpfx, type;
5573 if(buflen == 0) buf = NULL;
5575 if (needsTransform && buf) {
5576 pFT_Outline_Transform(outline, &transMat);
5579 for(contour = 0; contour < outline->n_contours; contour++) {
5580 pph_start = needed;
5581 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5582 first_pt = point;
5583 if(buf) {
5584 pph->dwType = TT_POLYGON_TYPE;
5585 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5587 needed += sizeof(*pph);
5588 point++;
5589 while(point <= outline->contours[contour]) {
5590 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5591 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5592 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5593 cpfx = 0;
5594 do {
5595 if(buf)
5596 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5597 cpfx++;
5598 point++;
5599 } while(point <= outline->contours[contour] &&
5600 (outline->tags[point] & FT_Curve_Tag_On) ==
5601 (outline->tags[point-1] & FT_Curve_Tag_On));
5602 /* At the end of a contour Windows adds the start point, but
5603 only for Beziers */
5604 if(point > outline->contours[contour] &&
5605 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5606 if(buf)
5607 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5608 cpfx++;
5609 } else if(point <= outline->contours[contour] &&
5610 outline->tags[point] & FT_Curve_Tag_On) {
5611 /* add closing pt for bezier */
5612 if(buf)
5613 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5614 cpfx++;
5615 point++;
5617 if(buf) {
5618 ppc->wType = type;
5619 ppc->cpfx = cpfx;
5621 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5623 if(buf)
5624 pph->cb = needed - pph_start;
5626 break;
5628 case GGO_BEZIER:
5630 /* Convert the quadratic Beziers to cubic Beziers.
5631 The parametric eqn for a cubic Bezier is, from PLRM:
5632 r(t) = at^3 + bt^2 + ct + r0
5633 with the control points:
5634 r1 = r0 + c/3
5635 r2 = r1 + (c + b)/3
5636 r3 = r0 + c + b + a
5638 A quadratic Bezier has the form:
5639 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5641 So equating powers of t leads to:
5642 r1 = 2/3 p1 + 1/3 p0
5643 r2 = 2/3 p1 + 1/3 p2
5644 and of course r0 = p0, r3 = p2
5647 int contour, point = 0, first_pt;
5648 FT_Outline *outline = &ft_face->glyph->outline;
5649 TTPOLYGONHEADER *pph;
5650 TTPOLYCURVE *ppc;
5651 DWORD pph_start, cpfx, type;
5652 FT_Vector cubic_control[4];
5653 if(buflen == 0) buf = NULL;
5655 if (needsTransform && buf) {
5656 pFT_Outline_Transform(outline, &transMat);
5659 for(contour = 0; contour < outline->n_contours; contour++) {
5660 pph_start = needed;
5661 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5662 first_pt = point;
5663 if(buf) {
5664 pph->dwType = TT_POLYGON_TYPE;
5665 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5667 needed += sizeof(*pph);
5668 point++;
5669 while(point <= outline->contours[contour]) {
5670 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5671 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5672 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5673 cpfx = 0;
5674 do {
5675 if(type == TT_PRIM_LINE) {
5676 if(buf)
5677 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5678 cpfx++;
5679 point++;
5680 } else {
5681 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5682 so cpfx = 3n */
5684 /* FIXME: Possible optimization in endpoint calculation
5685 if there are two consecutive curves */
5686 cubic_control[0] = outline->points[point-1];
5687 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5688 cubic_control[0].x += outline->points[point].x + 1;
5689 cubic_control[0].y += outline->points[point].y + 1;
5690 cubic_control[0].x >>= 1;
5691 cubic_control[0].y >>= 1;
5693 if(point+1 > outline->contours[contour])
5694 cubic_control[3] = outline->points[first_pt];
5695 else {
5696 cubic_control[3] = outline->points[point+1];
5697 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5698 cubic_control[3].x += outline->points[point].x + 1;
5699 cubic_control[3].y += outline->points[point].y + 1;
5700 cubic_control[3].x >>= 1;
5701 cubic_control[3].y >>= 1;
5704 /* r1 = 1/3 p0 + 2/3 p1
5705 r2 = 1/3 p2 + 2/3 p1 */
5706 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5707 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5708 cubic_control[2] = cubic_control[1];
5709 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5710 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5711 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5712 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5713 if(buf) {
5714 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5715 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5716 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5718 cpfx += 3;
5719 point++;
5721 } while(point <= outline->contours[contour] &&
5722 (outline->tags[point] & FT_Curve_Tag_On) ==
5723 (outline->tags[point-1] & FT_Curve_Tag_On));
5724 /* At the end of a contour Windows adds the start point,
5725 but only for Beziers and we've already done that.
5727 if(point <= outline->contours[contour] &&
5728 outline->tags[point] & FT_Curve_Tag_On) {
5729 /* This is the closing pt of a bezier, but we've already
5730 added it, so just inc point and carry on */
5731 point++;
5733 if(buf) {
5734 ppc->wType = type;
5735 ppc->cpfx = cpfx;
5737 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5739 if(buf)
5740 pph->cb = needed - pph_start;
5742 break;
5745 default:
5746 FIXME("Unsupported format %d\n", format);
5747 return GDI_ERROR;
5749 return needed;
5752 static BOOL get_bitmap_text_metrics(GdiFont *font)
5754 FT_Face ft_face = font->ft_face;
5755 FT_WinFNT_HeaderRec winfnt_header;
5756 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5757 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5758 font->potm->otmSize = size;
5760 #define TM font->potm->otmTextMetrics
5761 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5763 TM.tmHeight = winfnt_header.pixel_height;
5764 TM.tmAscent = winfnt_header.ascent;
5765 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5766 TM.tmInternalLeading = winfnt_header.internal_leading;
5767 TM.tmExternalLeading = winfnt_header.external_leading;
5768 TM.tmAveCharWidth = winfnt_header.avg_width;
5769 TM.tmMaxCharWidth = winfnt_header.max_width;
5770 TM.tmWeight = winfnt_header.weight;
5771 TM.tmOverhang = 0;
5772 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5773 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5774 TM.tmFirstChar = winfnt_header.first_char;
5775 TM.tmLastChar = winfnt_header.last_char;
5776 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5777 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5778 TM.tmItalic = winfnt_header.italic;
5779 TM.tmUnderlined = font->underline;
5780 TM.tmStruckOut = font->strikeout;
5781 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5782 TM.tmCharSet = winfnt_header.charset;
5784 else
5786 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5787 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5788 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5789 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5790 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5791 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5792 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5793 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5794 TM.tmOverhang = 0;
5795 TM.tmDigitizedAspectX = 96; /* FIXME */
5796 TM.tmDigitizedAspectY = 96; /* FIXME */
5797 TM.tmFirstChar = 1;
5798 TM.tmLastChar = 255;
5799 TM.tmDefaultChar = 32;
5800 TM.tmBreakChar = 32;
5801 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5802 TM.tmUnderlined = font->underline;
5803 TM.tmStruckOut = font->strikeout;
5804 /* NB inverted meaning of TMPF_FIXED_PITCH */
5805 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5806 TM.tmCharSet = font->charset;
5808 #undef TM
5810 return TRUE;
5814 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5816 double scale_x, scale_y;
5818 if (font->aveWidth)
5820 scale_x = (double)font->aveWidth;
5821 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5823 else
5824 scale_x = font->scale_y;
5826 scale_x *= fabs(font->font_desc.matrix.eM11);
5827 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5829 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5830 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5832 SCALE_Y(ptm->tmHeight);
5833 SCALE_Y(ptm->tmAscent);
5834 SCALE_Y(ptm->tmDescent);
5835 SCALE_Y(ptm->tmInternalLeading);
5836 SCALE_Y(ptm->tmExternalLeading);
5837 SCALE_Y(ptm->tmOverhang);
5839 SCALE_X(ptm->tmAveCharWidth);
5840 SCALE_X(ptm->tmMaxCharWidth);
5842 #undef SCALE_X
5843 #undef SCALE_Y
5846 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5848 double scale_x, scale_y;
5850 if (font->aveWidth)
5852 scale_x = (double)font->aveWidth;
5853 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5855 else
5856 scale_x = font->scale_y;
5858 scale_x *= fabs(font->font_desc.matrix.eM11);
5859 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5861 scale_font_metrics(font, &potm->otmTextMetrics);
5863 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5864 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5866 SCALE_Y(potm->otmAscent);
5867 SCALE_Y(potm->otmDescent);
5868 SCALE_Y(potm->otmLineGap);
5869 SCALE_Y(potm->otmsCapEmHeight);
5870 SCALE_Y(potm->otmsXHeight);
5871 SCALE_Y(potm->otmrcFontBox.top);
5872 SCALE_Y(potm->otmrcFontBox.bottom);
5873 SCALE_X(potm->otmrcFontBox.left);
5874 SCALE_X(potm->otmrcFontBox.right);
5875 SCALE_Y(potm->otmMacAscent);
5876 SCALE_Y(potm->otmMacDescent);
5877 SCALE_Y(potm->otmMacLineGap);
5878 SCALE_X(potm->otmptSubscriptSize.x);
5879 SCALE_Y(potm->otmptSubscriptSize.y);
5880 SCALE_X(potm->otmptSubscriptOffset.x);
5881 SCALE_Y(potm->otmptSubscriptOffset.y);
5882 SCALE_X(potm->otmptSuperscriptSize.x);
5883 SCALE_Y(potm->otmptSuperscriptSize.y);
5884 SCALE_X(potm->otmptSuperscriptOffset.x);
5885 SCALE_Y(potm->otmptSuperscriptOffset.y);
5886 SCALE_Y(potm->otmsStrikeoutSize);
5887 SCALE_Y(potm->otmsStrikeoutPosition);
5888 SCALE_Y(potm->otmsUnderscoreSize);
5889 SCALE_Y(potm->otmsUnderscorePosition);
5891 #undef SCALE_X
5892 #undef SCALE_Y
5895 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
5897 if(!font->potm)
5899 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
5901 /* Make sure that the font has sane width/height ratio */
5902 if (font->aveWidth)
5904 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5906 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5907 font->aveWidth = 0;
5911 *ptm = font->potm->otmTextMetrics;
5912 scale_font_metrics(font, ptm);
5913 return TRUE;
5916 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5918 int i;
5920 for(i = 0; i < ft_face->num_charmaps; i++)
5922 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5923 return TRUE;
5925 return FALSE;
5928 static BOOL get_outline_text_metrics(GdiFont *font)
5930 BOOL ret = FALSE;
5931 FT_Face ft_face = font->ft_face;
5932 UINT needed, lenfam, lensty;
5933 TT_OS2 *pOS2;
5934 TT_HoriHeader *pHori;
5935 TT_Postscript *pPost;
5936 FT_Fixed x_scale, y_scale;
5937 WCHAR *family_nameW, *style_nameW;
5938 static const WCHAR spaceW[] = {' ', '\0'};
5939 char *cp;
5940 INT ascent, descent;
5942 TRACE("font=%p\n", font);
5944 if(!FT_IS_SCALABLE(ft_face))
5945 return FALSE;
5947 needed = sizeof(*font->potm);
5949 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5950 family_nameW = strdupW(font->name);
5952 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5953 * sizeof(WCHAR);
5954 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5955 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5956 style_nameW, lensty/sizeof(WCHAR));
5958 /* These names should be read from the TT name table */
5960 /* length of otmpFamilyName */
5961 needed += lenfam;
5963 /* length of otmpFaceName */
5964 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5965 needed += lenfam; /* just the family name */
5966 } else {
5967 needed += lenfam + lensty; /* family + " " + style */
5970 /* length of otmpStyleName */
5971 needed += lensty;
5973 /* length of otmpFullName */
5974 needed += lenfam + lensty;
5977 x_scale = ft_face->size->metrics.x_scale;
5978 y_scale = ft_face->size->metrics.y_scale;
5980 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5981 if(!pOS2) {
5982 FIXME("Can't find OS/2 table - not TT font?\n");
5983 goto end;
5986 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5987 if(!pHori) {
5988 FIXME("Can't find HHEA table - not TT font?\n");
5989 goto end;
5992 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5994 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",
5995 pOS2->usWinAscent, pOS2->usWinDescent,
5996 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5997 ft_face->ascender, ft_face->descender, ft_face->height,
5998 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5999 ft_face->bbox.yMax, ft_face->bbox.yMin);
6001 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6002 font->potm->otmSize = needed;
6004 #define TM font->potm->otmTextMetrics
6006 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6007 ascent = pHori->Ascender;
6008 descent = -pHori->Descender;
6009 } else {
6010 ascent = pOS2->usWinAscent;
6011 descent = pOS2->usWinDescent;
6014 if(font->yMax) {
6015 TM.tmAscent = font->yMax;
6016 TM.tmDescent = -font->yMin;
6017 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6018 } else {
6019 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6020 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6021 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6022 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6025 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6027 /* MSDN says:
6028 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6030 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6031 ((ascent + descent) -
6032 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6034 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6035 if (TM.tmAveCharWidth == 0) {
6036 TM.tmAveCharWidth = 1;
6038 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6039 TM.tmWeight = FW_REGULAR;
6040 if (font->fake_bold)
6041 TM.tmWeight = FW_BOLD;
6042 else
6044 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6046 if (pOS2->usWeightClass > FW_MEDIUM)
6047 TM.tmWeight = pOS2->usWeightClass;
6049 else if (pOS2->usWeightClass <= FW_MEDIUM)
6050 TM.tmWeight = pOS2->usWeightClass;
6052 TM.tmOverhang = 0;
6053 TM.tmDigitizedAspectX = 300;
6054 TM.tmDigitizedAspectY = 300;
6055 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6056 * symbol range to 0 - f0ff
6059 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6061 TM.tmFirstChar = 0;
6062 switch(GetACP())
6064 case 1257: /* Baltic */
6065 TM.tmLastChar = 0xf8fd;
6066 break;
6067 default:
6068 TM.tmLastChar = 0xf0ff;
6070 TM.tmBreakChar = 0x20;
6071 TM.tmDefaultChar = 0x1f;
6073 else
6075 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6076 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6078 if(pOS2->usFirstCharIndex <= 1)
6079 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6080 else if (pOS2->usFirstCharIndex > 0xff)
6081 TM.tmBreakChar = 0x20;
6082 else
6083 TM.tmBreakChar = pOS2->usFirstCharIndex;
6084 TM.tmDefaultChar = TM.tmBreakChar - 1;
6086 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6087 TM.tmUnderlined = font->underline;
6088 TM.tmStruckOut = font->strikeout;
6090 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6091 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6092 (pOS2->version == 0xFFFFU ||
6093 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6094 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6095 else
6096 TM.tmPitchAndFamily = 0;
6098 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6100 case PAN_FAMILY_SCRIPT:
6101 TM.tmPitchAndFamily |= FF_SCRIPT;
6102 break;
6104 case PAN_FAMILY_DECORATIVE:
6105 TM.tmPitchAndFamily |= FF_DECORATIVE;
6106 break;
6108 case PAN_ANY:
6109 case PAN_NO_FIT:
6110 case PAN_FAMILY_TEXT_DISPLAY:
6111 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6112 /* which is clearly not what the panose spec says. */
6113 default:
6114 if(TM.tmPitchAndFamily == 0 || /* fixed */
6115 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6116 TM.tmPitchAndFamily = FF_MODERN;
6117 else
6119 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6121 case PAN_ANY:
6122 case PAN_NO_FIT:
6123 default:
6124 TM.tmPitchAndFamily |= FF_DONTCARE;
6125 break;
6127 case PAN_SERIF_COVE:
6128 case PAN_SERIF_OBTUSE_COVE:
6129 case PAN_SERIF_SQUARE_COVE:
6130 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6131 case PAN_SERIF_SQUARE:
6132 case PAN_SERIF_THIN:
6133 case PAN_SERIF_BONE:
6134 case PAN_SERIF_EXAGGERATED:
6135 case PAN_SERIF_TRIANGLE:
6136 TM.tmPitchAndFamily |= FF_ROMAN;
6137 break;
6139 case PAN_SERIF_NORMAL_SANS:
6140 case PAN_SERIF_OBTUSE_SANS:
6141 case PAN_SERIF_PERP_SANS:
6142 case PAN_SERIF_FLARED:
6143 case PAN_SERIF_ROUNDED:
6144 TM.tmPitchAndFamily |= FF_SWISS;
6145 break;
6148 break;
6151 if(FT_IS_SCALABLE(ft_face))
6152 TM.tmPitchAndFamily |= TMPF_VECTOR;
6154 if(FT_IS_SFNT(ft_face))
6156 if (font->ntmFlags & NTM_PS_OPENTYPE)
6157 TM.tmPitchAndFamily |= TMPF_DEVICE;
6158 else
6159 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6162 TM.tmCharSet = font->charset;
6164 font->potm->otmFiller = 0;
6165 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6166 font->potm->otmfsSelection = pOS2->fsSelection;
6167 font->potm->otmfsType = pOS2->fsType;
6168 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6169 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6170 font->potm->otmItalicAngle = 0; /* POST table */
6171 font->potm->otmEMSquare = ft_face->units_per_EM;
6172 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6173 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6174 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6175 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6176 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6177 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6178 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6179 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6180 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6181 font->potm->otmMacAscent = TM.tmAscent;
6182 font->potm->otmMacDescent = -TM.tmDescent;
6183 font->potm->otmMacLineGap = font->potm->otmLineGap;
6184 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6185 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6186 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6187 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6188 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6189 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6190 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6191 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6192 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6193 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6194 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6195 if(!pPost) {
6196 font->potm->otmsUnderscoreSize = 0;
6197 font->potm->otmsUnderscorePosition = 0;
6198 } else {
6199 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6200 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6202 #undef TM
6204 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6205 cp = (char*)font->potm + sizeof(*font->potm);
6206 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6207 strcpyW((WCHAR*)cp, family_nameW);
6208 cp += lenfam;
6209 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6210 strcpyW((WCHAR*)cp, style_nameW);
6211 cp += lensty;
6212 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6213 strcpyW((WCHAR*)cp, family_nameW);
6214 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6215 strcatW((WCHAR*)cp, spaceW);
6216 strcatW((WCHAR*)cp, style_nameW);
6217 cp += lenfam + lensty;
6218 } else
6219 cp += lenfam;
6220 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6221 strcpyW((WCHAR*)cp, family_nameW);
6222 strcatW((WCHAR*)cp, spaceW);
6223 strcatW((WCHAR*)cp, style_nameW);
6224 ret = TRUE;
6226 end:
6227 HeapFree(GetProcessHeap(), 0, style_nameW);
6228 HeapFree(GetProcessHeap(), 0, family_nameW);
6229 return ret;
6232 /*************************************************************
6233 * freetype_GetGlyphOutline
6235 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6236 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6238 struct freetype_physdev *physdev = get_freetype_dev( dev );
6239 DWORD ret;
6241 if (!physdev->font)
6243 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6244 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6247 GDI_CheckNotLock();
6248 EnterCriticalSection( &freetype_cs );
6249 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6250 LeaveCriticalSection( &freetype_cs );
6251 return ret;
6254 /*************************************************************
6255 * freetype_GetTextMetrics
6257 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6259 struct freetype_physdev *physdev = get_freetype_dev( dev );
6260 BOOL ret;
6262 if (!physdev->font)
6264 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6265 return dev->funcs->pGetTextMetrics( dev, metrics );
6268 GDI_CheckNotLock();
6269 EnterCriticalSection( &freetype_cs );
6270 ret = get_text_metrics( physdev->font, metrics );
6271 LeaveCriticalSection( &freetype_cs );
6272 return ret;
6275 /*************************************************************
6276 * freetype_GetOutlineTextMetrics
6278 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6280 struct freetype_physdev *physdev = get_freetype_dev( dev );
6281 UINT ret = 0;
6283 if (!physdev->font)
6285 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6286 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6289 TRACE("font=%p\n", physdev->font);
6291 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6293 GDI_CheckNotLock();
6294 EnterCriticalSection( &freetype_cs );
6296 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6298 if(cbSize >= physdev->font->potm->otmSize)
6300 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6301 scale_outline_font_metrics(physdev->font, potm);
6303 ret = physdev->font->potm->otmSize;
6305 LeaveCriticalSection( &freetype_cs );
6306 return ret;
6309 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6311 HFONTLIST *hfontlist;
6312 child->font = alloc_font();
6313 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6314 if(!child->font->ft_face)
6316 free_font(child->font);
6317 child->font = NULL;
6318 return FALSE;
6321 child->font->font_desc = font->font_desc;
6322 child->font->ntmFlags = child->face->ntmFlags;
6323 child->font->orientation = font->orientation;
6324 child->font->scale_y = font->scale_y;
6325 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6326 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6327 child->font->name = strdupW(child->face->family->FamilyName);
6328 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6329 child->font->base_font = font;
6330 list_add_head(&child_font_list, &child->font->entry);
6331 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6332 return TRUE;
6335 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6337 FT_UInt g;
6338 CHILD_FONT *child_font;
6340 if(font->base_font)
6341 font = font->base_font;
6343 *linked_font = font;
6345 if((*glyph = get_glyph_index(font, c)))
6346 return TRUE;
6348 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6350 if(!child_font->font)
6351 if(!load_child_font(font, child_font))
6352 continue;
6354 if(!child_font->font->ft_face)
6355 continue;
6356 g = get_glyph_index(child_font->font, c);
6357 if(g)
6359 *glyph = g;
6360 *linked_font = child_font->font;
6361 return TRUE;
6364 return FALSE;
6367 /*************************************************************
6368 * freetype_GetCharWidth
6370 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6372 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6373 UINT c;
6374 GLYPHMETRICS gm;
6375 FT_UInt glyph_index;
6376 GdiFont *linked_font;
6377 struct freetype_physdev *physdev = get_freetype_dev( dev );
6379 if (!physdev->font)
6381 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6382 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6385 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6387 GDI_CheckNotLock();
6388 EnterCriticalSection( &freetype_cs );
6389 for(c = firstChar; c <= lastChar; c++) {
6390 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6391 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6392 &gm, 0, NULL, &identity);
6393 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6395 LeaveCriticalSection( &freetype_cs );
6396 return TRUE;
6399 /*************************************************************
6400 * freetype_GetCharABCWidths
6402 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6404 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6405 UINT c;
6406 GLYPHMETRICS gm;
6407 FT_UInt glyph_index;
6408 GdiFont *linked_font;
6409 struct freetype_physdev *physdev = get_freetype_dev( dev );
6411 if (!physdev->font)
6413 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6414 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6417 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6419 GDI_CheckNotLock();
6420 EnterCriticalSection( &freetype_cs );
6422 for(c = firstChar; c <= lastChar; c++) {
6423 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6424 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6425 &gm, 0, NULL, &identity);
6426 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6427 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6428 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6429 FONT_GM(linked_font,glyph_index)->bbx;
6431 LeaveCriticalSection( &freetype_cs );
6432 return TRUE;
6435 /*************************************************************
6436 * freetype_GetCharABCWidthsI
6438 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6440 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6441 UINT c;
6442 GLYPHMETRICS gm;
6443 FT_UInt glyph_index;
6444 GdiFont *linked_font;
6445 struct freetype_physdev *physdev = get_freetype_dev( dev );
6447 if (!physdev->font)
6449 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6450 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6453 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6454 return FALSE;
6456 GDI_CheckNotLock();
6457 EnterCriticalSection( &freetype_cs );
6459 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6460 if (!pgi)
6461 for(c = firstChar; c < firstChar+count; c++) {
6462 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6463 &gm, 0, NULL, &identity);
6464 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6465 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6466 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6467 - FONT_GM(linked_font,c)->bbx;
6469 else
6470 for(c = 0; c < count; c++) {
6471 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6472 &gm, 0, NULL, &identity);
6473 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6474 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6475 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6476 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6479 LeaveCriticalSection( &freetype_cs );
6480 return TRUE;
6483 /*************************************************************
6484 * freetype_GetTextExtentExPoint
6486 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6487 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6489 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6490 INT idx;
6491 INT nfit = 0, ext;
6492 GLYPHMETRICS gm;
6493 TEXTMETRICW tm;
6494 FT_UInt glyph_index;
6495 GdiFont *linked_font;
6496 struct freetype_physdev *physdev = get_freetype_dev( dev );
6498 if (!physdev->font)
6500 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6501 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6504 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6506 GDI_CheckNotLock();
6507 EnterCriticalSection( &freetype_cs );
6509 size->cx = 0;
6510 get_text_metrics( physdev->font, &tm );
6511 size->cy = tm.tmHeight;
6513 for(idx = 0; idx < count; idx++) {
6514 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6515 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6516 &gm, 0, NULL, &identity);
6517 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6518 ext = size->cx;
6519 if (! pnfit || ext <= max_ext) {
6520 ++nfit;
6521 if (dxs)
6522 dxs[idx] = ext;
6526 if (pnfit)
6527 *pnfit = nfit;
6529 LeaveCriticalSection( &freetype_cs );
6530 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6531 return TRUE;
6534 /*************************************************************
6535 * freetype_GetTextExtentExPointI
6537 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
6538 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
6540 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6541 INT idx;
6542 INT nfit = 0, ext;
6543 GLYPHMETRICS gm;
6544 TEXTMETRICW tm;
6545 struct freetype_physdev *physdev = get_freetype_dev( dev );
6547 if (!physdev->font)
6549 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
6550 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
6553 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
6555 GDI_CheckNotLock();
6556 EnterCriticalSection( &freetype_cs );
6558 size->cx = 0;
6559 get_text_metrics(physdev->font, &tm);
6560 size->cy = tm.tmHeight;
6562 for(idx = 0; idx < count; idx++) {
6563 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6564 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
6565 ext = size->cx;
6566 if (! pnfit || ext <= max_ext) {
6567 ++nfit;
6568 if (dxs)
6569 dxs[idx] = ext;
6573 if (pnfit)
6574 *pnfit = nfit;
6576 LeaveCriticalSection( &freetype_cs );
6577 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6578 return TRUE;
6581 /*************************************************************
6582 * freetype_GetFontData
6584 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
6586 struct freetype_physdev *physdev = get_freetype_dev( dev );
6588 if (!physdev->font)
6590 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
6591 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
6594 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6595 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6596 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6598 return get_font_data( physdev->font, table, offset, buf, cbData );
6601 /*************************************************************
6602 * freetype_GetTextFace
6604 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
6606 INT n;
6607 struct freetype_physdev *physdev = get_freetype_dev( dev );
6609 if (!physdev->font)
6611 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
6612 return dev->funcs->pGetTextFace( dev, count, str );
6615 n = strlenW(physdev->font->name) + 1;
6616 if (str)
6618 lstrcpynW(str, physdev->font->name, count);
6619 n = min(count, n);
6621 return n;
6624 /*************************************************************
6625 * freetype_GetTextCharsetInfo
6627 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
6629 struct freetype_physdev *physdev = get_freetype_dev( dev );
6631 if (!physdev->font)
6633 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
6634 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
6636 if (fs) *fs = physdev->font->fs;
6637 return physdev->font->charset;
6640 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6642 GdiFont *font = dc->gdiFont, *linked_font;
6643 struct list *first_hfont;
6644 BOOL ret;
6646 GDI_CheckNotLock();
6647 EnterCriticalSection( &freetype_cs );
6648 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6649 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6650 if(font == linked_font)
6651 *new_hfont = dc->hFont;
6652 else
6654 first_hfont = list_head(&linked_font->hfontlist);
6655 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6657 LeaveCriticalSection( &freetype_cs );
6658 return ret;
6661 /* Retrieve a list of supported Unicode ranges for a given font.
6662 * Can be called with NULL gs to calculate the buffer size. Returns
6663 * the number of ranges found.
6665 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6667 DWORD num_ranges = 0;
6669 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6671 FT_UInt glyph_code;
6672 FT_ULong char_code, char_code_prev;
6674 glyph_code = 0;
6675 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6677 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6678 face->num_glyphs, glyph_code, char_code);
6680 if (!glyph_code) return 0;
6682 if (gs)
6684 gs->ranges[0].wcLow = (USHORT)char_code;
6685 gs->ranges[0].cGlyphs = 0;
6686 gs->cGlyphsSupported = 0;
6689 num_ranges = 1;
6690 while (glyph_code)
6692 if (char_code < char_code_prev)
6694 ERR("expected increasing char code from FT_Get_Next_Char\n");
6695 return 0;
6697 if (char_code - char_code_prev > 1)
6699 num_ranges++;
6700 if (gs)
6702 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6703 gs->ranges[num_ranges - 1].cGlyphs = 1;
6704 gs->cGlyphsSupported++;
6707 else if (gs)
6709 gs->ranges[num_ranges - 1].cGlyphs++;
6710 gs->cGlyphsSupported++;
6712 char_code_prev = char_code;
6713 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6716 else
6717 FIXME("encoding %u not supported\n", face->charmap->encoding);
6719 return num_ranges;
6722 /*************************************************************
6723 * freetype_GetFontUnicodeRanges
6725 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
6727 struct freetype_physdev *physdev = get_freetype_dev( dev );
6728 DWORD size, num_ranges;
6730 if (!physdev->font)
6732 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
6733 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
6736 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
6737 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6738 if (glyphset)
6740 glyphset->cbThis = size;
6741 glyphset->cRanges = num_ranges;
6742 glyphset->flAccel = 0;
6744 return size;
6747 /*************************************************************
6748 * freetype_FontIsLinked
6750 static BOOL freetype_FontIsLinked( PHYSDEV dev )
6752 struct freetype_physdev *physdev = get_freetype_dev( dev );
6753 BOOL ret;
6755 if (!physdev->font)
6757 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
6758 return dev->funcs->pFontIsLinked( dev );
6761 GDI_CheckNotLock();
6762 EnterCriticalSection( &freetype_cs );
6763 ret = !list_empty(&physdev->font->child_fonts);
6764 LeaveCriticalSection( &freetype_cs );
6765 return ret;
6768 static BOOL is_hinting_enabled(void)
6770 /* Use the >= 2.2.0 function if available */
6771 if(pFT_Get_TrueType_Engine_Type)
6773 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6774 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6776 #ifdef FT_DRIVER_HAS_HINTER
6777 else
6779 FT_Module mod;
6781 /* otherwise if we've been compiled with < 2.2.0 headers
6782 use the internal macro */
6783 mod = pFT_Get_Module(library, "truetype");
6784 if(mod && FT_DRIVER_HAS_HINTER(mod))
6785 return TRUE;
6787 #endif
6789 return FALSE;
6792 static BOOL is_subpixel_rendering_enabled( void )
6794 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6795 return pFT_Library_SetLcdFilter &&
6796 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6797 #else
6798 return FALSE;
6799 #endif
6802 /*************************************************************************
6803 * GetRasterizerCaps (GDI32.@)
6805 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6807 static int hinting = -1;
6808 static int subpixel = -1;
6810 if(hinting == -1)
6812 hinting = is_hinting_enabled();
6813 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6816 if ( subpixel == -1 )
6818 subpixel = is_subpixel_rendering_enabled();
6819 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6822 lprs->nSize = sizeof(RASTERIZER_STATUS);
6823 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6824 if ( subpixel )
6825 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6826 lprs->nLanguageID = 0;
6827 return TRUE;
6830 /*************************************************************
6831 * freetype_GdiRealizationInfo
6833 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
6835 struct freetype_physdev *physdev = get_freetype_dev( dev );
6836 realization_info_t *info = ptr;
6838 if (!physdev->font)
6840 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
6841 return dev->funcs->pGdiRealizationInfo( dev, ptr );
6844 FIXME("(%p, %p): stub!\n", physdev->font, info);
6846 info->flags = 1;
6847 if(FT_IS_SCALABLE(physdev->font->ft_face))
6848 info->flags |= 2;
6850 info->cache_num = physdev->font->cache_num;
6851 info->unknown2 = -1;
6852 return TRUE;
6855 /*************************************************************************
6856 * Kerning support for TrueType fonts
6858 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6860 struct TT_kern_table
6862 USHORT version;
6863 USHORT nTables;
6866 struct TT_kern_subtable
6868 USHORT version;
6869 USHORT length;
6870 union
6872 USHORT word;
6873 struct
6875 USHORT horizontal : 1;
6876 USHORT minimum : 1;
6877 USHORT cross_stream: 1;
6878 USHORT override : 1;
6879 USHORT reserved1 : 4;
6880 USHORT format : 8;
6881 } bits;
6882 } coverage;
6885 struct TT_format0_kern_subtable
6887 USHORT nPairs;
6888 USHORT searchRange;
6889 USHORT entrySelector;
6890 USHORT rangeShift;
6893 struct TT_kern_pair
6895 USHORT left;
6896 USHORT right;
6897 short value;
6900 static DWORD parse_format0_kern_subtable(GdiFont *font,
6901 const struct TT_format0_kern_subtable *tt_f0_ks,
6902 const USHORT *glyph_to_char,
6903 KERNINGPAIR *kern_pair, DWORD cPairs)
6905 USHORT i, nPairs;
6906 const struct TT_kern_pair *tt_kern_pair;
6908 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6910 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6912 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6913 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6914 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6916 if (!kern_pair || !cPairs)
6917 return nPairs;
6919 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6921 nPairs = min(nPairs, cPairs);
6923 for (i = 0; i < nPairs; i++)
6925 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6926 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6927 /* this algorithm appears to better match what Windows does */
6928 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6929 if (kern_pair->iKernAmount < 0)
6931 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6932 kern_pair->iKernAmount -= font->ppem;
6934 else if (kern_pair->iKernAmount > 0)
6936 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6937 kern_pair->iKernAmount += font->ppem;
6939 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6941 TRACE("left %u right %u value %d\n",
6942 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6944 kern_pair++;
6946 TRACE("copied %u entries\n", nPairs);
6947 return nPairs;
6950 /*************************************************************
6951 * freetype_GetKerningPairs
6953 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
6955 DWORD length;
6956 void *buf;
6957 const struct TT_kern_table *tt_kern_table;
6958 const struct TT_kern_subtable *tt_kern_subtable;
6959 USHORT i, nTables;
6960 USHORT *glyph_to_char;
6961 GdiFont *font;
6962 struct freetype_physdev *physdev = get_freetype_dev( dev );
6964 if (!(font = physdev->font))
6966 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
6967 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
6970 GDI_CheckNotLock();
6971 EnterCriticalSection( &freetype_cs );
6972 if (font->total_kern_pairs != (DWORD)-1)
6974 if (cPairs && kern_pair)
6976 cPairs = min(cPairs, font->total_kern_pairs);
6977 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6979 else cPairs = font->total_kern_pairs;
6981 LeaveCriticalSection( &freetype_cs );
6982 return cPairs;
6985 font->total_kern_pairs = 0;
6987 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
6989 if (length == GDI_ERROR)
6991 TRACE("no kerning data in the font\n");
6992 LeaveCriticalSection( &freetype_cs );
6993 return 0;
6996 buf = HeapAlloc(GetProcessHeap(), 0, length);
6997 if (!buf)
6999 WARN("Out of memory\n");
7000 LeaveCriticalSection( &freetype_cs );
7001 return 0;
7004 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7006 /* build a glyph index to char code map */
7007 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7008 if (!glyph_to_char)
7010 WARN("Out of memory allocating a glyph index to char code map\n");
7011 HeapFree(GetProcessHeap(), 0, buf);
7012 LeaveCriticalSection( &freetype_cs );
7013 return 0;
7016 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7018 FT_UInt glyph_code;
7019 FT_ULong char_code;
7021 glyph_code = 0;
7022 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7024 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7025 font->ft_face->num_glyphs, glyph_code, char_code);
7027 while (glyph_code)
7029 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7031 /* FIXME: This doesn't match what Windows does: it does some fancy
7032 * things with duplicate glyph index to char code mappings, while
7033 * we just avoid overriding existing entries.
7035 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7036 glyph_to_char[glyph_code] = (USHORT)char_code;
7038 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7041 else
7043 ULONG n;
7045 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7046 for (n = 0; n <= 65535; n++)
7047 glyph_to_char[n] = (USHORT)n;
7050 tt_kern_table = buf;
7051 nTables = GET_BE_WORD(tt_kern_table->nTables);
7052 TRACE("version %u, nTables %u\n",
7053 GET_BE_WORD(tt_kern_table->version), nTables);
7055 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7057 for (i = 0; i < nTables; i++)
7059 struct TT_kern_subtable tt_kern_subtable_copy;
7061 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7062 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7063 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7065 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7066 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7067 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7069 /* According to the TrueType specification this is the only format
7070 * that will be properly interpreted by Windows and OS/2
7072 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7074 DWORD new_chunk, old_total = font->total_kern_pairs;
7076 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7077 glyph_to_char, NULL, 0);
7078 font->total_kern_pairs += new_chunk;
7080 if (!font->kern_pairs)
7081 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7082 font->total_kern_pairs * sizeof(*font->kern_pairs));
7083 else
7084 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7085 font->total_kern_pairs * sizeof(*font->kern_pairs));
7087 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7088 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7090 else
7091 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7093 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7096 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7097 HeapFree(GetProcessHeap(), 0, buf);
7099 if (cPairs && kern_pair)
7101 cPairs = min(cPairs, font->total_kern_pairs);
7102 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7104 else cPairs = font->total_kern_pairs;
7106 LeaveCriticalSection( &freetype_cs );
7107 return cPairs;
7110 static const struct gdi_dc_funcs freetype_funcs =
7112 NULL, /* pAbortDoc */
7113 NULL, /* pAbortPath */
7114 NULL, /* pAlphaBlend */
7115 NULL, /* pAngleArc */
7116 NULL, /* pArc */
7117 NULL, /* pArcTo */
7118 NULL, /* pBeginPath */
7119 NULL, /* pBlendImage */
7120 NULL, /* pChoosePixelFormat */
7121 NULL, /* pChord */
7122 NULL, /* pCloseFigure */
7123 NULL, /* pCopyBitmap */
7124 NULL, /* pCreateBitmap */
7125 NULL, /* pCreateCompatibleDC */
7126 freetype_CreateDC, /* pCreateDC */
7127 NULL, /* pCreateDIBSection */
7128 NULL, /* pDeleteBitmap */
7129 freetype_DeleteDC, /* pDeleteDC */
7130 NULL, /* pDeleteObject */
7131 NULL, /* pDescribePixelFormat */
7132 NULL, /* pDeviceCapabilities */
7133 NULL, /* pEllipse */
7134 NULL, /* pEndDoc */
7135 NULL, /* pEndPage */
7136 NULL, /* pEndPath */
7137 freetype_EnumFonts, /* pEnumFonts */
7138 NULL, /* pEnumICMProfiles */
7139 NULL, /* pExcludeClipRect */
7140 NULL, /* pExtDeviceMode */
7141 NULL, /* pExtEscape */
7142 NULL, /* pExtFloodFill */
7143 NULL, /* pExtSelectClipRgn */
7144 NULL, /* pExtTextOut */
7145 NULL, /* pFillPath */
7146 NULL, /* pFillRgn */
7147 NULL, /* pFlattenPath */
7148 freetype_FontIsLinked, /* pFontIsLinked */
7149 NULL, /* pFrameRgn */
7150 NULL, /* pGdiComment */
7151 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7152 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7153 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7154 freetype_GetCharWidth, /* pGetCharWidth */
7155 NULL, /* pGetDeviceCaps */
7156 NULL, /* pGetDeviceGammaRamp */
7157 freetype_GetFontData, /* pGetFontData */
7158 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7159 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7160 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7161 NULL, /* pGetICMProfile */
7162 NULL, /* pGetImage */
7163 freetype_GetKerningPairs, /* pGetKerningPairs */
7164 NULL, /* pGetNearestColor */
7165 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7166 NULL, /* pGetPixel */
7167 NULL, /* pGetPixelFormat */
7168 NULL, /* pGetSystemPaletteEntries */
7169 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7170 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7171 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7172 freetype_GetTextFace, /* pGetTextFace */
7173 freetype_GetTextMetrics, /* pGetTextMetrics */
7174 NULL, /* pGradientFill */
7175 NULL, /* pIntersectClipRect */
7176 NULL, /* pInvertRgn */
7177 NULL, /* pLineTo */
7178 NULL, /* pModifyWorldTransform */
7179 NULL, /* pMoveTo */
7180 NULL, /* pOffsetClipRgn */
7181 NULL, /* pOffsetViewportOrg */
7182 NULL, /* pOffsetWindowOrg */
7183 NULL, /* pPaintRgn */
7184 NULL, /* pPatBlt */
7185 NULL, /* pPie */
7186 NULL, /* pPolyBezier */
7187 NULL, /* pPolyBezierTo */
7188 NULL, /* pPolyDraw */
7189 NULL, /* pPolyPolygon */
7190 NULL, /* pPolyPolyline */
7191 NULL, /* pPolygon */
7192 NULL, /* pPolyline */
7193 NULL, /* pPolylineTo */
7194 NULL, /* pPutImage */
7195 NULL, /* pRealizeDefaultPalette */
7196 NULL, /* pRealizePalette */
7197 NULL, /* pRectangle */
7198 NULL, /* pResetDC */
7199 NULL, /* pRestoreDC */
7200 NULL, /* pRoundRect */
7201 NULL, /* pSaveDC */
7202 NULL, /* pScaleViewportExt */
7203 NULL, /* pScaleWindowExt */
7204 NULL, /* pSelectBitmap */
7205 NULL, /* pSelectBrush */
7206 NULL, /* pSelectClipPath */
7207 freetype_SelectFont, /* pSelectFont */
7208 NULL, /* pSelectPalette */
7209 NULL, /* pSelectPen */
7210 NULL, /* pSetArcDirection */
7211 NULL, /* pSetBkColor */
7212 NULL, /* pSetBkMode */
7213 NULL, /* pSetDCBrushColor */
7214 NULL, /* pSetDCPenColor */
7215 NULL, /* pSetDIBColorTable */
7216 NULL, /* pSetDIBitsToDevice */
7217 NULL, /* pSetDeviceClipping */
7218 NULL, /* pSetDeviceGammaRamp */
7219 NULL, /* pSetLayout */
7220 NULL, /* pSetMapMode */
7221 NULL, /* pSetMapperFlags */
7222 NULL, /* pSetPixel */
7223 NULL, /* pSetPixelFormat */
7224 NULL, /* pSetPolyFillMode */
7225 NULL, /* pSetROP2 */
7226 NULL, /* pSetRelAbs */
7227 NULL, /* pSetStretchBltMode */
7228 NULL, /* pSetTextAlign */
7229 NULL, /* pSetTextCharacterExtra */
7230 NULL, /* pSetTextColor */
7231 NULL, /* pSetTextJustification */
7232 NULL, /* pSetViewportExt */
7233 NULL, /* pSetViewportOrg */
7234 NULL, /* pSetWindowExt */
7235 NULL, /* pSetWindowOrg */
7236 NULL, /* pSetWorldTransform */
7237 NULL, /* pStartDoc */
7238 NULL, /* pStartPage */
7239 NULL, /* pStretchBlt */
7240 NULL, /* pStretchDIBits */
7241 NULL, /* pStrokeAndFillPath */
7242 NULL, /* pStrokePath */
7243 NULL, /* pSwapBuffers */
7244 NULL, /* pUnrealizePalette */
7245 NULL, /* pWidenPath */
7246 /* OpenGL not supported */
7249 #else /* HAVE_FREETYPE */
7251 /*************************************************************************/
7253 BOOL WineEngInit(void)
7255 return FALSE;
7257 BOOL WineEngDestroyFontInstance(HFONT hfont)
7259 return FALSE;
7262 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7264 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7265 return 1;
7268 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7270 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7271 return TRUE;
7274 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7276 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7277 return NULL;
7280 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7282 return FALSE;
7285 /*************************************************************************
7286 * GetRasterizerCaps (GDI32.@)
7288 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7290 lprs->nSize = sizeof(RASTERIZER_STATUS);
7291 lprs->wFlags = 0;
7292 lprs->nLanguageID = 0;
7293 return TRUE;
7296 #endif /* HAVE_FREETYPE */