gdi32: Simplify list processing by using the LIST_FOR_EACH_ENTRY macro.
[wine.git] / dlls / gdi32 / freetype.c
blob5cf34ca88441420301676aa7d6a047a7fd10950a
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(FcConfigSubstitute);
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(FcPatternGetInteger);
205 MAKE_FUNCPTR(FcPatternGetString);
206 #endif
208 #undef MAKE_FUNCPTR
210 #ifndef FT_MAKE_TAG
211 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
212 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
213 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
214 #endif
216 #ifndef ft_encoding_none
217 #define FT_ENCODING_NONE ft_encoding_none
218 #endif
219 #ifndef ft_encoding_ms_symbol
220 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
221 #endif
222 #ifndef ft_encoding_unicode
223 #define FT_ENCODING_UNICODE ft_encoding_unicode
224 #endif
225 #ifndef ft_encoding_apple_roman
226 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
227 #endif
229 #ifdef WORDS_BIGENDIAN
230 #define GET_BE_WORD(x) (x)
231 #else
232 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
233 #endif
235 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
236 typedef struct {
237 FT_Short height;
238 FT_Short width;
239 FT_Pos size;
240 FT_Pos x_ppem;
241 FT_Pos y_ppem;
242 FT_Short internal_leading;
243 } Bitmap_Size;
245 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
246 So to let this compile on older versions of FreeType we'll define the
247 new structure here. */
248 typedef struct {
249 FT_Short height, width;
250 FT_Pos size, x_ppem, y_ppem;
251 } My_FT_Bitmap_Size;
253 struct enum_data
255 ENUMLOGFONTEXW elf;
256 NEWTEXTMETRICEXW ntm;
257 DWORD type;
260 typedef struct tagFace {
261 struct list entry;
262 WCHAR *StyleName;
263 WCHAR *FullName;
264 WCHAR *file;
265 void *font_data_ptr;
266 DWORD font_data_size;
267 FT_Long face_index;
268 FONTSIGNATURE fs;
269 DWORD ntmFlags;
270 FT_Fixed font_version;
271 BOOL scalable;
272 BOOL vertical;
273 Bitmap_Size size; /* set if face is a bitmap */
274 BOOL external; /* TRUE if we should manually add this font to the registry */
275 DWORD aa_flags;
276 struct tagFamily *family;
277 /* Cached data for Enum */
278 struct enum_data *cached_enum_data;
279 } Face;
281 typedef struct tagFamily {
282 struct list entry;
283 WCHAR *FamilyName;
284 WCHAR *EnglishName;
285 struct list faces;
286 struct list *replacement;
287 } Family;
289 typedef struct {
290 GLYPHMETRICS gm;
291 ABC abc; /* metrics of the unrotated char */
292 BOOL init;
293 } GM;
295 typedef struct {
296 FLOAT eM11, eM12;
297 FLOAT eM21, eM22;
298 } FMAT2;
300 typedef struct {
301 DWORD hash;
302 LOGFONTW lf;
303 FMAT2 matrix;
304 BOOL can_use_bitmap;
305 } FONT_DESC;
307 typedef struct tagHFONTLIST {
308 struct list entry;
309 HFONT hfont;
310 } HFONTLIST;
312 typedef struct tagGdiFont GdiFont;
314 typedef struct {
315 struct list entry;
316 Face *face;
317 GdiFont *font;
318 } CHILD_FONT;
320 struct tagGdiFont {
321 struct list entry;
322 GM **gm;
323 DWORD gmsize;
324 struct list hfontlist;
325 OUTLINETEXTMETRICW *potm;
326 DWORD total_kern_pairs;
327 KERNINGPAIR *kern_pairs;
328 struct list child_fonts;
330 /* the following members can be accessed without locking, they are never modified after creation */
331 FT_Face ft_face;
332 struct font_mapping *mapping;
333 LPWSTR name;
334 int charset;
335 int codepage;
336 BOOL fake_italic;
337 BOOL fake_bold;
338 BYTE underline;
339 BYTE strikeout;
340 INT orientation;
341 FONT_DESC font_desc;
342 LONG aveWidth, ppem;
343 double scale_y;
344 SHORT yMax;
345 SHORT yMin;
346 DWORD ntmFlags;
347 DWORD aa_flags;
348 UINT ntmCellHeight, ntmAvgWidth;
349 FONTSIGNATURE fs;
350 GdiFont *base_font;
351 VOID *GSUB_Table;
352 DWORD cache_num;
355 typedef struct {
356 struct list entry;
357 const WCHAR *font_name;
358 FONTSIGNATURE fs;
359 struct list links;
360 } SYSTEM_LINKS;
362 struct enum_charset_element {
363 DWORD mask;
364 DWORD charset;
365 WCHAR name[LF_FACESIZE];
368 struct enum_charset_list {
369 DWORD total;
370 struct enum_charset_element element[32];
373 #define GM_BLOCK_SIZE 128
374 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
376 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
377 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
378 #define UNUSED_CACHE_SIZE 10
379 static struct list system_links = LIST_INIT(system_links);
381 static struct list font_subst_list = LIST_INIT(font_subst_list);
383 static struct list font_list = LIST_INIT(font_list);
385 struct freetype_physdev
387 struct gdi_physdev dev;
388 GdiFont *font;
391 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
393 return (struct freetype_physdev *)dev;
396 static const struct gdi_dc_funcs freetype_funcs;
398 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
399 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
400 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
402 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
403 static const WCHAR win9x_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','\\',
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 winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
409 'W','i','n','d','o','w','s',' ','N','T','\\',
410 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
411 'F','o','n','t','s','\0'};
413 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
414 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
415 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
416 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
418 static const WCHAR * const SystemFontValues[] = {
419 System_Value,
420 OEMFont_Value,
421 FixedSys_Value,
422 NULL
425 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
426 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
428 /* Interesting and well-known (frequently-assumed!) font names */
429 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
430 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 };
431 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
432 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
433 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
434 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
435 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
436 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
438 static const WCHAR arial[] = {'A','r','i','a','l',0};
439 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
440 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};
441 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};
442 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
443 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
444 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
445 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
446 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
447 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
449 static const WCHAR *default_serif_list[] =
451 times_new_roman,
452 liberation_serif,
453 bitstream_vera_serif,
454 NULL
457 static const WCHAR *default_fixed_list[] =
459 courier_new,
460 liberation_mono,
461 bitstream_vera_sans_mono,
462 NULL
465 static const WCHAR *default_sans_list[] =
467 arial,
468 liberation_sans,
469 bitstream_vera_sans,
470 NULL
473 typedef struct {
474 WCHAR *name;
475 INT charset;
476 } NameCs;
478 typedef struct tagFontSubst {
479 struct list entry;
480 NameCs from;
481 NameCs to;
482 } FontSubst;
484 /* Registry font cache key and value names */
485 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
486 'F','o','n','t','s',0};
487 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
488 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
489 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
490 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
491 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
492 static const WCHAR face_vertical_value[] = {'V','e','r','t','i','c','a','l',0};
493 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
494 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
495 static const WCHAR face_size_value[] = {'S','i','z','e',0};
496 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
497 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
498 static const WCHAR face_aa_value[] = {'A','n','t','i','a','l','i','a','s','i','n','g',0};
499 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
500 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
501 static const WCHAR face_file_name_value[] = {'F','i','l','e',' ','N','a','m','e','\0'};
502 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
505 struct font_mapping
507 struct list entry;
508 int refcount;
509 dev_t dev;
510 ino_t ino;
511 void *data;
512 size_t size;
515 static struct list mappings_list = LIST_INIT( mappings_list );
517 static UINT default_aa_flags;
519 static CRITICAL_SECTION freetype_cs;
520 static CRITICAL_SECTION_DEBUG critsect_debug =
522 0, 0, &freetype_cs,
523 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
524 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
526 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
528 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
530 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
531 static BOOL use_default_fallback = FALSE;
533 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
534 static BOOL get_outline_text_metrics(GdiFont *font);
535 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
537 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
538 'W','i','n','d','o','w','s',' ','N','T','\\',
539 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
540 'S','y','s','t','e','m','L','i','n','k',0};
542 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
543 'F','o','n','t','L','i','n','k','\\',
544 'S','y','s','t','e','m','L','i','n','k',0};
546 /****************************************
547 * Notes on .fon files
549 * The fonts System, FixedSys and Terminal are special. There are typically multiple
550 * versions installed for different resolutions and codepages. Windows stores which one to use
551 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
552 * Key Meaning
553 * FIXEDFON.FON FixedSys
554 * FONTS.FON System
555 * OEMFONT.FON Terminal
556 * LogPixels Current dpi set by the display control panel applet
557 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
558 * also has a LogPixels value that appears to mirror this)
560 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
561 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
562 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
563 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
564 * so that makes sense.
566 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
567 * to be mapped into the registry on Windows 2000 at least).
568 * I have
569 * woafont=app850.fon
570 * ega80woa.fon=ega80850.fon
571 * ega40woa.fon=ega40850.fon
572 * cga80woa.fon=cga80850.fon
573 * cga40woa.fon=cga40850.fon
576 /* These are all structures needed for the GSUB table */
578 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
579 #define TATEGAKI_LOWER_BOUND 0x02F1
581 typedef struct {
582 DWORD version;
583 WORD ScriptList;
584 WORD FeatureList;
585 WORD LookupList;
586 } GSUB_Header;
588 typedef struct {
589 CHAR ScriptTag[4];
590 WORD Script;
591 } GSUB_ScriptRecord;
593 typedef struct {
594 WORD ScriptCount;
595 GSUB_ScriptRecord ScriptRecord[1];
596 } GSUB_ScriptList;
598 typedef struct {
599 CHAR LangSysTag[4];
600 WORD LangSys;
601 } GSUB_LangSysRecord;
603 typedef struct {
604 WORD DefaultLangSys;
605 WORD LangSysCount;
606 GSUB_LangSysRecord LangSysRecord[1];
607 } GSUB_Script;
609 typedef struct {
610 WORD LookupOrder; /* Reserved */
611 WORD ReqFeatureIndex;
612 WORD FeatureCount;
613 WORD FeatureIndex[1];
614 } GSUB_LangSys;
616 typedef struct {
617 CHAR FeatureTag[4];
618 WORD Feature;
619 } GSUB_FeatureRecord;
621 typedef struct {
622 WORD FeatureCount;
623 GSUB_FeatureRecord FeatureRecord[1];
624 } GSUB_FeatureList;
626 typedef struct {
627 WORD FeatureParams; /* Reserved */
628 WORD LookupCount;
629 WORD LookupListIndex[1];
630 } GSUB_Feature;
632 typedef struct {
633 WORD LookupCount;
634 WORD Lookup[1];
635 } GSUB_LookupList;
637 typedef struct {
638 WORD LookupType;
639 WORD LookupFlag;
640 WORD SubTableCount;
641 WORD SubTable[1];
642 } GSUB_LookupTable;
644 typedef struct {
645 WORD CoverageFormat;
646 WORD GlyphCount;
647 WORD GlyphArray[1];
648 } GSUB_CoverageFormat1;
650 typedef struct {
651 WORD Start;
652 WORD End;
653 WORD StartCoverageIndex;
654 } GSUB_RangeRecord;
656 typedef struct {
657 WORD CoverageFormat;
658 WORD RangeCount;
659 GSUB_RangeRecord RangeRecord[1];
660 } GSUB_CoverageFormat2;
662 typedef struct {
663 WORD SubstFormat; /* = 1 */
664 WORD Coverage;
665 WORD DeltaGlyphID;
666 } GSUB_SingleSubstFormat1;
668 typedef struct {
669 WORD SubstFormat; /* = 2 */
670 WORD Coverage;
671 WORD GlyphCount;
672 WORD Substitute[1];
673 }GSUB_SingleSubstFormat2;
675 #ifdef HAVE_CARBON_CARBON_H
676 static char *find_cache_dir(void)
678 FSRef ref;
679 OSErr err;
680 static char cached_path[MAX_PATH];
681 static const char *wine = "/Wine", *fonts = "/Fonts";
683 if(*cached_path) return cached_path;
685 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
686 if(err != noErr)
688 WARN("can't create cached data folder\n");
689 return NULL;
691 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
692 if(err != noErr)
694 WARN("can't create cached data path\n");
695 *cached_path = '\0';
696 return NULL;
698 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
700 ERR("Could not create full path\n");
701 *cached_path = '\0';
702 return NULL;
704 strcat(cached_path, wine);
706 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
708 WARN("Couldn't mkdir %s\n", cached_path);
709 *cached_path = '\0';
710 return NULL;
712 strcat(cached_path, fonts);
713 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
715 WARN("Couldn't mkdir %s\n", cached_path);
716 *cached_path = '\0';
717 return NULL;
719 return cached_path;
722 /******************************************************************
723 * expand_mac_font
725 * Extracts individual TrueType font files from a Mac suitcase font
726 * and saves them into the user's caches directory (see
727 * find_cache_dir()).
728 * Returns a NULL terminated array of filenames.
730 * We do this because they are apps that try to read ttf files
731 * themselves and they don't like Mac suitcase files.
733 static char **expand_mac_font(const char *path)
735 FSRef ref;
736 SInt16 res_ref;
737 OSStatus s;
738 unsigned int idx;
739 const char *out_dir;
740 const char *filename;
741 int output_len;
742 struct {
743 char **array;
744 unsigned int size, max_size;
745 } ret;
747 TRACE("path %s\n", path);
749 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
750 if(s != noErr)
752 WARN("failed to get ref\n");
753 return NULL;
756 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
757 if(s != noErr)
759 TRACE("no data fork, so trying resource fork\n");
760 res_ref = FSOpenResFile(&ref, fsRdPerm);
761 if(res_ref == -1)
763 TRACE("unable to open resource fork\n");
764 return NULL;
768 ret.size = 0;
769 ret.max_size = 10;
770 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
771 if(!ret.array)
773 CloseResFile(res_ref);
774 return NULL;
777 out_dir = find_cache_dir();
779 filename = strrchr(path, '/');
780 if(!filename) filename = path;
781 else filename++;
783 /* output filename has the form out_dir/filename_%04x.ttf */
784 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
786 UseResFile(res_ref);
787 idx = 1;
788 while(1)
790 FamRec *fam_rec;
791 unsigned short *num_faces_ptr, num_faces, face;
792 AsscEntry *assoc;
793 Handle fond;
794 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
796 fond = Get1IndResource(fond_res, idx);
797 if(!fond) break;
798 TRACE("got fond resource %d\n", idx);
799 HLock(fond);
801 fam_rec = *(FamRec**)fond;
802 num_faces_ptr = (unsigned short *)(fam_rec + 1);
803 num_faces = GET_BE_WORD(*num_faces_ptr);
804 num_faces++;
805 assoc = (AsscEntry*)(num_faces_ptr + 1);
806 TRACE("num faces %04x\n", num_faces);
807 for(face = 0; face < num_faces; face++, assoc++)
809 Handle sfnt;
810 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
811 unsigned short size, font_id;
812 char *output;
814 size = GET_BE_WORD(assoc->fontSize);
815 font_id = GET_BE_WORD(assoc->fontID);
816 if(size != 0)
818 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
819 continue;
822 TRACE("trying to load sfnt id %04x\n", font_id);
823 sfnt = GetResource(sfnt_res, font_id);
824 if(!sfnt)
826 TRACE("can't get sfnt resource %04x\n", font_id);
827 continue;
830 output = HeapAlloc(GetProcessHeap(), 0, output_len);
831 if(output)
833 int fd;
835 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
837 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
838 if(fd != -1 || errno == EEXIST)
840 if(fd != -1)
842 unsigned char *sfnt_data;
844 HLock(sfnt);
845 sfnt_data = *(unsigned char**)sfnt;
846 write(fd, sfnt_data, GetHandleSize(sfnt));
847 HUnlock(sfnt);
848 close(fd);
850 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
852 ret.max_size *= 2;
853 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
855 ret.array[ret.size++] = output;
857 else
859 WARN("unable to create %s\n", output);
860 HeapFree(GetProcessHeap(), 0, output);
863 ReleaseResource(sfnt);
865 HUnlock(fond);
866 ReleaseResource(fond);
867 idx++;
869 CloseResFile(res_ref);
871 return ret.array;
874 #endif /* HAVE_CARBON_CARBON_H */
876 static inline BOOL is_win9x(void)
878 return GetVersion() & 0x80000000;
881 This function builds an FT_Fixed from a double. It fails if the absolute
882 value of the float number is greater than 32768.
884 static inline FT_Fixed FT_FixedFromFloat(double f)
886 return f * 0x10000;
890 This function builds an FT_Fixed from a FIXED. It simply put f.value
891 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
893 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
895 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
898 static BOOL is_hinting_enabled(void)
900 static int enabled = -1;
902 if (enabled == -1)
904 /* Use the >= 2.2.0 function if available */
905 if (pFT_Get_TrueType_Engine_Type)
907 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
908 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
910 #ifdef FT_DRIVER_HAS_HINTER
911 else
913 /* otherwise if we've been compiled with < 2.2.0 headers use the internal macro */
914 FT_Module mod = pFT_Get_Module(library, "truetype");
915 enabled = (mod && FT_DRIVER_HAS_HINTER(mod));
917 #endif
918 else enabled = FALSE;
919 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
921 return enabled;
924 static BOOL is_subpixel_rendering_enabled( void )
926 #ifdef HAVE_FREETYPE_FTLCDFIL_H
927 static int enabled = -1;
928 if (enabled == -1)
930 enabled = (pFT_Library_SetLcdFilter &&
931 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature);
932 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
934 return enabled;
935 #else
936 return FALSE;
937 #endif
941 static const struct list *get_face_list_from_family(const Family *family)
943 if (!list_empty(&family->faces))
944 return &family->faces;
945 else
946 return family->replacement;
949 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
951 Family *family;
952 Face *face;
953 const WCHAR *file;
955 TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
957 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
959 const struct list *face_list;
960 if(face_name && strcmpiW(face_name, family->FamilyName))
961 continue;
962 face_list = get_face_list_from_family(family);
963 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
965 if (!face->file)
966 continue;
967 file = strrchrW(face->file, '/');
968 if(!file)
969 file = face->file;
970 else
971 file++;
972 if(!strcmpiW(file, file_name)) return face;
975 return NULL;
978 static Family *find_family_from_name(const WCHAR *name)
980 Family *family;
982 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
984 if(!strcmpiW(family->FamilyName, name))
985 return family;
988 return NULL;
991 static Family *find_family_from_any_name(const WCHAR *name)
993 Family *family;
995 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
997 if(!strcmpiW(family->FamilyName, name))
998 return family;
999 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
1000 return family;
1003 return NULL;
1006 static void DumpSubstList(void)
1008 FontSubst *psub;
1010 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
1012 if(psub->from.charset != -1 || psub->to.charset != -1)
1013 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
1014 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
1015 else
1016 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
1017 debugstr_w(psub->to.name));
1019 return;
1022 static LPWSTR strdupW(LPCWSTR p)
1024 LPWSTR ret;
1025 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
1026 ret = HeapAlloc(GetProcessHeap(), 0, len);
1027 memcpy(ret, p, len);
1028 return ret;
1031 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1032 INT from_charset)
1034 FontSubst *element;
1036 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1038 if(!strcmpiW(element->from.name, from_name) &&
1039 (element->from.charset == from_charset ||
1040 element->from.charset == -1))
1041 return element;
1044 return NULL;
1047 #define ADD_FONT_SUBST_FORCE 1
1049 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1051 FontSubst *from_exist, *to_exist;
1053 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1055 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1057 list_remove(&from_exist->entry);
1058 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
1059 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
1060 HeapFree(GetProcessHeap(), 0, from_exist);
1061 from_exist = NULL;
1064 if(!from_exist)
1066 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1068 if(to_exist)
1070 HeapFree(GetProcessHeap(), 0, subst->to.name);
1071 subst->to.name = strdupW(to_exist->to.name);
1074 list_add_tail(subst_list, &subst->entry);
1076 return TRUE;
1079 HeapFree(GetProcessHeap(), 0, subst->from.name);
1080 HeapFree(GetProcessHeap(), 0, subst->to.name);
1081 HeapFree(GetProcessHeap(), 0, subst);
1082 return FALSE;
1085 static WCHAR *towstr(UINT cp, const char *str)
1087 int len;
1088 WCHAR *wstr;
1090 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1091 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1092 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1093 return wstr;
1096 static char *strWtoA(UINT cp, const WCHAR *str)
1098 int len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL );
1099 char *ret = HeapAlloc( GetProcessHeap(), 0, len );
1100 WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL );
1101 return ret;
1104 static void split_subst_info(NameCs *nc, LPSTR str)
1106 CHAR *p = strrchr(str, ',');
1108 nc->charset = -1;
1109 if(p && *(p+1)) {
1110 nc->charset = strtol(p+1, NULL, 10);
1111 *p = '\0';
1113 nc->name = towstr(CP_ACP, str);
1116 static void LoadSubstList(void)
1118 FontSubst *psub;
1119 HKEY hkey;
1120 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1121 LPSTR value;
1122 LPVOID data;
1124 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1125 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1126 &hkey) == ERROR_SUCCESS) {
1128 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1129 &valuelen, &datalen, NULL, NULL);
1131 valuelen++; /* returned value doesn't include room for '\0' */
1132 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1133 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1135 dlen = datalen;
1136 vlen = valuelen;
1137 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1138 &dlen) == ERROR_SUCCESS) {
1139 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1141 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1142 split_subst_info(&psub->from, value);
1143 split_subst_info(&psub->to, data);
1145 /* Win 2000 doesn't allow mapping between different charsets
1146 or mapping of DEFAULT_CHARSET */
1147 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1148 psub->to.charset == DEFAULT_CHARSET) {
1149 HeapFree(GetProcessHeap(), 0, psub->to.name);
1150 HeapFree(GetProcessHeap(), 0, psub->from.name);
1151 HeapFree(GetProcessHeap(), 0, psub);
1152 } else {
1153 add_font_subst(&font_subst_list, psub, 0);
1155 /* reset dlen and vlen */
1156 dlen = datalen;
1157 vlen = valuelen;
1159 HeapFree(GetProcessHeap(), 0, data);
1160 HeapFree(GetProcessHeap(), 0, value);
1161 RegCloseKey(hkey);
1166 /*****************************************************************
1167 * get_name_table_entry
1169 * Supply the platform, encoding, language and name ids in req
1170 * and if the name exists the function will fill in the string
1171 * and string_len members. The string is owned by FreeType so
1172 * don't free it. Returns TRUE if the name is found else FALSE.
1174 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1176 FT_SfntName name;
1177 FT_UInt num_names, name_index;
1179 if(FT_IS_SFNT(ft_face))
1181 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1183 for(name_index = 0; name_index < num_names; name_index++)
1185 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1187 if((name.platform_id == req->platform_id) &&
1188 ((name.encoding_id == TT_MS_ID_UNICODE_CS) || (name.encoding_id == TT_MS_ID_SYMBOL_CS)) &&
1189 (name.language_id == req->language_id) &&
1190 (name.name_id == req->name_id))
1192 req->string = name.string;
1193 req->string_len = name.string_len;
1194 return TRUE;
1199 req->string = NULL;
1200 req->string_len = 0;
1201 return FALSE;
1204 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1206 WCHAR *ret = NULL;
1207 FT_SfntName name;
1209 name.platform_id = TT_PLATFORM_MICROSOFT;
1210 name.language_id = language_id;
1211 name.name_id = name_id;
1213 if(get_name_table_entry(ft_face, &name))
1215 FT_UInt i;
1217 /* String is not nul terminated and string_len is a byte length. */
1218 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1219 for(i = 0; i < name.string_len / 2; i++)
1221 WORD *tmp = (WORD *)&name.string[i * 2];
1222 ret[i] = GET_BE_WORD(*tmp);
1224 ret[i] = 0;
1225 TRACE("Got localised name %s\n", debugstr_w(ret));
1228 return ret;
1231 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1233 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1234 if (f1->scalable) return TRUE;
1235 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1236 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1239 static inline void free_face( Face *face )
1241 HeapFree( GetProcessHeap(), 0, face->file );
1242 HeapFree( GetProcessHeap(), 0, face->StyleName );
1243 HeapFree( GetProcessHeap(), 0, face->FullName );
1244 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1245 HeapFree( GetProcessHeap(), 0, face );
1248 static inline void free_family( Family *family )
1250 Face *face, *cursor2;
1252 LIST_FOR_EACH_ENTRY_SAFE( face, cursor2, &family->faces, Face, entry )
1254 list_remove( &face->entry );
1255 free_face( face );
1257 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1258 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1259 HeapFree( GetProcessHeap(), 0, family );
1262 static inline int style_order(const Face *face)
1264 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1266 case NTM_REGULAR:
1267 return 0;
1268 case NTM_BOLD:
1269 return 1;
1270 case NTM_ITALIC:
1271 return 2;
1272 case NTM_BOLD | NTM_ITALIC:
1273 return 3;
1274 default:
1275 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1276 debugstr_w(face->family->FamilyName),
1277 debugstr_w(face->StyleName),
1278 face->ntmFlags);
1279 return 9999;
1283 static BOOL insert_face_in_family_list( Face *face, Family *family )
1285 Face *cursor;
1287 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1289 if (faces_equal( face, cursor ))
1291 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1292 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1293 cursor->font_version, face->font_version);
1295 if (face->font_version <= cursor->font_version)
1297 TRACE("Original font %s is newer so skipping %s\n",
1298 debugstr_w(cursor->file), debugstr_w(face->file));
1299 return FALSE;
1301 else
1303 TRACE("Replacing original %s with %s\n",
1304 debugstr_w(cursor->file), debugstr_w(face->file));
1305 list_add_before( &cursor->entry, &face->entry );
1306 face->family = family;
1307 list_remove( &cursor->entry);
1308 free_face( cursor );
1309 return TRUE;
1312 else
1313 TRACE("Adding new %s\n", debugstr_w(face->file));
1315 if (style_order( face ) < style_order( cursor )) break;
1318 list_add_before( &cursor->entry, &face->entry );
1319 face->family = family;
1320 return TRUE;
1323 /****************************************************************
1324 * NB This function stores the ptrs to the strings to save copying.
1325 * Don't free them after calling.
1327 static Family *create_family( WCHAR *name, WCHAR *english_name )
1329 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1330 family->FamilyName = name;
1331 family->EnglishName = english_name;
1332 list_init( &family->faces );
1333 family->replacement = &family->faces;
1335 return family;
1338 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1340 DWORD type, size = sizeof(DWORD);
1342 if (RegQueryValueExW(hkey, value, NULL, &type, (BYTE *)data, &size) ||
1343 type != REG_DWORD || size != sizeof(DWORD))
1345 *data = 0;
1346 return ERROR_BAD_CONFIGURATION;
1348 return ERROR_SUCCESS;
1351 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1353 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1356 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1358 DWORD needed, strike_index = 0;
1359 HKEY hkey_strike;
1361 /* If we have a File Name key then this is a real font, not just the parent
1362 key of a bunch of non-scalable strikes */
1363 needed = buffer_size;
1364 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1366 Face *face;
1367 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1368 face->cached_enum_data = NULL;
1370 face->file = strdupW( buffer );
1371 face->StyleName = strdupW(face_name);
1373 needed = buffer_size;
1374 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1375 face->FullName = strdupW( buffer );
1376 else
1377 face->FullName = NULL;
1379 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1380 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1381 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1382 reg_load_dword(hkey_face, face_vertical_value, (DWORD*)&face->vertical);
1383 reg_load_dword(hkey_face, face_aa_value, (DWORD*)&face->aa_flags);
1385 needed = sizeof(face->fs);
1386 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1388 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1390 face->scalable = TRUE;
1391 memset(&face->size, 0, sizeof(face->size));
1393 else
1395 face->scalable = FALSE;
1396 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1397 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1398 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1399 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1400 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1402 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1403 face->size.height, face->size.width, face->size.size >> 6,
1404 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1407 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1408 face->fs.fsCsb[0], face->fs.fsCsb[1],
1409 face->fs.fsUsb[0], face->fs.fsUsb[1],
1410 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1412 insert_face_in_family_list(face, family);
1414 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1417 /* load bitmap strikes */
1419 needed = buffer_size;
1420 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1422 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1424 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1425 RegCloseKey(hkey_strike);
1427 needed = buffer_size;
1431 static void load_font_list_from_cache(HKEY hkey_font_cache)
1433 DWORD size, family_index = 0;
1434 Family *family;
1435 HKEY hkey_family;
1436 WCHAR buffer[4096];
1438 size = sizeof(buffer);
1439 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1441 WCHAR *english_family = NULL;
1442 WCHAR *family_name = strdupW( buffer );
1443 DWORD face_index = 0;
1445 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1446 TRACE("opened family key %s\n", debugstr_w(family_name));
1447 size = sizeof(buffer);
1448 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1449 english_family = strdupW( buffer );
1451 family = create_family(family_name, english_family);
1452 list_add_tail(&font_list, &family->entry);
1454 if(english_family)
1456 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1457 subst->from.name = strdupW(english_family);
1458 subst->from.charset = -1;
1459 subst->to.name = strdupW(family_name);
1460 subst->to.charset = -1;
1461 add_font_subst(&font_subst_list, subst, 0);
1464 size = sizeof(buffer);
1465 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1467 WCHAR *face_name = strdupW( buffer );
1468 HKEY hkey_face;
1470 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1472 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1473 RegCloseKey(hkey_face);
1475 HeapFree( GetProcessHeap(), 0, face_name );
1476 size = sizeof(buffer);
1478 RegCloseKey(hkey_family);
1479 size = sizeof(buffer);
1483 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1485 LONG ret;
1486 HKEY hkey_wine_fonts;
1488 /* We don't want to create the fonts key as volatile, so open this first */
1489 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1490 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1491 if(ret != ERROR_SUCCESS)
1493 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1494 return ret;
1497 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1498 KEY_ALL_ACCESS, NULL, hkey, disposition);
1499 RegCloseKey(hkey_wine_fonts);
1500 return ret;
1503 static void add_face_to_cache(Face *face)
1505 HKEY hkey_font_cache, hkey_family, hkey_face;
1506 WCHAR *face_key_name;
1508 create_font_cache_key(&hkey_font_cache, NULL);
1510 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1511 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1512 if(face->family->EnglishName)
1513 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1514 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1516 if(face->scalable)
1517 face_key_name = face->StyleName;
1518 else
1520 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1521 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1522 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1524 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1525 &hkey_face, NULL);
1526 if(!face->scalable)
1527 HeapFree(GetProcessHeap(), 0, face_key_name);
1529 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1530 (strlenW(face->file) + 1) * sizeof(WCHAR));
1531 if (face->FullName)
1532 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1533 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1535 reg_save_dword(hkey_face, face_index_value, face->face_index);
1536 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1537 reg_save_dword(hkey_face, face_version_value, face->font_version);
1538 if (face->vertical) reg_save_dword(hkey_face, face_vertical_value, face->vertical);
1539 if (face->aa_flags) reg_save_dword(hkey_face, face_aa_value, face->aa_flags);
1541 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1543 if(!face->scalable)
1545 reg_save_dword(hkey_face, face_height_value, face->size.height);
1546 reg_save_dword(hkey_face, face_width_value, face->size.width);
1547 reg_save_dword(hkey_face, face_size_value, face->size.size);
1548 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1549 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1550 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1552 RegCloseKey(hkey_face);
1553 RegCloseKey(hkey_family);
1554 RegCloseKey(hkey_font_cache);
1557 static WCHAR *prepend_at(WCHAR *family)
1559 WCHAR *str;
1561 if (!family)
1562 return NULL;
1564 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1565 str[0] = '@';
1566 strcpyW(str + 1, family);
1567 HeapFree(GetProcessHeap(), 0, family);
1568 return str;
1571 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1573 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1574 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1576 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1577 if (!*name)
1579 *name = *english;
1580 *english = NULL;
1582 else if (!strcmpiW( *name, *english ))
1584 HeapFree( GetProcessHeap(), 0, *english );
1585 *english = NULL;
1588 if (vertical)
1590 *name = prepend_at( *name );
1591 *english = prepend_at( *english );
1595 static Family *get_family( FT_Face ft_face, BOOL vertical )
1597 Family *family;
1598 WCHAR *name, *english_name;
1600 get_family_names( ft_face, &name, &english_name, vertical );
1602 family = find_family_from_name( name );
1604 if (!family)
1606 family = create_family( name, english_name );
1607 list_add_tail( &font_list, &family->entry );
1609 if (english_name)
1611 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1612 subst->from.name = strdupW( english_name );
1613 subst->from.charset = -1;
1614 subst->to.name = strdupW( name );
1615 subst->to.charset = -1;
1616 add_font_subst( &font_subst_list, subst, 0 );
1619 else
1621 HeapFree( GetProcessHeap(), 0, name );
1622 HeapFree( GetProcessHeap(), 0, english_name );
1625 return family;
1628 static inline FT_Fixed get_font_version( FT_Face ft_face )
1630 FT_Fixed version = 0;
1631 TT_Header *header;
1633 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1634 if (header) version = header->Font_Revision;
1636 return version;
1639 static inline DWORD get_ntm_flags( FT_Face ft_face )
1641 DWORD flags = 0;
1642 FT_ULong table_size = 0;
1644 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1645 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1646 if (flags == 0) flags = NTM_REGULAR;
1648 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1649 flags |= NTM_PS_OPENTYPE;
1651 return flags;
1654 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1656 int internal_leading = 0;
1657 FT_WinFNT_HeaderRec winfnt_header;
1659 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1660 internal_leading = winfnt_header.internal_leading;
1662 return internal_leading;
1665 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1667 TT_OS2 *os2;
1668 FT_UInt dummy;
1669 CHARSETINFO csi;
1670 FT_WinFNT_HeaderRec winfnt_header;
1671 int i;
1673 memset( fs, 0, sizeof(*fs) );
1675 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1676 if (os2)
1678 fs->fsUsb[0] = os2->ulUnicodeRange1;
1679 fs->fsUsb[1] = os2->ulUnicodeRange2;
1680 fs->fsUsb[2] = os2->ulUnicodeRange3;
1681 fs->fsUsb[3] = os2->ulUnicodeRange4;
1683 if (os2->version == 0)
1685 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1686 fs->fsCsb[0] = FS_LATIN1;
1687 else
1688 fs->fsCsb[0] = FS_SYMBOL;
1690 else
1692 fs->fsCsb[0] = os2->ulCodePageRange1;
1693 fs->fsCsb[1] = os2->ulCodePageRange2;
1696 else
1698 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1700 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1701 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1702 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1703 *fs = csi.fs;
1707 if (fs->fsCsb[0] == 0)
1709 /* let's see if we can find any interesting cmaps */
1710 for (i = 0; i < ft_face->num_charmaps; i++)
1712 switch (ft_face->charmaps[i]->encoding)
1714 case FT_ENCODING_UNICODE:
1715 case FT_ENCODING_APPLE_ROMAN:
1716 fs->fsCsb[0] |= FS_LATIN1;
1717 break;
1718 case FT_ENCODING_MS_SYMBOL:
1719 fs->fsCsb[0] |= FS_SYMBOL;
1720 break;
1721 default:
1722 break;
1728 #define ADDFONT_EXTERNAL_FONT 0x01
1729 #define ADDFONT_FORCE_BITMAP 0x02
1730 #define ADDFONT_ADD_TO_CACHE 0x04
1731 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
1733 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1734 DWORD flags, BOOL vertical, DWORD aa_flags )
1736 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1737 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1739 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
1740 if (!face->StyleName)
1741 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1742 if (!face->StyleName)
1744 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1747 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
1748 if (!face->FullName)
1749 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1750 if (vertical)
1751 face->FullName = prepend_at( face->FullName );
1753 if (file)
1755 face->file = towstr( CP_UNIXCP, file );
1756 face->font_data_ptr = NULL;
1757 face->font_data_size = 0;
1759 else
1761 face->file = NULL;
1762 face->font_data_ptr = font_data_ptr;
1763 face->font_data_size = font_data_size;
1766 face->face_index = face_index;
1767 get_fontsig( ft_face, &face->fs );
1768 face->ntmFlags = get_ntm_flags( ft_face );
1769 face->font_version = get_font_version( ft_face );
1771 if (FT_IS_SCALABLE( ft_face ))
1773 memset( &face->size, 0, sizeof(face->size) );
1774 face->scalable = TRUE;
1776 else
1778 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1779 size->height, size->width, size->size >> 6,
1780 size->x_ppem >> 6, size->y_ppem >> 6);
1781 face->size.height = size->height;
1782 face->size.width = size->width;
1783 face->size.size = size->size;
1784 face->size.x_ppem = size->x_ppem;
1785 face->size.y_ppem = size->y_ppem;
1786 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1787 face->scalable = FALSE;
1790 face->vertical = vertical;
1791 face->external = (flags & ADDFONT_EXTERNAL_FONT) != 0;
1792 face->aa_flags = aa_flags;
1793 face->family = NULL;
1794 face->cached_enum_data = NULL;
1796 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1797 face->fs.fsCsb[0], face->fs.fsCsb[1],
1798 face->fs.fsUsb[0], face->fs.fsUsb[1],
1799 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1801 return face;
1804 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1805 FT_Long face_index, DWORD flags, BOOL vertical, DWORD aa_flags )
1807 Face *face;
1808 Family *family;
1810 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags, vertical, aa_flags );
1811 family = get_family( ft_face, vertical );
1812 if (!insert_face_in_family_list( face, family ))
1814 free_face( face );
1815 return;
1818 if (flags & ADDFONT_ADD_TO_CACHE)
1819 add_face_to_cache( face );
1821 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1822 debugstr_w(face->StyleName));
1825 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1826 FT_Long face_index, BOOL allow_bitmap )
1828 FT_Error err;
1829 TT_OS2 *pOS2;
1830 FT_Face ft_face;
1832 if (file)
1834 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1835 err = pFT_New_Face(library, file, face_index, &ft_face);
1837 else
1839 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1840 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1843 if (err != 0)
1845 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1846 return NULL;
1849 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1850 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1852 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1853 goto fail;
1856 if (!FT_IS_SFNT( ft_face ))
1858 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1860 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1861 goto fail;
1864 else
1866 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1867 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1868 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1870 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1871 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1872 goto fail;
1875 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1876 we don't want to load these. */
1877 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1879 FT_ULong len = 0;
1881 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1883 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1884 goto fail;
1889 if (!ft_face->family_name || !ft_face->style_name)
1891 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1892 goto fail;
1895 return ft_face;
1896 fail:
1897 pFT_Done_Face( ft_face );
1898 return NULL;
1901 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1903 FT_Face ft_face;
1904 FT_Long face_index = 0, num_faces;
1905 INT ret = 0;
1906 DWORD aa_flags = HIWORD( flags );
1908 if (!aa_flags) aa_flags = default_aa_flags;
1910 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1911 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1913 #ifdef HAVE_CARBON_CARBON_H
1914 if(file)
1916 char **mac_list = expand_mac_font(file);
1917 if(mac_list)
1919 BOOL had_one = FALSE;
1920 char **cursor;
1921 for(cursor = mac_list; *cursor; cursor++)
1923 had_one = TRUE;
1924 AddFontToList(*cursor, NULL, 0, flags);
1925 HeapFree(GetProcessHeap(), 0, *cursor);
1927 HeapFree(GetProcessHeap(), 0, mac_list);
1928 if(had_one)
1929 return 1;
1932 #endif /* HAVE_CARBON_CARBON_H */
1934 do {
1935 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_FORCE_BITMAP );
1936 if (!ft_face) return 0;
1938 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1940 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1941 pFT_Done_Face(ft_face);
1942 return 0;
1945 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE, aa_flags);
1946 ++ret;
1948 if (FT_HAS_VERTICAL(ft_face))
1950 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE, aa_flags);
1951 ++ret;
1954 num_faces = ft_face->num_faces;
1955 pFT_Done_Face(ft_face);
1956 } while(num_faces > ++face_index);
1957 return ret;
1960 static void DumpFontList(void)
1962 Family *family;
1963 Face *face;
1965 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
1966 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1967 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
1968 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1969 if(!face->scalable)
1970 TRACE(" %d", face->size.height);
1971 TRACE("\n");
1974 return;
1977 /***********************************************************
1978 * The replacement list is a way to map an entire font
1979 * family onto another family. For example adding
1981 * [HKCU\Software\Wine\Fonts\Replacements]
1982 * "Wingdings"="Winedings"
1984 * would enumerate the Winedings font both as Winedings and
1985 * Wingdings. However if a real Wingdings font is present the
1986 * replacement does not take place.
1989 static void LoadReplaceList(void)
1991 HKEY hkey;
1992 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1993 LPWSTR value;
1994 LPVOID data;
1996 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1997 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1999 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2000 &valuelen, &datalen, NULL, NULL);
2002 valuelen++; /* returned value doesn't include room for '\0' */
2003 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2004 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2006 dlen = datalen;
2007 vlen = valuelen;
2008 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
2009 &dlen) == ERROR_SUCCESS) {
2010 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
2011 /* "NewName"="Oldname" */
2012 if(!find_family_from_any_name(value))
2014 Family * const family = find_family_from_any_name(data);
2015 if (family != NULL)
2017 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2018 if (new_family != NULL)
2020 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
2021 new_family->FamilyName = strdupW(value);
2022 new_family->EnglishName = NULL;
2023 list_init(&new_family->faces);
2024 new_family->replacement = &family->faces;
2025 list_add_tail(&font_list, &new_family->entry);
2028 else
2030 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2033 else
2035 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2037 /* reset dlen and vlen */
2038 dlen = datalen;
2039 vlen = valuelen;
2041 HeapFree(GetProcessHeap(), 0, data);
2042 HeapFree(GetProcessHeap(), 0, value);
2043 RegCloseKey(hkey);
2047 static const WCHAR *font_links_list[] =
2049 Lucida_Sans_Unicode,
2050 Microsoft_Sans_Serif,
2051 Tahoma
2054 static const struct font_links_defaults_list
2056 /* Keyed off substitution for "MS Shell Dlg" */
2057 const WCHAR *shelldlg;
2058 /* Maximum of four substitutes, plus terminating NULL pointer */
2059 const WCHAR *substitutes[5];
2060 } font_links_defaults_list[] =
2062 /* Non East-Asian */
2063 { Tahoma, /* FIXME unverified ordering */
2064 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2066 /* Below lists are courtesy of
2067 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2069 /* Japanese */
2070 { MS_UI_Gothic,
2071 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2073 /* Chinese Simplified */
2074 { SimSun,
2075 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2077 /* Korean */
2078 { Gulim,
2079 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2081 /* Chinese Traditional */
2082 { PMingLiU,
2083 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2088 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2090 SYSTEM_LINKS *font_link;
2092 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2094 if(!strcmpiW(font_link->font_name, name))
2095 return font_link;
2098 return NULL;
2101 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2103 const WCHAR *value;
2104 int i;
2105 FontSubst *psub;
2106 Family *family;
2107 Face *face;
2108 const WCHAR *file;
2110 if (values)
2112 SYSTEM_LINKS *font_link;
2114 psub = get_font_subst(&font_subst_list, name, -1);
2115 /* Don't store fonts that are only substitutes for other fonts */
2116 if(psub)
2118 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2119 return;
2122 font_link = find_font_link(name);
2123 if (font_link == NULL)
2125 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2126 font_link->font_name = strdupW(name);
2127 list_init(&font_link->links);
2128 list_add_tail(&system_links, &font_link->entry);
2131 memset(&font_link->fs, 0, sizeof font_link->fs);
2132 for (i = 0; values[i] != NULL; i++)
2134 const struct list *face_list;
2135 CHILD_FONT *child_font;
2137 value = values[i];
2138 if (!strcmpiW(name,value))
2139 continue;
2140 psub = get_font_subst(&font_subst_list, value, -1);
2141 if(psub)
2142 value = psub->to.name;
2143 family = find_family_from_name(value);
2144 if (!family)
2145 continue;
2146 file = NULL;
2147 /* Use first extant filename for this Family */
2148 face_list = get_face_list_from_family(family);
2149 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2151 if (!face->file)
2152 continue;
2153 file = strrchrW(face->file, '/');
2154 if (!file)
2155 file = face->file;
2156 else
2157 file++;
2158 break;
2160 if (!file)
2161 continue;
2162 face = find_face_from_filename(file, value);
2163 if(!face)
2165 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2166 continue;
2169 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2170 child_font->face = face;
2171 child_font->font = NULL;
2172 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2173 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2174 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2175 child_font->face->face_index);
2176 list_add_tail(&font_link->links, &child_font->entry);
2178 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2184 /*************************************************************
2185 * init_system_links
2187 static BOOL init_system_links(void)
2189 HKEY hkey;
2190 BOOL ret = FALSE;
2191 DWORD type, max_val, max_data, val_len, data_len, index;
2192 WCHAR *value, *data;
2193 WCHAR *entry, *next;
2194 SYSTEM_LINKS *font_link, *system_font_link;
2195 CHILD_FONT *child_font;
2196 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2197 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2198 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2199 Face *face;
2200 FontSubst *psub;
2201 UINT i, j;
2203 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2205 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2206 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2207 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2208 val_len = max_val + 1;
2209 data_len = max_data;
2210 index = 0;
2211 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2213 psub = get_font_subst(&font_subst_list, value, -1);
2214 /* Don't store fonts that are only substitutes for other fonts */
2215 if(psub)
2217 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2218 goto next;
2220 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2221 font_link->font_name = strdupW(value);
2222 memset(&font_link->fs, 0, sizeof font_link->fs);
2223 list_init(&font_link->links);
2224 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2226 WCHAR *face_name;
2227 CHILD_FONT *child_font;
2229 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2231 next = entry + strlenW(entry) + 1;
2233 face_name = strchrW(entry, ',');
2234 if(face_name)
2236 *face_name++ = 0;
2237 while(isspaceW(*face_name))
2238 face_name++;
2240 psub = get_font_subst(&font_subst_list, face_name, -1);
2241 if(psub)
2242 face_name = psub->to.name;
2244 face = find_face_from_filename(entry, face_name);
2245 if(!face)
2247 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2248 continue;
2251 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2252 child_font->face = face;
2253 child_font->font = NULL;
2254 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2255 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2256 TRACE("Adding file %s index %ld\n",
2257 debugstr_w(child_font->face->file), child_font->face->face_index);
2258 list_add_tail(&font_link->links, &child_font->entry);
2260 list_add_tail(&system_links, &font_link->entry);
2261 next:
2262 val_len = max_val + 1;
2263 data_len = max_data;
2266 HeapFree(GetProcessHeap(), 0, value);
2267 HeapFree(GetProcessHeap(), 0, data);
2268 RegCloseKey(hkey);
2272 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2273 if (!psub) {
2274 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2275 goto skip_internal;
2278 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2280 const FontSubst *psub2;
2281 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2283 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2285 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2286 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2288 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2289 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2291 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2293 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2297 skip_internal:
2299 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2300 that Tahoma has */
2302 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2303 system_font_link->font_name = strdupW(System);
2304 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2305 list_init(&system_font_link->links);
2307 face = find_face_from_filename(tahoma_ttf, Tahoma);
2308 if(face)
2310 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2311 child_font->face = face;
2312 child_font->font = NULL;
2313 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2314 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2315 TRACE("Found Tahoma in %s index %ld\n",
2316 debugstr_w(child_font->face->file), child_font->face->face_index);
2317 list_add_tail(&system_font_link->links, &child_font->entry);
2319 font_link = find_font_link(Tahoma);
2320 if (font_link != NULL)
2322 CHILD_FONT *font_link_entry;
2323 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2325 CHILD_FONT *new_child;
2326 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2327 new_child->face = font_link_entry->face;
2328 new_child->font = NULL;
2329 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2330 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2331 list_add_tail(&system_font_link->links, &new_child->entry);
2334 list_add_tail(&system_links, &system_font_link->entry);
2335 return ret;
2338 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2340 DIR *dir;
2341 struct dirent *dent;
2342 char path[MAX_PATH];
2344 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2346 dir = opendir(dirname);
2347 if(!dir) {
2348 WARN("Can't open directory %s\n", debugstr_a(dirname));
2349 return FALSE;
2351 while((dent = readdir(dir)) != NULL) {
2352 struct stat statbuf;
2354 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2355 continue;
2357 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2359 sprintf(path, "%s/%s", dirname, dent->d_name);
2361 if(stat(path, &statbuf) == -1)
2363 WARN("Can't stat %s\n", debugstr_a(path));
2364 continue;
2366 if(S_ISDIR(statbuf.st_mode))
2367 ReadFontDir(path, external_fonts);
2368 else
2370 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2371 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2372 AddFontToList(path, NULL, 0, addfont_flags);
2375 closedir(dir);
2376 return TRUE;
2379 #ifdef SONAME_LIBFONTCONFIG
2381 static BOOL fontconfig_enabled;
2383 static UINT parse_aa_pattern( FcPattern *pattern )
2385 FcBool antialias;
2386 int rgba;
2387 UINT aa_flags = 0;
2389 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2390 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2392 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2394 switch (rgba)
2396 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2397 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2398 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2399 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2400 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2403 return aa_flags;
2406 static void init_fontconfig(void)
2408 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2410 if (!fc_handle)
2412 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2413 return;
2416 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2417 LOAD_FUNCPTR(FcConfigSubstitute);
2418 LOAD_FUNCPTR(FcFontList);
2419 LOAD_FUNCPTR(FcFontSetDestroy);
2420 LOAD_FUNCPTR(FcInit);
2421 LOAD_FUNCPTR(FcObjectSetAdd);
2422 LOAD_FUNCPTR(FcObjectSetCreate);
2423 LOAD_FUNCPTR(FcObjectSetDestroy);
2424 LOAD_FUNCPTR(FcPatternCreate);
2425 LOAD_FUNCPTR(FcPatternDestroy);
2426 LOAD_FUNCPTR(FcPatternGetBool);
2427 LOAD_FUNCPTR(FcPatternGetInteger);
2428 LOAD_FUNCPTR(FcPatternGetString);
2429 #undef LOAD_FUNCPTR
2431 if (pFcInit())
2433 FcPattern *pattern = pFcPatternCreate();
2434 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2435 default_aa_flags = parse_aa_pattern( pattern );
2436 pFcPatternDestroy( pattern );
2437 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2438 fontconfig_enabled = TRUE;
2442 static void load_fontconfig_fonts(void)
2444 FcPattern *pat;
2445 FcObjectSet *os;
2446 FcFontSet *fontset;
2447 int i, len;
2448 char *file;
2449 const char *ext;
2451 if (!fontconfig_enabled) return;
2453 pat = pFcPatternCreate();
2454 os = pFcObjectSetCreate();
2455 pFcObjectSetAdd(os, FC_FILE);
2456 pFcObjectSetAdd(os, FC_SCALABLE);
2457 pFcObjectSetAdd(os, FC_ANTIALIAS);
2458 pFcObjectSetAdd(os, FC_RGBA);
2459 fontset = pFcFontList(NULL, pat, os);
2460 if(!fontset) return;
2461 for(i = 0; i < fontset->nfont; i++) {
2462 FcBool scalable;
2463 DWORD aa_flags;
2465 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2466 continue;
2468 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2470 /* We're just interested in OT/TT fonts for now, so this hack just
2471 picks up the scalable fonts without extensions .pf[ab] to save time
2472 loading every other font */
2474 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2476 TRACE("not scalable\n");
2477 continue;
2480 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2481 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2483 len = strlen( file );
2484 if(len < 4) continue;
2485 ext = &file[ len - 3 ];
2486 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2487 AddFontToList(file, NULL, 0,
2488 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2490 pFcFontSetDestroy(fontset);
2491 pFcObjectSetDestroy(os);
2492 pFcPatternDestroy(pat);
2495 #elif defined(HAVE_CARBON_CARBON_H)
2497 static void load_mac_font_callback(const void *value, void *context)
2499 CFStringRef pathStr = value;
2500 CFIndex len;
2501 char* path;
2503 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2504 path = HeapAlloc(GetProcessHeap(), 0, len);
2505 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2507 TRACE("font file %s\n", path);
2508 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2510 HeapFree(GetProcessHeap(), 0, path);
2513 static void load_mac_fonts(void)
2515 CFStringRef removeDupesKey;
2516 CFBooleanRef removeDupesValue;
2517 CFDictionaryRef options;
2518 CTFontCollectionRef col;
2519 CFArrayRef descs;
2520 CFMutableSetRef paths;
2521 CFIndex i;
2523 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2524 removeDupesValue = kCFBooleanTrue;
2525 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2526 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2527 col = CTFontCollectionCreateFromAvailableFonts(options);
2528 if (options) CFRelease(options);
2529 if (!col)
2531 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2532 return;
2535 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2536 CFRelease(col);
2537 if (!descs)
2539 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2540 return;
2543 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2544 if (!paths)
2546 WARN("CFSetCreateMutable failed\n");
2547 CFRelease(descs);
2548 return;
2551 for (i = 0; i < CFArrayGetCount(descs); i++)
2553 CTFontDescriptorRef desc;
2554 CTFontRef font;
2555 ATSFontRef atsFont;
2556 OSStatus status;
2557 FSRef fsref;
2558 CFURLRef url;
2559 CFStringRef ext;
2560 CFStringRef path;
2562 desc = CFArrayGetValueAtIndex(descs, i);
2564 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2565 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2566 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2567 if (!font) continue;
2569 atsFont = CTFontGetPlatformFont(font, NULL);
2570 if (!atsFont)
2572 CFRelease(font);
2573 continue;
2576 status = ATSFontGetFileReference(atsFont, &fsref);
2577 CFRelease(font);
2578 if (status != noErr) continue;
2580 url = CFURLCreateFromFSRef(NULL, &fsref);
2581 if (!url) continue;
2583 ext = CFURLCopyPathExtension(url);
2584 if (ext)
2586 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2587 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2588 CFRelease(ext);
2589 if (skip)
2591 CFRelease(url);
2592 continue;
2596 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2597 CFRelease(url);
2598 if (!path) continue;
2600 CFSetAddValue(paths, path);
2601 CFRelease(path);
2604 CFRelease(descs);
2606 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2607 CFRelease(paths);
2610 #endif
2612 static BOOL load_font_from_data_dir(LPCWSTR file)
2614 BOOL ret = FALSE;
2615 const char *data_dir = wine_get_data_dir();
2617 if (!data_dir) data_dir = wine_get_build_dir();
2619 if (data_dir)
2621 INT len;
2622 char *unix_name;
2624 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2626 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2628 strcpy(unix_name, data_dir);
2629 strcat(unix_name, "/fonts/");
2631 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2633 EnterCriticalSection( &freetype_cs );
2634 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2635 LeaveCriticalSection( &freetype_cs );
2636 HeapFree(GetProcessHeap(), 0, unix_name);
2638 return ret;
2641 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2643 static const WCHAR slashW[] = {'\\','\0'};
2644 BOOL ret = FALSE;
2645 WCHAR windowsdir[MAX_PATH];
2646 char *unixname;
2648 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2649 strcatW(windowsdir, fontsW);
2650 strcatW(windowsdir, slashW);
2651 strcatW(windowsdir, file);
2652 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2653 EnterCriticalSection( &freetype_cs );
2654 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2655 LeaveCriticalSection( &freetype_cs );
2656 HeapFree(GetProcessHeap(), 0, unixname);
2658 return ret;
2661 static void load_system_fonts(void)
2663 HKEY hkey;
2664 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2665 const WCHAR * const *value;
2666 DWORD dlen, type;
2667 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2668 char *unixname;
2670 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2671 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2672 strcatW(windowsdir, fontsW);
2673 for(value = SystemFontValues; *value; value++) {
2674 dlen = sizeof(data);
2675 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2676 type == REG_SZ) {
2677 BOOL added = FALSE;
2679 sprintfW(pathW, fmtW, windowsdir, data);
2680 if((unixname = wine_get_unix_file_name(pathW))) {
2681 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2682 HeapFree(GetProcessHeap(), 0, unixname);
2684 if (!added)
2685 load_font_from_data_dir(data);
2688 RegCloseKey(hkey);
2692 /*************************************************************
2694 * This adds registry entries for any externally loaded fonts
2695 * (fonts from fontconfig or FontDirs). It also deletes entries
2696 * of no longer existing fonts.
2699 static void update_reg_entries(void)
2701 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2702 LPWSTR valueW;
2703 DWORD len;
2704 Family *family;
2705 Face *face;
2706 WCHAR *file, *path;
2707 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2709 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2710 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2711 ERR("Can't create Windows font reg key\n");
2712 goto end;
2715 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2716 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2717 ERR("Can't create Windows font reg key\n");
2718 goto end;
2721 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2722 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2723 ERR("Can't create external font reg key\n");
2724 goto end;
2727 /* enumerate the fonts and add external ones to the two keys */
2729 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2730 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2731 char *buffer;
2732 if(!face->external) continue;
2734 if(face->FullName)
2736 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2737 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2738 strcpyW(valueW, face->FullName);
2740 else
2742 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2743 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2744 strcpyW(valueW, family->FamilyName);
2747 buffer = strWtoA( CP_UNIXCP, face->file );
2748 path = wine_get_dos_file_name( buffer );
2749 HeapFree( GetProcessHeap(), 0, buffer );
2751 if (path)
2752 file = path;
2753 else if ((file = strrchrW(face->file, '/')))
2754 file++;
2755 else
2756 file = face->file;
2758 len = strlenW(file) + 1;
2759 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2760 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2761 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2763 HeapFree(GetProcessHeap(), 0, path);
2764 HeapFree(GetProcessHeap(), 0, valueW);
2767 end:
2768 if(external_key) RegCloseKey(external_key);
2769 if(win9x_key) RegCloseKey(win9x_key);
2770 if(winnt_key) RegCloseKey(winnt_key);
2771 return;
2774 static void delete_external_font_keys(void)
2776 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2777 DWORD dlen, vlen, datalen, valuelen, i, type;
2778 LPWSTR valueW;
2779 LPVOID data;
2781 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2782 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2783 ERR("Can't create Windows font reg key\n");
2784 goto end;
2787 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2788 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2789 ERR("Can't create Windows font reg key\n");
2790 goto end;
2793 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2794 ERR("Can't create external font reg key\n");
2795 goto end;
2798 /* Delete all external fonts added last time */
2800 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2801 &valuelen, &datalen, NULL, NULL);
2802 valuelen++; /* returned value doesn't include room for '\0' */
2803 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2804 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2806 dlen = datalen * sizeof(WCHAR);
2807 vlen = valuelen;
2808 i = 0;
2809 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2810 &dlen) == ERROR_SUCCESS) {
2812 RegDeleteValueW(winnt_key, valueW);
2813 RegDeleteValueW(win9x_key, valueW);
2814 /* reset dlen and vlen */
2815 dlen = datalen;
2816 vlen = valuelen;
2818 HeapFree(GetProcessHeap(), 0, data);
2819 HeapFree(GetProcessHeap(), 0, valueW);
2821 /* Delete the old external fonts key */
2822 RegCloseKey(external_key);
2823 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2825 end:
2826 if(win9x_key) RegCloseKey(win9x_key);
2827 if(winnt_key) RegCloseKey(winnt_key);
2830 /*************************************************************
2831 * WineEngAddFontResourceEx
2834 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2836 INT ret = 0;
2838 GDI_CheckNotLock();
2840 if (ft_handle) /* do it only if we have freetype up and running */
2842 char *unixname;
2844 if(flags)
2845 FIXME("Ignoring flags %x\n", flags);
2847 if((unixname = wine_get_unix_file_name(file)))
2849 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2851 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2852 EnterCriticalSection( &freetype_cs );
2853 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2854 LeaveCriticalSection( &freetype_cs );
2855 HeapFree(GetProcessHeap(), 0, unixname);
2857 if (!ret && !strchrW(file, '\\')) {
2858 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2859 ret = load_font_from_winfonts_dir(file);
2860 if (!ret) {
2861 /* Try in datadir/fonts (or builddir/fonts),
2862 * needed for Magic the Gathering Online
2864 ret = load_font_from_data_dir(file);
2868 return ret;
2871 /*************************************************************
2872 * WineEngAddFontMemResourceEx
2875 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2877 GDI_CheckNotLock();
2879 if (ft_handle) /* do it only if we have freetype up and running */
2881 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2883 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2884 memcpy(pFontCopy, pbFont, cbFont);
2886 EnterCriticalSection( &freetype_cs );
2887 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2888 LeaveCriticalSection( &freetype_cs );
2890 if (*pcFonts == 0)
2892 TRACE("AddFontToList failed\n");
2893 HeapFree(GetProcessHeap(), 0, pFontCopy);
2894 return 0;
2896 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2897 * For now return something unique but quite random
2899 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2900 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2903 *pcFonts = 0;
2904 return 0;
2907 /*************************************************************
2908 * WineEngRemoveFontResourceEx
2911 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2913 GDI_CheckNotLock();
2914 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2915 return TRUE;
2918 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
2920 WCHAR *fullname;
2921 char *unix_name;
2922 int file_len;
2924 if (!font_file) return NULL;
2926 file_len = strlenW( font_file );
2928 if (font_path && font_path[0])
2930 int path_len = strlenW( font_path );
2931 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
2932 if (!fullname) return NULL;
2933 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
2934 fullname[path_len] = '\\';
2935 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
2937 else
2939 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
2940 if (!len) return NULL;
2941 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2942 if (!fullname) return NULL;
2943 GetFullPathNameW( font_file, len, fullname, NULL );
2946 unix_name = wine_get_unix_file_name( fullname );
2947 HeapFree( GetProcessHeap(), 0, fullname );
2948 return unix_name;
2951 #include <pshpack1.h>
2952 struct fontdir
2954 WORD num_of_resources;
2955 WORD res_id;
2956 WORD dfVersion;
2957 DWORD dfSize;
2958 CHAR dfCopyright[60];
2959 WORD dfType;
2960 WORD dfPoints;
2961 WORD dfVertRes;
2962 WORD dfHorizRes;
2963 WORD dfAscent;
2964 WORD dfInternalLeading;
2965 WORD dfExternalLeading;
2966 BYTE dfItalic;
2967 BYTE dfUnderline;
2968 BYTE dfStrikeOut;
2969 WORD dfWeight;
2970 BYTE dfCharSet;
2971 WORD dfPixWidth;
2972 WORD dfPixHeight;
2973 BYTE dfPitchAndFamily;
2974 WORD dfAvgWidth;
2975 WORD dfMaxWidth;
2976 BYTE dfFirstChar;
2977 BYTE dfLastChar;
2978 BYTE dfDefaultChar;
2979 BYTE dfBreakChar;
2980 WORD dfWidthBytes;
2981 DWORD dfDevice;
2982 DWORD dfFace;
2983 DWORD dfReserved;
2984 CHAR szFaceName[LF_FACESIZE];
2987 #include <poppack.h>
2989 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2990 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
2992 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
2994 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
2995 Face *face;
2996 Family *family;
2997 WCHAR *name, *english_name;
2998 ENUMLOGFONTEXW elf;
2999 NEWTEXTMETRICEXW ntm;
3000 DWORD type;
3002 if (!ft_face) return FALSE;
3003 face = create_face( ft_face, 0, unix_name, NULL, 0, 0, FALSE, 0 );
3004 get_family_names( ft_face, &name, &english_name, FALSE );
3005 family = create_family( name, english_name );
3006 insert_face_in_family_list( face, family );
3007 pFT_Done_Face( ft_face );
3009 GetEnumStructs( face, &elf, &ntm, &type );
3010 free_family( family );
3012 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3014 memset( fd, 0, sizeof(*fd) );
3016 fd->num_of_resources = 1;
3017 fd->res_id = 0;
3018 fd->dfVersion = 0x200;
3019 fd->dfSize = sizeof(*fd);
3020 strcpy( fd->dfCopyright, "Wine fontdir" );
3021 fd->dfType = 0x4003; /* 0x0080 set if private */
3022 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3023 fd->dfVertRes = 72;
3024 fd->dfHorizRes = 72;
3025 fd->dfAscent = ntm.ntmTm.tmAscent;
3026 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3027 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3028 fd->dfItalic = ntm.ntmTm.tmItalic;
3029 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3030 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3031 fd->dfWeight = ntm.ntmTm.tmWeight;
3032 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3033 fd->dfPixWidth = 0;
3034 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3035 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3036 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3037 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3038 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3039 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3040 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3041 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3042 fd->dfWidthBytes = 0;
3043 fd->dfDevice = 0;
3044 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3045 fd->dfReserved = 0;
3046 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3048 return TRUE;
3051 #define NE_FFLAGS_LIBMODULE 0x8000
3052 #define NE_OSFLAGS_WINDOWS 0x02
3054 static const char dos_string[0x40] = "This is a TrueType resource file";
3055 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3057 #include <pshpack2.h>
3059 struct ne_typeinfo
3061 WORD type_id;
3062 WORD count;
3063 DWORD res;
3066 struct ne_nameinfo
3068 WORD off;
3069 WORD len;
3070 WORD flags;
3071 WORD id;
3072 DWORD res;
3075 struct rsrc_tab
3077 WORD align;
3078 struct ne_typeinfo fontdir_type;
3079 struct ne_nameinfo fontdir_name;
3080 struct ne_typeinfo scalable_type;
3081 struct ne_nameinfo scalable_name;
3082 WORD end_of_rsrc;
3083 BYTE fontdir_res_name[8];
3086 #include <poppack.h>
3088 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3090 BOOL ret = FALSE;
3091 HANDLE file;
3092 DWORD size, written;
3093 BYTE *ptr, *start;
3094 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3095 char *font_fileA, *last_part, *ext;
3096 IMAGE_DOS_HEADER dos;
3097 IMAGE_OS2_HEADER ne =
3099 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3100 0, 0, 0, 0, 0, 0,
3101 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3102 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3104 struct rsrc_tab rsrc_tab =
3107 { 0x8007, 1, 0 },
3108 { 0, 0, 0x0c50, 0x2c, 0 },
3109 { 0x80cc, 1, 0 },
3110 { 0, 0, 0x0c50, 0x8001, 0 },
3112 { 7,'F','O','N','T','D','I','R'}
3115 memset( &dos, 0, sizeof(dos) );
3116 dos.e_magic = IMAGE_DOS_SIGNATURE;
3117 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3119 /* import name is last part\0, resident name is last part without extension
3120 non-resident name is "FONTRES:" + lfFaceName */
3122 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3123 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3124 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3126 last_part = strrchr( font_fileA, '\\' );
3127 if (last_part) last_part++;
3128 else last_part = font_fileA;
3129 import_name_len = strlen( last_part ) + 1;
3131 ext = strchr( last_part, '.' );
3132 if (ext) res_name_len = ext - last_part;
3133 else res_name_len = import_name_len - 1;
3135 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3137 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3138 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3139 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3140 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3141 ne.ne_cbenttab = 2;
3142 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3144 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3145 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3146 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3147 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3149 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3150 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3152 if (!ptr)
3154 HeapFree( GetProcessHeap(), 0, font_fileA );
3155 return FALSE;
3158 memcpy( ptr, &dos, sizeof(dos) );
3159 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3160 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3162 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3163 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3165 ptr = start + dos.e_lfanew + ne.ne_restab;
3166 *ptr++ = res_name_len;
3167 memcpy( ptr, last_part, res_name_len );
3169 ptr = start + dos.e_lfanew + ne.ne_imptab;
3170 *ptr++ = import_name_len;
3171 memcpy( ptr, last_part, import_name_len );
3173 ptr = start + ne.ne_nrestab;
3174 *ptr++ = non_res_name_len;
3175 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3176 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3178 ptr = start + (rsrc_tab.scalable_name.off << 4);
3179 memcpy( ptr, font_fileA, font_file_len );
3181 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3182 memcpy( ptr, fontdir, fontdir->dfSize );
3184 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3185 if (file != INVALID_HANDLE_VALUE)
3187 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3188 ret = TRUE;
3189 CloseHandle( file );
3192 HeapFree( GetProcessHeap(), 0, start );
3193 HeapFree( GetProcessHeap(), 0, font_fileA );
3195 return ret;
3198 /*************************************************************
3199 * WineEngCreateScalableFontResource
3202 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3203 LPCWSTR font_file, LPCWSTR font_path )
3205 char *unix_name = get_ttf_file_name( font_file, font_path );
3206 struct fontdir fontdir;
3207 BOOL ret = FALSE;
3209 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3210 SetLastError( ERROR_INVALID_PARAMETER );
3211 else
3213 if (hidden) fontdir.dfType |= 0x80;
3214 ret = create_fot( resource, font_file, &fontdir );
3217 HeapFree( GetProcessHeap(), 0, unix_name );
3218 return ret;
3221 static const struct nls_update_font_list
3223 UINT ansi_cp, oem_cp;
3224 const char *oem, *fixed, *system;
3225 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3226 /* these are for font substitutes */
3227 const char *shelldlg, *tmsrmn;
3228 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3229 *helv_0, *tmsrmn_0;
3230 const struct subst
3232 const char *from, *to;
3233 } arial_0, courier_new_0, times_new_roman_0;
3234 } nls_update_font_list[] =
3236 /* Latin 1 (United States) */
3237 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3238 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3239 "Tahoma","Times New Roman",
3240 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3241 { 0 }, { 0 }, { 0 }
3243 /* Latin 1 (Multilingual) */
3244 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3245 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3246 "Tahoma","Times New Roman", /* FIXME unverified */
3247 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3248 { 0 }, { 0 }, { 0 }
3250 /* Eastern Europe */
3251 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3252 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3253 "Tahoma","Times New Roman", /* FIXME unverified */
3254 "Fixedsys,238", "System,238",
3255 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3256 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3257 { "Arial CE,0", "Arial,238" },
3258 { "Courier New CE,0", "Courier New,238" },
3259 { "Times New Roman CE,0", "Times New Roman,238" }
3261 /* Cyrillic */
3262 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3263 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3264 "Tahoma","Times New Roman", /* FIXME unverified */
3265 "Fixedsys,204", "System,204",
3266 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3267 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3268 { "Arial Cyr,0", "Arial,204" },
3269 { "Courier New Cyr,0", "Courier New,204" },
3270 { "Times New Roman Cyr,0", "Times New Roman,204" }
3272 /* Greek */
3273 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3274 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3275 "Tahoma","Times New Roman", /* FIXME unverified */
3276 "Fixedsys,161", "System,161",
3277 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3278 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3279 { "Arial Greek,0", "Arial,161" },
3280 { "Courier New Greek,0", "Courier New,161" },
3281 { "Times New Roman Greek,0", "Times New Roman,161" }
3283 /* Turkish */
3284 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3285 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3286 "Tahoma","Times New Roman", /* FIXME unverified */
3287 "Fixedsys,162", "System,162",
3288 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3289 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3290 { "Arial Tur,0", "Arial,162" },
3291 { "Courier New Tur,0", "Courier New,162" },
3292 { "Times New Roman Tur,0", "Times New Roman,162" }
3294 /* Hebrew */
3295 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3296 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3297 "Tahoma","Times New Roman", /* FIXME unverified */
3298 "Fixedsys,177", "System,177",
3299 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3300 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3301 { 0 }, { 0 }, { 0 }
3303 /* Arabic */
3304 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3305 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3306 "Tahoma","Times New Roman", /* FIXME unverified */
3307 "Fixedsys,178", "System,178",
3308 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3309 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3310 { 0 }, { 0 }, { 0 }
3312 /* Baltic */
3313 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3314 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3315 "Tahoma","Times New Roman", /* FIXME unverified */
3316 "Fixedsys,186", "System,186",
3317 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3318 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3319 { "Arial Baltic,0", "Arial,186" },
3320 { "Courier New Baltic,0", "Courier New,186" },
3321 { "Times New Roman Baltic,0", "Times New Roman,186" }
3323 /* Vietnamese */
3324 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3325 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3326 "Tahoma","Times New Roman", /* FIXME unverified */
3327 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3328 { 0 }, { 0 }, { 0 }
3330 /* Thai */
3331 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3332 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3333 "Tahoma","Times New Roman", /* FIXME unverified */
3334 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3335 { 0 }, { 0 }, { 0 }
3337 /* Japanese */
3338 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3339 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3340 "MS UI Gothic","MS Serif",
3341 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3342 { 0 }, { 0 }, { 0 }
3344 /* Chinese Simplified */
3345 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3346 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3347 "SimSun", "NSimSun",
3348 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3349 { 0 }, { 0 }, { 0 }
3351 /* Korean */
3352 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3353 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3354 "Gulim", "Batang",
3355 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3356 { 0 }, { 0 }, { 0 }
3358 /* Chinese Traditional */
3359 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3360 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3361 "PMingLiU", "MingLiU",
3362 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3363 { 0 }, { 0 }, { 0 }
3367 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3369 return ( ansi_cp == 932 /* CP932 for Japanese */
3370 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3371 || ansi_cp == 949 /* CP949 for Korean */
3372 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3375 static inline HKEY create_fonts_NT_registry_key(void)
3377 HKEY hkey = 0;
3379 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3380 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3381 return hkey;
3384 static inline HKEY create_fonts_9x_registry_key(void)
3386 HKEY hkey = 0;
3388 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3389 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3390 return hkey;
3393 static inline HKEY create_config_fonts_registry_key(void)
3395 HKEY hkey = 0;
3397 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3398 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3399 return hkey;
3402 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3404 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3406 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3407 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3408 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3409 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3412 static void set_value_key(HKEY hkey, const char *name, const char *value)
3414 if (value)
3415 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3416 else if (name)
3417 RegDeleteValueA(hkey, name);
3420 static void update_font_info(void)
3422 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3423 char buf[40], cpbuf[40];
3424 DWORD len, type;
3425 HKEY hkey = 0;
3426 UINT i, ansi_cp = 0, oem_cp = 0;
3427 DWORD screen_dpi = 96, font_dpi = 0;
3428 BOOL done = FALSE;
3430 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3431 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3432 &hkey) == ERROR_SUCCESS)
3434 reg_load_dword(hkey, logpixels, &screen_dpi);
3435 RegCloseKey(hkey);
3438 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3439 return;
3441 reg_load_dword(hkey, logpixels, &font_dpi);
3443 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3444 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3445 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3446 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3447 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3449 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3450 if (is_dbcs_ansi_cp(ansi_cp))
3451 use_default_fallback = TRUE;
3453 len = sizeof(buf);
3454 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3456 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3458 RegCloseKey(hkey);
3459 return;
3461 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3462 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3464 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3465 ansi_cp, oem_cp, screen_dpi);
3467 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3468 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3469 RegCloseKey(hkey);
3471 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3473 HKEY hkey;
3475 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3476 nls_update_font_list[i].oem_cp == oem_cp)
3478 hkey = create_config_fonts_registry_key();
3479 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3480 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3481 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3482 RegCloseKey(hkey);
3484 hkey = create_fonts_NT_registry_key();
3485 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3486 RegCloseKey(hkey);
3488 hkey = create_fonts_9x_registry_key();
3489 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3490 RegCloseKey(hkey);
3492 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3494 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3495 strlen(nls_update_font_list[i].shelldlg)+1);
3496 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3497 strlen(nls_update_font_list[i].tmsrmn)+1);
3499 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3500 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3501 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3502 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3503 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3504 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3505 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3506 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3508 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3509 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3510 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3512 RegCloseKey(hkey);
3514 done = TRUE;
3516 else
3518 /* Delete the FontSubstitutes from other locales */
3519 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3521 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3522 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3523 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3524 RegCloseKey(hkey);
3528 if (!done)
3529 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3532 static BOOL init_freetype(void)
3534 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3535 if(!ft_handle) {
3536 WINE_MESSAGE(
3537 "Wine cannot find the FreeType font library. To enable Wine to\n"
3538 "use TrueType fonts please install a version of FreeType greater than\n"
3539 "or equal to 2.0.5.\n"
3540 "http://www.freetype.org\n");
3541 return FALSE;
3544 #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;}
3546 LOAD_FUNCPTR(FT_Done_Face)
3547 LOAD_FUNCPTR(FT_Get_Char_Index)
3548 LOAD_FUNCPTR(FT_Get_First_Char)
3549 LOAD_FUNCPTR(FT_Get_Module)
3550 LOAD_FUNCPTR(FT_Get_Next_Char)
3551 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3552 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3553 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3554 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3555 LOAD_FUNCPTR(FT_Init_FreeType)
3556 LOAD_FUNCPTR(FT_Library_Version)
3557 LOAD_FUNCPTR(FT_Load_Glyph)
3558 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3559 LOAD_FUNCPTR(FT_Matrix_Multiply)
3560 #ifndef FT_MULFIX_INLINED
3561 LOAD_FUNCPTR(FT_MulFix)
3562 #endif
3563 LOAD_FUNCPTR(FT_New_Face)
3564 LOAD_FUNCPTR(FT_New_Memory_Face)
3565 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3566 LOAD_FUNCPTR(FT_Outline_Transform)
3567 LOAD_FUNCPTR(FT_Outline_Translate)
3568 LOAD_FUNCPTR(FT_Render_Glyph)
3569 LOAD_FUNCPTR(FT_Select_Charmap)
3570 LOAD_FUNCPTR(FT_Set_Charmap)
3571 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3572 LOAD_FUNCPTR(FT_Vector_Transform)
3573 LOAD_FUNCPTR(FT_Vector_Unit)
3574 #undef LOAD_FUNCPTR
3575 /* Don't warn if these ones are missing */
3576 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3577 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3578 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3579 #endif
3581 if(pFT_Init_FreeType(&library) != 0) {
3582 ERR("Can't init FreeType library\n");
3583 wine_dlclose(ft_handle, NULL, 0);
3584 ft_handle = NULL;
3585 return FALSE;
3587 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3589 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3590 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3591 ((FT_Version.minor << 8) & 0x00ff00) |
3592 ((FT_Version.patch ) & 0x0000ff);
3594 font_driver = &freetype_funcs;
3595 return TRUE;
3597 sym_not_found:
3598 WINE_MESSAGE(
3599 "Wine cannot find certain functions that it needs inside the FreeType\n"
3600 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3601 "FreeType to at least version 2.1.4.\n"
3602 "http://www.freetype.org\n");
3603 wine_dlclose(ft_handle, NULL, 0);
3604 ft_handle = NULL;
3605 return FALSE;
3608 static void init_font_list(void)
3610 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3611 static const WCHAR pathW[] = {'P','a','t','h',0};
3612 HKEY hkey;
3613 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3614 WCHAR windowsdir[MAX_PATH];
3615 char *unixname;
3616 const char *data_dir;
3618 #ifdef SONAME_LIBFONTCONFIG
3619 init_fontconfig();
3620 #endif
3622 delete_external_font_keys();
3624 /* load the system bitmap fonts */
3625 load_system_fonts();
3627 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3628 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3629 strcatW(windowsdir, fontsW);
3630 if((unixname = wine_get_unix_file_name(windowsdir)))
3632 ReadFontDir(unixname, FALSE);
3633 HeapFree(GetProcessHeap(), 0, unixname);
3636 /* load the system truetype fonts */
3637 data_dir = wine_get_data_dir();
3638 if (!data_dir) data_dir = wine_get_build_dir();
3639 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3641 strcpy(unixname, data_dir);
3642 strcat(unixname, "/fonts/");
3643 ReadFontDir(unixname, TRUE);
3644 HeapFree(GetProcessHeap(), 0, unixname);
3647 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3648 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3649 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3650 will skip these. */
3651 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3652 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3653 &hkey) == ERROR_SUCCESS)
3655 LPWSTR data, valueW;
3656 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3657 &valuelen, &datalen, NULL, NULL);
3659 valuelen++; /* returned value doesn't include room for '\0' */
3660 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3661 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3662 if (valueW && data)
3664 dlen = datalen * sizeof(WCHAR);
3665 vlen = valuelen;
3666 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3667 &dlen) == ERROR_SUCCESS)
3669 if(data[0] && (data[1] == ':'))
3671 if((unixname = wine_get_unix_file_name(data)))
3673 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3674 HeapFree(GetProcessHeap(), 0, unixname);
3677 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3679 WCHAR pathW[MAX_PATH];
3680 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3681 BOOL added = FALSE;
3683 sprintfW(pathW, fmtW, windowsdir, data);
3684 if((unixname = wine_get_unix_file_name(pathW)))
3686 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3687 HeapFree(GetProcessHeap(), 0, unixname);
3689 if (!added)
3690 load_font_from_data_dir(data);
3692 /* reset dlen and vlen */
3693 dlen = datalen;
3694 vlen = valuelen;
3697 HeapFree(GetProcessHeap(), 0, data);
3698 HeapFree(GetProcessHeap(), 0, valueW);
3699 RegCloseKey(hkey);
3702 #ifdef SONAME_LIBFONTCONFIG
3703 load_fontconfig_fonts();
3704 #elif defined(HAVE_CARBON_CARBON_H)
3705 load_mac_fonts();
3706 #endif
3708 /* then look in any directories that we've specified in the config file */
3709 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3710 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3712 DWORD len;
3713 LPWSTR valueW;
3714 LPSTR valueA, ptr;
3716 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3718 len += sizeof(WCHAR);
3719 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3720 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3722 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3723 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3724 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3725 TRACE( "got font path %s\n", debugstr_a(valueA) );
3726 ptr = valueA;
3727 while (ptr)
3729 const char* home;
3730 LPSTR next = strchr( ptr, ':' );
3731 if (next) *next++ = 0;
3732 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3733 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3735 strcpy( unixname, home );
3736 strcat( unixname, ptr + 1 );
3737 ReadFontDir( unixname, TRUE );
3738 HeapFree( GetProcessHeap(), 0, unixname );
3740 else
3741 ReadFontDir( ptr, TRUE );
3742 ptr = next;
3744 HeapFree( GetProcessHeap(), 0, valueA );
3746 HeapFree( GetProcessHeap(), 0, valueW );
3748 RegCloseKey(hkey);
3752 static BOOL move_to_front(const WCHAR *name)
3754 Family *family, *cursor2;
3755 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3757 if(!strcmpiW(family->FamilyName, name))
3759 list_remove(&family->entry);
3760 list_add_head(&font_list, &family->entry);
3761 return TRUE;
3764 return FALSE;
3767 static BOOL set_default(const WCHAR **name_list)
3769 while (*name_list)
3771 if (move_to_front(*name_list)) return TRUE;
3772 name_list++;
3775 return FALSE;
3778 static void reorder_font_list(void)
3780 set_default( default_serif_list );
3781 set_default( default_fixed_list );
3782 set_default( default_sans_list );
3785 /*************************************************************
3786 * WineEngInit
3788 * Initialize FreeType library and create a list of available faces
3790 BOOL WineEngInit(void)
3792 HKEY hkey_font_cache;
3793 DWORD disposition;
3794 HANDLE font_mutex;
3796 /* update locale dependent font info in registry */
3797 update_font_info();
3799 if(!init_freetype()) return FALSE;
3801 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3803 ERR("Failed to create font mutex\n");
3804 return FALSE;
3806 WaitForSingleObject(font_mutex, INFINITE);
3808 create_font_cache_key(&hkey_font_cache, &disposition);
3810 if(disposition == REG_CREATED_NEW_KEY)
3811 init_font_list();
3812 else
3813 load_font_list_from_cache(hkey_font_cache);
3815 RegCloseKey(hkey_font_cache);
3817 reorder_font_list();
3819 DumpFontList();
3820 LoadSubstList();
3821 DumpSubstList();
3822 LoadReplaceList();
3824 if(disposition == REG_CREATED_NEW_KEY)
3825 update_reg_entries();
3827 init_system_links();
3829 ReleaseMutex(font_mutex);
3830 return TRUE;
3834 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3836 TT_OS2 *pOS2;
3837 TT_HoriHeader *pHori;
3839 LONG ppem;
3841 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3842 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3844 if(height == 0) height = 16;
3846 /* Calc. height of EM square:
3848 * For +ve lfHeight we have
3849 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3850 * Re-arranging gives:
3851 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3853 * For -ve lfHeight we have
3854 * |lfHeight| = ppem
3855 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3856 * with il = winAscent + winDescent - units_per_em]
3860 if(height > 0) {
3861 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3862 ppem = MulDiv(ft_face->units_per_EM, height,
3863 pHori->Ascender - pHori->Descender);
3864 else
3865 ppem = MulDiv(ft_face->units_per_EM, height,
3866 pOS2->usWinAscent + pOS2->usWinDescent);
3868 else
3869 ppem = -height;
3871 return ppem;
3874 static struct font_mapping *map_font_file( const char *name )
3876 struct font_mapping *mapping;
3877 struct stat st;
3878 int fd;
3880 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3881 if (fstat( fd, &st ) == -1) goto error;
3883 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3885 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3887 mapping->refcount++;
3888 close( fd );
3889 return mapping;
3892 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3893 goto error;
3895 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3896 close( fd );
3898 if (mapping->data == MAP_FAILED)
3900 HeapFree( GetProcessHeap(), 0, mapping );
3901 return NULL;
3903 mapping->refcount = 1;
3904 mapping->dev = st.st_dev;
3905 mapping->ino = st.st_ino;
3906 mapping->size = st.st_size;
3907 list_add_tail( &mappings_list, &mapping->entry );
3908 return mapping;
3910 error:
3911 close( fd );
3912 return NULL;
3915 static void unmap_font_file( struct font_mapping *mapping )
3917 if (!--mapping->refcount)
3919 list_remove( &mapping->entry );
3920 munmap( mapping->data, mapping->size );
3921 HeapFree( GetProcessHeap(), 0, mapping );
3925 static LONG load_VDMX(GdiFont*, LONG);
3927 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3929 FT_Error err;
3930 FT_Face ft_face;
3931 void *data_ptr;
3932 DWORD data_size;
3934 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
3936 if (face->file)
3938 char *filename = strWtoA( CP_UNIXCP, face->file );
3939 font->mapping = map_font_file( filename );
3940 HeapFree( GetProcessHeap(), 0, filename );
3941 if (!font->mapping)
3943 WARN("failed to map %s\n", debugstr_w(face->file));
3944 return 0;
3946 data_ptr = font->mapping->data;
3947 data_size = font->mapping->size;
3949 else
3951 data_ptr = face->font_data_ptr;
3952 data_size = face->font_data_size;
3955 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3956 if(err) {
3957 ERR("FT_New_Face rets %d\n", err);
3958 return 0;
3961 /* set it here, as load_VDMX needs it */
3962 font->ft_face = ft_face;
3964 if(FT_IS_SCALABLE(ft_face)) {
3965 /* load the VDMX table if we have one */
3966 font->ppem = load_VDMX(font, height);
3967 if(font->ppem == 0)
3968 font->ppem = calc_ppem_for_height(ft_face, height);
3969 TRACE("height %d => ppem %d\n", height, font->ppem);
3971 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3972 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3973 } else {
3974 font->ppem = height;
3975 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3976 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3978 return ft_face;
3982 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3984 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3985 a single face with the requested charset. The idea is to check if
3986 the selected font supports the current ANSI codepage, if it does
3987 return the corresponding charset, else return the first charset */
3989 CHARSETINFO csi;
3990 int acp = GetACP(), i;
3991 DWORD fs0;
3993 *cp = acp;
3994 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3996 const SYSTEM_LINKS *font_link;
3998 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
3999 return csi.ciCharset;
4001 font_link = find_font_link(family_name);
4002 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4003 return csi.ciCharset;
4006 for(i = 0; i < 32; i++) {
4007 fs0 = 1L << i;
4008 if(face->fs.fsCsb[0] & fs0) {
4009 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4010 *cp = csi.ciACP;
4011 return csi.ciCharset;
4013 else
4014 FIXME("TCI failing on %x\n", fs0);
4018 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4019 face->fs.fsCsb[0], debugstr_w(face->file));
4020 *cp = acp;
4021 return DEFAULT_CHARSET;
4024 static GdiFont *alloc_font(void)
4026 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4027 ret->gmsize = 1;
4028 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4029 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4030 ret->potm = NULL;
4031 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4032 ret->total_kern_pairs = (DWORD)-1;
4033 ret->kern_pairs = NULL;
4034 list_init(&ret->hfontlist);
4035 list_init(&ret->child_fonts);
4036 return ret;
4039 static void free_font(GdiFont *font)
4041 CHILD_FONT *child, *child_next;
4042 HFONTLIST *hfontlist, *hfnext;
4043 DWORD i;
4045 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
4047 list_remove(&child->entry);
4048 if(child->font)
4049 free_font(child->font);
4050 HeapFree(GetProcessHeap(), 0, child);
4053 LIST_FOR_EACH_ENTRY_SAFE( hfontlist, hfnext, &font->hfontlist, HFONTLIST, entry )
4055 list_remove(&hfontlist->entry);
4056 HeapFree(GetProcessHeap(), 0, hfontlist);
4059 if (font->ft_face) pFT_Done_Face(font->ft_face);
4060 if (font->mapping) unmap_font_file( font->mapping );
4061 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4062 HeapFree(GetProcessHeap(), 0, font->potm);
4063 HeapFree(GetProcessHeap(), 0, font->name);
4064 for (i = 0; i < font->gmsize; i++)
4065 HeapFree(GetProcessHeap(),0,font->gm[i]);
4066 HeapFree(GetProcessHeap(), 0, font->gm);
4067 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4068 HeapFree(GetProcessHeap(), 0, font);
4072 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4074 FT_Face ft_face = font->ft_face;
4075 FT_ULong len;
4076 FT_Error err;
4078 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4080 if(!buf)
4081 len = 0;
4082 else
4083 len = cbData;
4085 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4087 /* make sure value of len is the value freetype says it needs */
4088 if (buf && len)
4090 FT_ULong needed = 0;
4091 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4092 if( !err && needed < len) len = needed;
4094 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4095 if (err)
4097 TRACE("Can't find table %c%c%c%c\n",
4098 /* bytes were reversed */
4099 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4100 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4101 return GDI_ERROR;
4103 return len;
4106 /*************************************************************
4107 * load_VDMX
4109 * load the vdmx entry for the specified height
4112 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4113 ( ( (FT_ULong)_x4 << 24 ) | \
4114 ( (FT_ULong)_x3 << 16 ) | \
4115 ( (FT_ULong)_x2 << 8 ) | \
4116 (FT_ULong)_x1 )
4118 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4120 typedef struct {
4121 BYTE bCharSet;
4122 BYTE xRatio;
4123 BYTE yStartRatio;
4124 BYTE yEndRatio;
4125 } Ratios;
4127 typedef struct {
4128 WORD recs;
4129 BYTE startsz;
4130 BYTE endsz;
4131 } VDMX_group;
4133 static LONG load_VDMX(GdiFont *font, LONG height)
4135 WORD hdr[3], tmp;
4136 VDMX_group group;
4137 BYTE devXRatio, devYRatio;
4138 USHORT numRecs, numRatios;
4139 DWORD result, offset = -1;
4140 LONG ppem = 0;
4141 int i;
4143 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
4145 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4146 return ppem;
4148 /* FIXME: need the real device aspect ratio */
4149 devXRatio = 1;
4150 devYRatio = 1;
4152 numRecs = GET_BE_WORD(hdr[1]);
4153 numRatios = GET_BE_WORD(hdr[2]);
4155 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4156 for(i = 0; i < numRatios; i++) {
4157 Ratios ratio;
4159 offset = (3 * 2) + (i * sizeof(Ratios));
4160 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4161 offset = -1;
4163 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4165 if((ratio.xRatio == 0 &&
4166 ratio.yStartRatio == 0 &&
4167 ratio.yEndRatio == 0) ||
4168 (devXRatio == ratio.xRatio &&
4169 devYRatio >= ratio.yStartRatio &&
4170 devYRatio <= ratio.yEndRatio))
4172 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4173 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4174 offset = GET_BE_WORD(tmp);
4175 break;
4179 if(offset == -1) {
4180 FIXME("No suitable ratio found\n");
4181 return ppem;
4184 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4185 USHORT recs;
4186 BYTE startsz, endsz;
4187 WORD *vTable;
4189 recs = GET_BE_WORD(group.recs);
4190 startsz = group.startsz;
4191 endsz = group.endsz;
4193 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4195 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4196 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4197 if(result == GDI_ERROR) {
4198 FIXME("Failed to retrieve vTable\n");
4199 goto end;
4202 if(height > 0) {
4203 for(i = 0; i < recs; i++) {
4204 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4205 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4206 ppem = GET_BE_WORD(vTable[i * 3]);
4208 if(yMax + -yMin == height) {
4209 font->yMax = yMax;
4210 font->yMin = yMin;
4211 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4212 break;
4214 if(yMax + -yMin > height) {
4215 if(--i < 0) {
4216 ppem = 0;
4217 goto end; /* failed */
4219 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4220 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4221 ppem = GET_BE_WORD(vTable[i * 3]);
4222 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4223 break;
4226 if(!font->yMax) {
4227 ppem = 0;
4228 TRACE("ppem not found for height %d\n", height);
4231 end:
4232 HeapFree(GetProcessHeap(), 0, vTable);
4235 return ppem;
4238 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4240 if(font->font_desc.hash != fd->hash) return TRUE;
4241 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4242 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4243 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4244 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4247 static void calc_hash(FONT_DESC *pfd)
4249 DWORD hash = 0, *ptr, two_chars;
4250 WORD *pwc;
4251 unsigned int i;
4253 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4254 hash ^= *ptr;
4255 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4256 hash ^= *ptr;
4257 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4258 two_chars = *ptr;
4259 pwc = (WCHAR *)&two_chars;
4260 if(!*pwc) break;
4261 *pwc = toupperW(*pwc);
4262 pwc++;
4263 *pwc = toupperW(*pwc);
4264 hash ^= two_chars;
4265 if(!*pwc) break;
4267 hash ^= !pfd->can_use_bitmap;
4268 pfd->hash = hash;
4269 return;
4272 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4274 GdiFont *ret, *next;
4275 FONT_DESC fd;
4276 HFONTLIST *hflist;
4278 fd.lf = *plf;
4279 fd.matrix = *pmat;
4280 fd.can_use_bitmap = can_use_bitmap;
4281 calc_hash(&fd);
4283 /* try the in-use list */
4284 LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
4286 if(fontcmp(ret, &fd)) continue;
4287 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4288 LIST_FOR_EACH_ENTRY( hflist, &ret->hfontlist, struct tagHFONTLIST, entry )
4289 if(hflist->hfont == hfont) return ret;
4291 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4292 hflist->hfont = hfont;
4293 list_add_head(&ret->hfontlist, &hflist->entry);
4294 return ret;
4297 /* then the unused list */
4298 LIST_FOR_EACH_ENTRY_SAFE( ret, next, &unused_gdi_font_list, struct tagGdiFont, entry )
4300 if(fontcmp(ret, &fd)) continue;
4301 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4303 assert(list_empty(&ret->hfontlist));
4304 TRACE("Found %p in unused list\n", ret);
4305 list_remove(&ret->entry);
4306 list_add_head(&gdi_font_list, &ret->entry);
4307 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4308 hflist->hfont = hfont;
4309 list_add_head(&ret->hfontlist, &hflist->entry);
4310 return ret;
4312 return NULL;
4315 static void add_to_cache(GdiFont *font)
4317 static DWORD cache_num = 1;
4319 font->cache_num = cache_num++;
4320 list_add_head(&gdi_font_list, &font->entry);
4323 /*************************************************************
4324 * create_child_font_list
4326 static BOOL create_child_font_list(GdiFont *font)
4328 BOOL ret = FALSE;
4329 SYSTEM_LINKS *font_link;
4330 CHILD_FONT *font_link_entry, *new_child;
4331 FontSubst *psub;
4332 WCHAR* font_name;
4334 psub = get_font_subst(&font_subst_list, font->name, -1);
4335 font_name = psub ? psub->to.name : font->name;
4336 font_link = find_font_link(font_name);
4337 if (font_link != NULL)
4339 TRACE("found entry in system list\n");
4340 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4342 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4343 new_child->face = font_link_entry->face;
4344 new_child->font = NULL;
4345 list_add_tail(&font->child_fonts, &new_child->entry);
4346 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4348 ret = TRUE;
4351 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4352 * Sans Serif. This is how asian windows get default fallbacks for fonts
4354 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4355 font->charset != OEM_CHARSET &&
4356 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4358 font_link = find_font_link(szDefaultFallbackLink);
4359 if (font_link != NULL)
4361 TRACE("found entry in default fallback list\n");
4362 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4364 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4365 new_child->face = font_link_entry->face;
4366 new_child->font = NULL;
4367 list_add_tail(&font->child_fonts, &new_child->entry);
4368 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4370 ret = TRUE;
4374 return ret;
4377 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4379 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4381 if (pFT_Set_Charmap)
4383 FT_Int i;
4384 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4386 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4388 for (i = 0; i < ft_face->num_charmaps; i++)
4390 if (ft_face->charmaps[i]->encoding == encoding)
4392 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4393 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4395 switch (ft_face->charmaps[i]->platform_id)
4397 default:
4398 cmap_def = ft_face->charmaps[i];
4399 break;
4400 case 0: /* Apple Unicode */
4401 cmap0 = ft_face->charmaps[i];
4402 break;
4403 case 1: /* Macintosh */
4404 cmap1 = ft_face->charmaps[i];
4405 break;
4406 case 2: /* ISO */
4407 cmap2 = ft_face->charmaps[i];
4408 break;
4409 case 3: /* Microsoft */
4410 cmap3 = ft_face->charmaps[i];
4411 break;
4415 if (cmap3) /* prefer Microsoft cmap table */
4416 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4417 else if (cmap1)
4418 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4419 else if (cmap2)
4420 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4421 else if (cmap0)
4422 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4423 else if (cmap_def)
4424 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4426 return ft_err == FT_Err_Ok;
4429 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4433 /*************************************************************
4434 * freetype_CreateDC
4436 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4437 LPCWSTR output, const DEVMODEW *devmode )
4439 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4441 if (!physdev) return FALSE;
4442 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4443 return TRUE;
4447 /*************************************************************
4448 * freetype_DeleteDC
4450 static BOOL freetype_DeleteDC( PHYSDEV dev )
4452 struct freetype_physdev *physdev = get_freetype_dev( dev );
4453 HeapFree( GetProcessHeap(), 0, physdev );
4454 return TRUE;
4457 static FT_Encoding pick_charmap( FT_Face face, int charset )
4459 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
4460 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
4461 const FT_Encoding *encs = regular_order;
4463 if (charset == SYMBOL_CHARSET) encs = symbol_order;
4465 while (*encs != 0)
4467 if (select_charmap( face, *encs )) break;
4468 encs++;
4470 return *encs;
4473 #define GASP_GRIDFIT 0x01
4474 #define GASP_DOGRAY 0x02
4475 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4477 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
4479 DWORD size;
4480 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
4481 WORD *alloced = NULL, *ptr = buf;
4482 WORD num_recs, version;
4483 BOOL ret = FALSE;
4485 *flags = 0;
4486 size = get_font_data( font, GASP_TAG, 0, NULL, 0 );
4487 if (size == GDI_ERROR) return FALSE;
4488 if (size < 4 * sizeof(WORD)) return FALSE;
4489 if (size > sizeof(buf))
4491 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
4492 if (!ptr) return FALSE;
4495 get_font_data( font, GASP_TAG, 0, ptr, size );
4497 version = GET_BE_WORD( *ptr++ );
4498 num_recs = GET_BE_WORD( *ptr++ );
4500 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
4502 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
4503 goto done;
4506 while (num_recs--)
4508 *flags = GET_BE_WORD( *(ptr + 1) );
4509 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
4510 ptr += 2;
4512 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
4513 ret = TRUE;
4515 done:
4516 HeapFree( GetProcessHeap(), 0, alloced );
4517 return ret;
4520 /*************************************************************
4521 * freetype_SelectFont
4523 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
4525 struct freetype_physdev *physdev = get_freetype_dev( dev );
4526 GdiFont *ret;
4527 Face *face, *best, *best_bitmap;
4528 Family *family, *last_resort_family;
4529 const struct list *face_list;
4530 INT height, width = 0;
4531 unsigned int score = 0, new_score;
4532 signed int diff = 0, newdiff;
4533 BOOL bd, it, can_use_bitmap, want_vertical;
4534 LOGFONTW lf;
4535 CHARSETINFO csi;
4536 HFONTLIST *hflist;
4537 FMAT2 dcmat;
4538 FontSubst *psub = NULL;
4539 DC *dc = get_dc_ptr( dev->hdc );
4540 const SYSTEM_LINKS *font_link;
4542 if (!hfont) /* notification that the font has been changed by another driver */
4544 physdev->font = NULL;
4545 release_dc_ptr( dc );
4546 return 0;
4549 GetObjectW( hfont, sizeof(lf), &lf );
4550 lf.lfWidth = abs(lf.lfWidth);
4552 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4554 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4555 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4556 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4557 lf.lfEscapement);
4559 if(dc->GraphicsMode == GM_ADVANCED)
4561 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4562 /* Try to avoid not necessary glyph transformations */
4563 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4565 lf.lfHeight *= fabs(dcmat.eM11);
4566 lf.lfWidth *= fabs(dcmat.eM11);
4567 dcmat.eM11 = dcmat.eM22 = 1.0;
4570 else
4572 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4573 font scaling abilities. */
4574 dcmat.eM11 = dcmat.eM22 = 1.0;
4575 dcmat.eM21 = dcmat.eM12 = 0;
4576 if (dc->vport2WorldValid)
4578 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4579 lf.lfOrientation = -lf.lfOrientation;
4580 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4581 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4585 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4586 dcmat.eM21, dcmat.eM22);
4588 GDI_CheckNotLock();
4589 EnterCriticalSection( &freetype_cs );
4591 /* check the cache first */
4592 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4593 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4594 goto done;
4597 if(list_empty(&font_list)) /* No fonts installed */
4599 TRACE("No fonts installed\n");
4600 goto done;
4603 TRACE("not in cache\n");
4604 ret = alloc_font();
4606 ret->font_desc.matrix = dcmat;
4607 ret->font_desc.lf = lf;
4608 ret->font_desc.can_use_bitmap = can_use_bitmap;
4609 calc_hash(&ret->font_desc);
4610 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4611 hflist->hfont = hfont;
4612 list_add_head(&ret->hfontlist, &hflist->entry);
4614 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4615 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4616 original value lfCharSet. Note this is a special case for
4617 Symbol and doesn't happen at least for "Wingdings*" */
4619 if(!strcmpiW(lf.lfFaceName, SymbolW))
4620 lf.lfCharSet = SYMBOL_CHARSET;
4622 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4623 switch(lf.lfCharSet) {
4624 case DEFAULT_CHARSET:
4625 csi.fs.fsCsb[0] = 0;
4626 break;
4627 default:
4628 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4629 csi.fs.fsCsb[0] = 0;
4630 break;
4634 family = NULL;
4635 if(lf.lfFaceName[0] != '\0') {
4636 CHILD_FONT *font_link_entry;
4637 LPWSTR FaceName = lf.lfFaceName;
4639 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4641 if(psub) {
4642 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4643 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4644 if (psub->to.charset != -1)
4645 lf.lfCharSet = psub->to.charset;
4648 /* We want a match on name and charset or just name if
4649 charset was DEFAULT_CHARSET. If the latter then
4650 we fixup the returned charset later in get_nearest_charset
4651 where we'll either use the charset of the current ansi codepage
4652 or if that's unavailable the first charset that the font supports.
4654 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4655 if (!strcmpiW(family->FamilyName, FaceName) ||
4656 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4658 font_link = find_font_link(family->FamilyName);
4659 face_list = get_face_list_from_family(family);
4660 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4661 if (!(face->scalable || can_use_bitmap))
4662 continue;
4663 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4664 goto found;
4665 if (font_link != NULL &&
4666 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4667 goto found;
4668 if (!csi.fs.fsCsb[0])
4669 goto found;
4674 /* Search by full face name. */
4675 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4676 face_list = get_face_list_from_family(family);
4677 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4678 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4679 (face->scalable || can_use_bitmap))
4681 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4682 goto found_face;
4683 font_link = find_font_link(family->FamilyName);
4684 if (font_link != NULL &&
4685 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4686 goto found_face;
4692 * Try check the SystemLink list first for a replacement font.
4693 * We may find good replacements there.
4695 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4697 if(!strcmpiW(font_link->font_name, FaceName) ||
4698 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4700 TRACE("found entry in system list\n");
4701 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4703 const SYSTEM_LINKS *links;
4705 face = font_link_entry->face;
4706 if (!(face->scalable || can_use_bitmap))
4707 continue;
4708 family = face->family;
4709 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4710 goto found;
4711 links = find_font_link(family->FamilyName);
4712 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4713 goto found;
4719 psub = NULL; /* substitution is no more relevant */
4721 /* If requested charset was DEFAULT_CHARSET then try using charset
4722 corresponding to the current ansi codepage */
4723 if (!csi.fs.fsCsb[0])
4725 INT acp = GetACP();
4726 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4727 FIXME("TCI failed on codepage %d\n", acp);
4728 csi.fs.fsCsb[0] = 0;
4729 } else
4730 lf.lfCharSet = csi.ciCharset;
4733 want_vertical = (lf.lfFaceName[0] == '@');
4735 /* Face families are in the top 4 bits of lfPitchAndFamily,
4736 so mask with 0xF0 before testing */
4738 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4739 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4740 strcpyW(lf.lfFaceName, defFixed);
4741 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4742 strcpyW(lf.lfFaceName, defSerif);
4743 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4744 strcpyW(lf.lfFaceName, defSans);
4745 else
4746 strcpyW(lf.lfFaceName, defSans);
4747 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4748 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4749 font_link = find_font_link(family->FamilyName);
4750 face_list = get_face_list_from_family(family);
4751 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4752 if (!(face->scalable || can_use_bitmap))
4753 continue;
4754 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4755 goto found;
4756 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4757 goto found;
4762 last_resort_family = NULL;
4763 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4764 font_link = find_font_link(family->FamilyName);
4765 face_list = get_face_list_from_family(family);
4766 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4767 if(face->vertical == want_vertical &&
4768 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4769 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4770 if(face->scalable)
4771 goto found;
4772 if(can_use_bitmap && !last_resort_family)
4773 last_resort_family = family;
4778 if(last_resort_family) {
4779 family = last_resort_family;
4780 csi.fs.fsCsb[0] = 0;
4781 goto found;
4784 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4785 face_list = get_face_list_from_family(family);
4786 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4787 if(face->scalable && face->vertical == want_vertical) {
4788 csi.fs.fsCsb[0] = 0;
4789 WARN("just using first face for now\n");
4790 goto found;
4792 if(can_use_bitmap && !last_resort_family)
4793 last_resort_family = family;
4796 if(!last_resort_family) {
4797 FIXME("can't find a single appropriate font - bailing\n");
4798 free_font(ret);
4799 ret = NULL;
4800 goto done;
4803 WARN("could only find a bitmap font - this will probably look awful!\n");
4804 family = last_resort_family;
4805 csi.fs.fsCsb[0] = 0;
4807 found:
4808 it = lf.lfItalic ? 1 : 0;
4809 bd = lf.lfWeight > 550 ? 1 : 0;
4811 height = lf.lfHeight;
4813 face = best = best_bitmap = NULL;
4814 font_link = find_font_link(family->FamilyName);
4815 face_list = get_face_list_from_family(family);
4816 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4818 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4819 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4820 !csi.fs.fsCsb[0])
4822 BOOL italic, bold;
4824 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4825 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4826 new_score = (italic ^ it) + (bold ^ bd);
4827 if(!best || new_score <= score)
4829 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4830 italic, bold, it, bd);
4831 score = new_score;
4832 best = face;
4833 if(best->scalable && score == 0) break;
4834 if(!best->scalable)
4836 if(height > 0)
4837 newdiff = height - (signed int)(best->size.height);
4838 else
4839 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4840 if(!best_bitmap || new_score < score ||
4841 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4843 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4844 diff = newdiff;
4845 best_bitmap = best;
4846 if(score == 0 && diff == 0) break;
4852 if(best)
4853 face = best->scalable ? best : best_bitmap;
4854 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4855 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4857 found_face:
4858 height = lf.lfHeight;
4860 ret->fs = face->fs;
4862 if(csi.fs.fsCsb[0]) {
4863 ret->charset = lf.lfCharSet;
4864 ret->codepage = csi.ciACP;
4866 else
4867 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4869 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4870 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
4872 ret->aveWidth = height ? lf.lfWidth : 0;
4874 if(!face->scalable) {
4875 /* Windows uses integer scaling factors for bitmap fonts */
4876 INT scale, scaled_height;
4877 GdiFont *cachedfont;
4879 /* FIXME: rotation of bitmap fonts is ignored */
4880 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4881 if (ret->aveWidth)
4882 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4883 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4884 dcmat.eM11 = dcmat.eM22 = 1.0;
4885 /* As we changed the matrix, we need to search the cache for the font again,
4886 * otherwise we might explode the cache. */
4887 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4888 TRACE("Found cached font after non-scalable matrix rescale!\n");
4889 free_font( ret );
4890 ret = cachedfont;
4891 goto done;
4893 calc_hash(&ret->font_desc);
4895 if (height != 0) height = diff;
4896 height += face->size.height;
4898 scale = (height + face->size.height - 1) / face->size.height;
4899 scaled_height = scale * face->size.height;
4900 /* Only jump to the next height if the difference <= 25% original height */
4901 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4902 /* The jump between unscaled and doubled is delayed by 1 */
4903 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4904 ret->scale_y = scale;
4906 width = face->size.x_ppem >> 6;
4907 height = face->size.y_ppem >> 6;
4909 else
4910 ret->scale_y = 1.0;
4911 TRACE("font scale y: %f\n", ret->scale_y);
4913 ret->ft_face = OpenFontFace(ret, face, width, height);
4915 if (!ret->ft_face)
4917 free_font( ret );
4918 ret = NULL;
4919 goto done;
4922 ret->ntmFlags = face->ntmFlags;
4924 pick_charmap( ret->ft_face, ret->charset );
4926 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4927 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4928 ret->underline = lf.lfUnderline ? 0xff : 0;
4929 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4930 create_child_font_list(ret);
4932 if (face->vertical) /* We need to try to load the GSUB table */
4934 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4935 if (length != GDI_ERROR)
4937 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4938 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4939 TRACE("Loaded GSUB table of %i bytes\n",length);
4942 ret->aa_flags = face->aa_flags;
4944 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4946 add_to_cache(ret);
4947 done:
4948 if (ret)
4950 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
4952 switch (lf.lfQuality)
4954 case NONANTIALIASED_QUALITY:
4955 case ANTIALIASED_QUALITY:
4956 next->funcs->pSelectFont( dev, hfont, aa_flags );
4957 break;
4958 case CLEARTYPE_QUALITY:
4959 case CLEARTYPE_NATURAL_QUALITY:
4960 default:
4961 if (!*aa_flags) *aa_flags = ret->aa_flags;
4962 next->funcs->pSelectFont( dev, hfont, aa_flags );
4964 /* fixup the antialiasing flags for that font */
4965 switch (*aa_flags)
4967 case WINE_GGO_HRGB_BITMAP:
4968 case WINE_GGO_HBGR_BITMAP:
4969 case WINE_GGO_VRGB_BITMAP:
4970 case WINE_GGO_VBGR_BITMAP:
4971 if (is_subpixel_rendering_enabled()) break;
4972 *aa_flags = GGO_GRAY4_BITMAP;
4973 /* fall through */
4974 case GGO_GRAY2_BITMAP:
4975 case GGO_GRAY4_BITMAP:
4976 case GGO_GRAY8_BITMAP:
4977 case WINE_GGO_GRAY16_BITMAP:
4978 if (is_hinting_enabled())
4980 WORD gasp_flags;
4981 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
4983 TRACE( "font %s %d aa disabled by GASP\n",
4984 debugstr_w(lf.lfFaceName), lf.lfHeight );
4985 *aa_flags = GGO_BITMAP;
4990 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
4991 physdev->font = ret;
4993 LeaveCriticalSection( &freetype_cs );
4994 release_dc_ptr( dc );
4995 return ret ? hfont : 0;
4998 static void dump_gdi_font_list(void)
5000 GdiFont *gdiFont;
5002 TRACE("---------- gdiFont Cache ----------\n");
5003 LIST_FOR_EACH_ENTRY( gdiFont, &gdi_font_list, struct tagGdiFont, entry )
5004 TRACE("gdiFont=%p %s %d\n",
5005 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
5007 TRACE("---------- Unused gdiFont Cache ----------\n");
5008 LIST_FOR_EACH_ENTRY( gdiFont, &unused_gdi_font_list, struct tagGdiFont, entry )
5009 TRACE("gdiFont=%p %s %d\n",
5010 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
5013 /*************************************************************
5014 * WineEngDestroyFontInstance
5016 * free the gdiFont associated with this handle
5019 BOOL WineEngDestroyFontInstance(HFONT handle)
5021 GdiFont *gdiFont, *next;
5022 HFONTLIST *hflist, *hfnext;
5023 BOOL ret = FALSE;
5024 int i = 0;
5026 GDI_CheckNotLock();
5027 EnterCriticalSection( &freetype_cs );
5029 TRACE("destroying hfont=%p\n", handle);
5030 if(TRACE_ON(font))
5031 dump_gdi_font_list();
5033 LIST_FOR_EACH_ENTRY_SAFE( gdiFont, next, &gdi_font_list, struct tagGdiFont, entry )
5035 LIST_FOR_EACH_ENTRY_SAFE( hflist, hfnext, &gdiFont->hfontlist, struct tagHFONTLIST, entry )
5037 if(hflist->hfont == handle) {
5038 list_remove(&hflist->entry);
5039 HeapFree(GetProcessHeap(), 0, hflist);
5040 ret = TRUE;
5043 if(list_empty(&gdiFont->hfontlist)) {
5044 TRACE("Moving to Unused list\n");
5045 list_remove(&gdiFont->entry);
5046 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
5051 LIST_FOR_EACH_ENTRY_SAFE( gdiFont, next, &unused_gdi_font_list, struct tagGdiFont, entry )
5053 if (i++ < UNUSED_CACHE_SIZE) continue;
5054 TRACE("freeing %p\n", gdiFont);
5055 list_remove(&gdiFont->entry);
5056 free_font(gdiFont);
5058 LeaveCriticalSection( &freetype_cs );
5059 return ret;
5062 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5064 HRSRC rsrc;
5065 HGLOBAL hMem;
5066 WCHAR *p;
5067 int i;
5069 id += IDS_FIRST_SCRIPT;
5070 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5071 if (!rsrc) return 0;
5072 hMem = LoadResource( gdi32_module, rsrc );
5073 if (!hMem) return 0;
5075 p = LockResource( hMem );
5076 id &= 0x000f;
5077 while (id--) p += *p + 1;
5079 i = min(LF_FACESIZE - 1, *p);
5080 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5081 buffer[i] = 0;
5082 return i;
5086 /***************************************************
5087 * create_enum_charset_list
5089 * This function creates charset enumeration list because in DEFAULT_CHARSET
5090 * case, the ANSI codepage's charset takes precedence over other charsets.
5091 * This function works as a filter other than DEFAULT_CHARSET case.
5093 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5095 CHARSETINFO csi;
5096 DWORD n = 0;
5098 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5099 csi.fs.fsCsb[0] != 0) {
5100 list->element[n].mask = csi.fs.fsCsb[0];
5101 list->element[n].charset = csi.ciCharset;
5102 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5103 n++;
5105 else { /* charset is DEFAULT_CHARSET or invalid. */
5106 INT acp, i;
5107 DWORD mask = 0;
5109 /* Set the current codepage's charset as the first element. */
5110 acp = GetACP();
5111 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5112 csi.fs.fsCsb[0] != 0) {
5113 list->element[n].mask = csi.fs.fsCsb[0];
5114 list->element[n].charset = csi.ciCharset;
5115 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5116 mask |= csi.fs.fsCsb[0];
5117 n++;
5120 /* Fill out left elements. */
5121 for (i = 0; i < 32; i++) {
5122 FONTSIGNATURE fs;
5123 fs.fsCsb[0] = 1L << i;
5124 fs.fsCsb[1] = 0;
5125 if (fs.fsCsb[0] & mask)
5126 continue; /* skip, already added. */
5127 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5128 continue; /* skip, this is an invalid fsCsb bit. */
5130 list->element[n].mask = fs.fsCsb[0];
5131 list->element[n].charset = csi.ciCharset;
5132 load_script_name( i, list->element[n].name );
5133 mask |= fs.fsCsb[0];
5134 n++;
5137 /* add catch all mask for remaining bits */
5138 if (~mask)
5140 list->element[n].mask = ~mask;
5141 list->element[n].charset = DEFAULT_CHARSET;
5142 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5143 n++;
5146 list->total = n;
5148 return n;
5151 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
5152 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5154 GdiFont *font;
5155 LONG width, height;
5157 if (face->cached_enum_data)
5159 TRACE("Cached\n");
5160 *pelf = face->cached_enum_data->elf;
5161 *pntm = face->cached_enum_data->ntm;
5162 *ptype = face->cached_enum_data->type;
5163 return;
5166 font = alloc_font();
5168 if(face->scalable) {
5169 height = 100;
5170 width = 0;
5171 } else {
5172 height = face->size.y_ppem >> 6;
5173 width = face->size.x_ppem >> 6;
5175 font->scale_y = 1.0;
5177 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5179 free_font(font);
5180 return;
5183 font->name = strdupW(face->family->FamilyName);
5184 font->ntmFlags = face->ntmFlags;
5186 if (get_outline_text_metrics(font))
5188 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5190 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5191 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5192 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5194 lstrcpynW(pelf->elfLogFont.lfFaceName,
5195 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5196 LF_FACESIZE);
5197 lstrcpynW(pelf->elfFullName,
5198 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5199 LF_FULLFACESIZE);
5200 lstrcpynW(pelf->elfStyle,
5201 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5202 LF_FACESIZE);
5204 else
5206 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5208 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5209 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5210 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5212 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
5213 if (face->FullName)
5214 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5215 else
5216 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
5217 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5220 pntm->ntmTm.ntmFlags = face->ntmFlags;
5221 pntm->ntmFontSig = face->fs;
5223 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5225 pelf->elfLogFont.lfEscapement = 0;
5226 pelf->elfLogFont.lfOrientation = 0;
5227 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5228 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5229 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5230 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5231 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5232 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5233 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5234 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5235 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5236 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5237 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5239 *ptype = 0;
5240 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5241 *ptype |= TRUETYPE_FONTTYPE;
5242 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5243 *ptype |= DEVICE_FONTTYPE;
5244 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5245 *ptype |= RASTER_FONTTYPE;
5247 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5248 if (face->cached_enum_data)
5250 face->cached_enum_data->elf = *pelf;
5251 face->cached_enum_data->ntm = *pntm;
5252 face->cached_enum_data->type = *ptype;
5255 free_font(font);
5258 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5260 Face *face;
5261 const struct list *face_list;
5263 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5265 face_list = get_face_list_from_family(family);
5266 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5267 if (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName)) return TRUE;
5269 return FALSE;
5272 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5274 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5276 return (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName));
5279 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5280 FONTENUMPROCW proc, LPARAM lparam)
5282 ENUMLOGFONTEXW elf;
5283 NEWTEXTMETRICEXW ntm;
5284 DWORD type = 0;
5285 int i;
5287 GetEnumStructs(face, &elf, &ntm, &type);
5288 for(i = 0; i < list->total; i++) {
5289 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5290 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5291 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
5292 i = list->total; /* break out of loop after enumeration */
5294 else
5296 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
5297 /* use the DEFAULT_CHARSET case only if no other charset is present */
5298 if (list->element[i].charset == DEFAULT_CHARSET &&
5299 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
5300 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5301 strcpyW(elf.elfScript, list->element[i].name);
5302 if (!elf.elfScript[0])
5303 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5305 /* Font Replacement */
5306 if (family != face->family)
5308 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5309 if (face->FullName)
5310 strcpyW(elf.elfFullName, face->FullName);
5311 else
5312 strcpyW(elf.elfFullName, family->FamilyName);
5314 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5315 debugstr_w(elf.elfLogFont.lfFaceName),
5316 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5317 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5318 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5319 ntm.ntmTm.ntmFlags);
5320 /* release section before callback (FIXME) */
5321 LeaveCriticalSection( &freetype_cs );
5322 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5323 EnterCriticalSection( &freetype_cs );
5325 return TRUE;
5328 /*************************************************************
5329 * freetype_EnumFonts
5331 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5333 Family *family;
5334 Face *face;
5335 const struct list *face_list;
5336 LOGFONTW lf;
5337 struct enum_charset_list enum_charsets;
5339 if (!plf)
5341 lf.lfCharSet = DEFAULT_CHARSET;
5342 lf.lfPitchAndFamily = 0;
5343 lf.lfFaceName[0] = 0;
5344 plf = &lf;
5347 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5349 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5351 GDI_CheckNotLock();
5352 EnterCriticalSection( &freetype_cs );
5353 if(plf->lfFaceName[0]) {
5354 FontSubst *psub;
5355 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5357 if(psub) {
5358 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5359 debugstr_w(psub->to.name));
5360 lf = *plf;
5361 strcpyW(lf.lfFaceName, psub->to.name);
5362 plf = &lf;
5365 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5366 if (!family_matches(family, plf)) continue;
5367 face_list = get_face_list_from_family(family);
5368 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5369 if (!face_matches(family->FamilyName, face, plf)) continue;
5370 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5373 } else {
5374 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5375 face_list = get_face_list_from_family(family);
5376 face = LIST_ENTRY(list_head(face_list), Face, entry);
5377 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5380 LeaveCriticalSection( &freetype_cs );
5381 return TRUE;
5384 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5386 pt->x.value = vec->x >> 6;
5387 pt->x.fract = (vec->x & 0x3f) << 10;
5388 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5389 pt->y.value = vec->y >> 6;
5390 pt->y.fract = (vec->y & 0x3f) << 10;
5391 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5392 return;
5395 /***************************************************
5396 * According to the MSDN documentation on WideCharToMultiByte,
5397 * certain codepages cannot set the default_used parameter.
5398 * This returns TRUE if the codepage can set that parameter, false else
5399 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5401 static BOOL codepage_sets_default_used(UINT codepage)
5403 switch (codepage)
5405 case CP_UTF7:
5406 case CP_UTF8:
5407 case CP_SYMBOL:
5408 return FALSE;
5409 default:
5410 return TRUE;
5415 * GSUB Table handling functions
5418 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5420 const GSUB_CoverageFormat1* cf1;
5422 cf1 = table;
5424 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5426 int count = GET_BE_WORD(cf1->GlyphCount);
5427 int i;
5428 TRACE("Coverage Format 1, %i glyphs\n",count);
5429 for (i = 0; i < count; i++)
5430 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5431 return i;
5432 return -1;
5434 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5436 const GSUB_CoverageFormat2* cf2;
5437 int i;
5438 int count;
5439 cf2 = (const GSUB_CoverageFormat2*)cf1;
5441 count = GET_BE_WORD(cf2->RangeCount);
5442 TRACE("Coverage Format 2, %i ranges\n",count);
5443 for (i = 0; i < count; i++)
5445 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5446 return -1;
5447 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5448 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5450 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5451 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5454 return -1;
5456 else
5457 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5459 return -1;
5462 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5464 const GSUB_ScriptList *script;
5465 const GSUB_Script *deflt = NULL;
5466 int i;
5467 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5469 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5470 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5472 const GSUB_Script *scr;
5473 int offset;
5475 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5476 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5478 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5479 return scr;
5480 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5481 deflt = scr;
5483 return deflt;
5486 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5488 int i;
5489 int offset;
5490 const GSUB_LangSys *Lang;
5492 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5494 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5496 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5497 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5499 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5500 return Lang;
5502 offset = GET_BE_WORD(script->DefaultLangSys);
5503 if (offset)
5505 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5506 return Lang;
5508 return NULL;
5511 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5513 int i;
5514 const GSUB_FeatureList *feature;
5515 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5517 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5518 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5520 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5521 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5523 const GSUB_Feature *feat;
5524 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5525 return feat;
5528 return NULL;
5531 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5533 int i;
5534 int offset;
5535 const GSUB_LookupList *lookup;
5536 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5538 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5539 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5541 const GSUB_LookupTable *look;
5542 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5543 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5544 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5545 if (GET_BE_WORD(look->LookupType) != 1)
5546 FIXME("We only handle SubType 1\n");
5547 else
5549 int j;
5551 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5553 const GSUB_SingleSubstFormat1 *ssf1;
5554 offset = GET_BE_WORD(look->SubTable[j]);
5555 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5556 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5558 int offset = GET_BE_WORD(ssf1->Coverage);
5559 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5560 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5562 TRACE(" Glyph 0x%x ->",glyph);
5563 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5564 TRACE(" 0x%x\n",glyph);
5567 else
5569 const GSUB_SingleSubstFormat2 *ssf2;
5570 INT index;
5571 INT offset;
5573 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5574 offset = GET_BE_WORD(ssf1->Coverage);
5575 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5576 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5577 TRACE(" Coverage index %i\n",index);
5578 if (index != -1)
5580 TRACE(" Glyph is 0x%x ->",glyph);
5581 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5582 TRACE("0x%x\n",glyph);
5588 return glyph;
5591 static const char* get_opentype_script(const GdiFont *font)
5594 * I am not sure if this is the correct way to generate our script tag
5597 switch (font->charset)
5599 case ANSI_CHARSET: return "latn";
5600 case BALTIC_CHARSET: return "latn"; /* ?? */
5601 case CHINESEBIG5_CHARSET: return "hani";
5602 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5603 case GB2312_CHARSET: return "hani";
5604 case GREEK_CHARSET: return "grek";
5605 case HANGUL_CHARSET: return "hang";
5606 case RUSSIAN_CHARSET: return "cyrl";
5607 case SHIFTJIS_CHARSET: return "kana";
5608 case TURKISH_CHARSET: return "latn"; /* ?? */
5609 case VIETNAMESE_CHARSET: return "latn";
5610 case JOHAB_CHARSET: return "latn"; /* ?? */
5611 case ARABIC_CHARSET: return "arab";
5612 case HEBREW_CHARSET: return "hebr";
5613 case THAI_CHARSET: return "thai";
5614 default: return "latn";
5618 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5620 const GSUB_Header *header;
5621 const GSUB_Script *script;
5622 const GSUB_LangSys *language;
5623 const GSUB_Feature *feature;
5625 if (!font->GSUB_Table)
5626 return glyph;
5628 header = font->GSUB_Table;
5630 script = GSUB_get_script_table(header, get_opentype_script(font));
5631 if (!script)
5633 TRACE("Script not found\n");
5634 return glyph;
5636 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5637 if (!language)
5639 TRACE("Language not found\n");
5640 return glyph;
5642 feature = GSUB_get_feature(header, language, "vrt2");
5643 if (!feature)
5644 feature = GSUB_get_feature(header, language, "vert");
5645 if (!feature)
5647 TRACE("vrt2/vert feature not found\n");
5648 return glyph;
5650 return GSUB_apply_feature(header, feature, glyph);
5653 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5655 FT_UInt glyphId;
5657 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5658 WCHAR wc = (WCHAR)glyph;
5659 BOOL default_used;
5660 BOOL *default_used_pointer;
5661 FT_UInt ret;
5662 char buf;
5663 default_used_pointer = NULL;
5664 default_used = FALSE;
5665 if (codepage_sets_default_used(font->codepage))
5666 default_used_pointer = &default_used;
5667 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5669 if (font->codepage == CP_SYMBOL && wc < 0x100)
5670 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
5671 else
5672 ret = 0;
5674 else
5675 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5676 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5677 return ret;
5680 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5682 if (glyph < 0x100) glyph += 0xf000;
5683 /* there is a number of old pre-Unicode "broken" TTFs, which
5684 do have symbols at U+00XX instead of U+f0XX */
5685 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5686 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5688 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5690 return glyphId;
5693 /*************************************************************
5694 * freetype_GetGlyphIndices
5696 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5698 struct freetype_physdev *physdev = get_freetype_dev( dev );
5699 int i;
5700 WORD default_char;
5701 BOOL got_default = FALSE;
5703 if (!physdev->font)
5705 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5706 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5709 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5711 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5712 got_default = TRUE;
5715 GDI_CheckNotLock();
5716 EnterCriticalSection( &freetype_cs );
5718 for(i = 0; i < count; i++)
5720 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5721 if (pgi[i] == 0)
5723 if (!got_default)
5725 if (FT_IS_SFNT(physdev->font->ft_face))
5727 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5728 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5730 else
5732 TEXTMETRICW textm;
5733 get_text_metrics(physdev->font, &textm);
5734 default_char = textm.tmDefaultChar;
5736 got_default = TRUE;
5738 pgi[i] = default_char;
5741 LeaveCriticalSection( &freetype_cs );
5742 return count;
5745 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5747 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5748 return !memcmp(matrix, &identity, sizeof(FMAT2));
5751 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5753 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5754 return !memcmp(matrix, &identity, sizeof(MAT2));
5757 static inline BYTE get_max_level( UINT format )
5759 switch( format )
5761 case GGO_GRAY2_BITMAP: return 4;
5762 case GGO_GRAY4_BITMAP: return 16;
5763 case GGO_GRAY8_BITMAP: return 64;
5765 return 255;
5768 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5770 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5771 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
5772 const MAT2* lpmat)
5774 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5775 FT_Face ft_face = incoming_font->ft_face;
5776 GdiFont *font = incoming_font;
5777 FT_UInt glyph_index;
5778 DWORD width, height, pitch, needed = 0;
5779 FT_Bitmap ft_bitmap;
5780 FT_Error err;
5781 INT left, right, top = 0, bottom = 0, adv;
5782 FT_Angle angle = 0;
5783 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5784 double widthRatio = 1.0;
5785 FT_Matrix transMat = identityMat;
5786 FT_Matrix transMatUnrotated;
5787 BOOL needsTransform = FALSE;
5788 BOOL tategaki = (font->GSUB_Table != NULL);
5789 UINT original_index;
5791 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5792 buflen, buf, lpmat);
5794 TRACE("font transform %f %f %f %f\n",
5795 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5796 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5798 if(format & GGO_GLYPH_INDEX) {
5799 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5800 original_index = glyph;
5801 format &= ~GGO_GLYPH_INDEX;
5802 } else {
5803 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5804 ft_face = font->ft_face;
5805 original_index = glyph_index;
5808 if(format & GGO_UNHINTED) {
5809 load_flags |= FT_LOAD_NO_HINTING;
5810 format &= ~GGO_UNHINTED;
5813 /* tategaki never appears to happen to lower glyph index */
5814 if (glyph_index < TATEGAKI_LOWER_BOUND )
5815 tategaki = FALSE;
5817 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5818 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5819 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5820 font->gmsize * sizeof(GM*));
5821 } else {
5822 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5823 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5825 *lpgm = FONT_GM(font,original_index)->gm;
5826 *abc = FONT_GM(font,original_index)->abc;
5827 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5828 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5829 lpgm->gmCellIncX, lpgm->gmCellIncY);
5830 return 1; /* FIXME */
5834 if (!font->gm[original_index / GM_BLOCK_SIZE])
5835 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5837 /* Scaling factor */
5838 if (font->aveWidth)
5840 TEXTMETRICW tm;
5842 get_text_metrics(font, &tm);
5844 widthRatio = (double)font->aveWidth;
5845 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5847 else
5848 widthRatio = font->scale_y;
5850 /* Scaling transform */
5851 if (widthRatio != 1.0 || font->scale_y != 1.0)
5853 FT_Matrix scaleMat;
5854 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5855 scaleMat.xy = 0;
5856 scaleMat.yx = 0;
5857 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5859 pFT_Matrix_Multiply(&scaleMat, &transMat);
5860 needsTransform = TRUE;
5863 /* Slant transform */
5864 if (font->fake_italic) {
5865 FT_Matrix slantMat;
5867 slantMat.xx = (1 << 16);
5868 slantMat.xy = ((1 << 16) >> 2);
5869 slantMat.yx = 0;
5870 slantMat.yy = (1 << 16);
5871 pFT_Matrix_Multiply(&slantMat, &transMat);
5872 needsTransform = TRUE;
5875 /* Rotation transform */
5876 transMatUnrotated = transMat;
5877 if(font->orientation && !tategaki) {
5878 FT_Matrix rotationMat;
5879 FT_Vector vecAngle;
5880 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5881 pFT_Vector_Unit(&vecAngle, angle);
5882 rotationMat.xx = vecAngle.x;
5883 rotationMat.xy = -vecAngle.y;
5884 rotationMat.yx = -rotationMat.xy;
5885 rotationMat.yy = rotationMat.xx;
5887 pFT_Matrix_Multiply(&rotationMat, &transMat);
5888 needsTransform = TRUE;
5891 /* World transform */
5892 if (!is_identity_FMAT2(&font->font_desc.matrix))
5894 FT_Matrix worldMat;
5895 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5896 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5897 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5898 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5899 pFT_Matrix_Multiply(&worldMat, &transMat);
5900 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5901 needsTransform = TRUE;
5904 /* Extra transformation specified by caller */
5905 if (!is_identity_MAT2(lpmat))
5907 FT_Matrix extraMat;
5908 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5909 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5910 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5911 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5912 pFT_Matrix_Multiply(&extraMat, &transMat);
5913 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5914 needsTransform = TRUE;
5917 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
5919 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5921 if(err) {
5922 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5923 return GDI_ERROR;
5926 if(!needsTransform) {
5927 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5928 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5929 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5931 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5932 bottom = (ft_face->glyph->metrics.horiBearingY -
5933 ft_face->glyph->metrics.height) & -64;
5934 lpgm->gmCellIncX = adv;
5935 lpgm->gmCellIncY = 0;
5936 } else {
5937 INT xc, yc;
5938 FT_Vector vec;
5940 left = right = 0;
5942 for(xc = 0; xc < 2; xc++) {
5943 for(yc = 0; yc < 2; yc++) {
5944 vec.x = (ft_face->glyph->metrics.horiBearingX +
5945 xc * ft_face->glyph->metrics.width);
5946 vec.y = ft_face->glyph->metrics.horiBearingY -
5947 yc * ft_face->glyph->metrics.height;
5948 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5949 pFT_Vector_Transform(&vec, &transMat);
5950 if(xc == 0 && yc == 0) {
5951 left = right = vec.x;
5952 top = bottom = vec.y;
5953 } else {
5954 if(vec.x < left) left = vec.x;
5955 else if(vec.x > right) right = vec.x;
5956 if(vec.y < bottom) bottom = vec.y;
5957 else if(vec.y > top) top = vec.y;
5961 left = left & -64;
5962 right = (right + 63) & -64;
5963 bottom = bottom & -64;
5964 top = (top + 63) & -64;
5966 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5967 vec.x = ft_face->glyph->metrics.horiAdvance;
5968 vec.y = 0;
5969 pFT_Vector_Transform(&vec, &transMat);
5970 lpgm->gmCellIncX = (vec.x+63) >> 6;
5971 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5973 vec.x = ft_face->glyph->metrics.horiAdvance;
5974 vec.y = 0;
5975 pFT_Vector_Transform(&vec, &transMatUnrotated);
5976 adv = (vec.x+63) >> 6;
5979 lpgm->gmBlackBoxX = (right - left) >> 6;
5980 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5981 lpgm->gmptGlyphOrigin.x = left >> 6;
5982 lpgm->gmptGlyphOrigin.y = top >> 6;
5983 abc->abcA = left >> 6;
5984 abc->abcB = (right - left) >> 6;
5985 abc->abcC = adv - abc->abcA - abc->abcB;
5987 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5988 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5989 lpgm->gmCellIncX, lpgm->gmCellIncY);
5991 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5992 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5994 FONT_GM(font,original_index)->gm = *lpgm;
5995 FONT_GM(font,original_index)->abc = *abc;
5996 FONT_GM(font,original_index)->init = TRUE;
5999 if(format == GGO_METRICS)
6001 return 1; /* FIXME */
6004 if(ft_face->glyph->format != ft_glyph_format_outline &&
6005 (format == GGO_NATIVE || format == GGO_BEZIER))
6007 TRACE("loaded a bitmap\n");
6008 return GDI_ERROR;
6011 switch(format) {
6012 case GGO_BITMAP:
6013 width = lpgm->gmBlackBoxX;
6014 height = lpgm->gmBlackBoxY;
6015 pitch = ((width + 31) >> 5) << 2;
6016 needed = pitch * height;
6018 if(!buf || !buflen) break;
6020 switch(ft_face->glyph->format) {
6021 case ft_glyph_format_bitmap:
6023 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6024 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
6025 INT h = ft_face->glyph->bitmap.rows;
6026 while(h--) {
6027 memcpy(dst, src, w);
6028 src += ft_face->glyph->bitmap.pitch;
6029 dst += pitch;
6031 break;
6034 case ft_glyph_format_outline:
6035 ft_bitmap.width = width;
6036 ft_bitmap.rows = height;
6037 ft_bitmap.pitch = pitch;
6038 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
6039 ft_bitmap.buffer = buf;
6041 if(needsTransform)
6042 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6044 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6046 /* Note: FreeType will only set 'black' bits for us. */
6047 memset(buf, 0, needed);
6048 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6049 break;
6051 default:
6052 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6053 return GDI_ERROR;
6055 break;
6057 case GGO_GRAY2_BITMAP:
6058 case GGO_GRAY4_BITMAP:
6059 case GGO_GRAY8_BITMAP:
6060 case WINE_GGO_GRAY16_BITMAP:
6062 unsigned int max_level, row, col;
6063 BYTE *start, *ptr;
6065 width = lpgm->gmBlackBoxX;
6066 height = lpgm->gmBlackBoxY;
6067 pitch = (width + 3) / 4 * 4;
6068 needed = pitch * height;
6070 if(!buf || !buflen) break;
6072 max_level = get_max_level( format );
6074 switch(ft_face->glyph->format) {
6075 case ft_glyph_format_bitmap:
6077 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6078 INT h = ft_face->glyph->bitmap.rows;
6079 INT x;
6080 memset( buf, 0, needed );
6081 while(h--) {
6082 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
6083 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
6084 src += ft_face->glyph->bitmap.pitch;
6085 dst += pitch;
6087 return needed;
6089 case ft_glyph_format_outline:
6091 ft_bitmap.width = width;
6092 ft_bitmap.rows = height;
6093 ft_bitmap.pitch = pitch;
6094 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6095 ft_bitmap.buffer = buf;
6097 if(needsTransform)
6098 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6100 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6102 memset(ft_bitmap.buffer, 0, buflen);
6104 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6106 if (max_level != 255)
6108 for (row = 0, start = buf; row < height; row++)
6110 for (col = 0, ptr = start; col < width; col++, ptr++)
6111 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6112 start += pitch;
6115 return needed;
6118 default:
6119 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6120 return GDI_ERROR;
6122 break;
6125 case WINE_GGO_HRGB_BITMAP:
6126 case WINE_GGO_HBGR_BITMAP:
6127 case WINE_GGO_VRGB_BITMAP:
6128 case WINE_GGO_VBGR_BITMAP:
6129 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6131 switch (ft_face->glyph->format)
6133 case FT_GLYPH_FORMAT_BITMAP:
6135 BYTE *src, *dst;
6136 INT src_pitch, x;
6138 width = lpgm->gmBlackBoxX;
6139 height = lpgm->gmBlackBoxY;
6140 pitch = width * 4;
6141 needed = pitch * height;
6143 if (!buf || !buflen) break;
6145 memset(buf, 0, buflen);
6146 dst = buf;
6147 src = ft_face->glyph->bitmap.buffer;
6148 src_pitch = ft_face->glyph->bitmap.pitch;
6150 height = min( height, ft_face->glyph->bitmap.rows );
6151 while ( height-- )
6153 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6155 if ( src[x / 8] & masks[x % 8] )
6156 ((unsigned int *)dst)[x] = ~0u;
6158 src += src_pitch;
6159 dst += pitch;
6162 break;
6165 case FT_GLYPH_FORMAT_OUTLINE:
6167 unsigned int *dst;
6168 BYTE *src;
6169 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6170 INT x_shift, y_shift;
6171 BOOL rgb;
6172 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6173 FT_Render_Mode render_mode =
6174 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6175 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6177 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6179 if ( render_mode == FT_RENDER_MODE_LCD)
6181 lpgm->gmBlackBoxX += 2;
6182 lpgm->gmptGlyphOrigin.x -= 1;
6184 else
6186 lpgm->gmBlackBoxY += 2;
6187 lpgm->gmptGlyphOrigin.y += 1;
6191 width = lpgm->gmBlackBoxX;
6192 height = lpgm->gmBlackBoxY;
6193 pitch = width * 4;
6194 needed = pitch * height;
6196 if (!buf || !buflen) break;
6198 memset(buf, 0, buflen);
6199 dst = buf;
6200 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6202 if ( needsTransform )
6203 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
6205 if ( pFT_Library_SetLcdFilter )
6206 pFT_Library_SetLcdFilter( library, lcdfilter );
6207 pFT_Render_Glyph (ft_face->glyph, render_mode);
6209 src = ft_face->glyph->bitmap.buffer;
6210 src_pitch = ft_face->glyph->bitmap.pitch;
6211 src_width = ft_face->glyph->bitmap.width;
6212 src_height = ft_face->glyph->bitmap.rows;
6214 if ( render_mode == FT_RENDER_MODE_LCD)
6216 rgb_interval = 1;
6217 hmul = 3;
6218 vmul = 1;
6220 else
6222 rgb_interval = src_pitch;
6223 hmul = 1;
6224 vmul = 3;
6227 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6228 if ( x_shift < 0 ) x_shift = 0;
6229 if ( x_shift + (src_width / hmul) > width )
6230 x_shift = width - (src_width / hmul);
6232 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6233 if ( y_shift < 0 ) y_shift = 0;
6234 if ( y_shift + (src_height / vmul) > height )
6235 y_shift = height - (src_height / vmul);
6237 dst += x_shift + y_shift * ( pitch / 4 );
6238 while ( src_height )
6240 for ( x = 0; x < src_width / hmul; x++ )
6242 if ( rgb )
6244 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6245 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6246 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6247 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6249 else
6251 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6252 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6253 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6254 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6257 src += src_pitch * vmul;
6258 dst += pitch / 4;
6259 src_height -= vmul;
6262 break;
6265 default:
6266 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6267 return GDI_ERROR;
6270 break;
6272 #else
6273 return GDI_ERROR;
6274 #endif
6276 case GGO_NATIVE:
6278 int contour, point = 0, first_pt;
6279 FT_Outline *outline = &ft_face->glyph->outline;
6280 TTPOLYGONHEADER *pph;
6281 TTPOLYCURVE *ppc;
6282 DWORD pph_start, cpfx, type;
6284 if(buflen == 0) buf = NULL;
6286 if (needsTransform && buf) {
6287 pFT_Outline_Transform(outline, &transMat);
6290 for(contour = 0; contour < outline->n_contours; contour++) {
6291 /* Ignore contours containing one point */
6292 if(point == outline->contours[contour]) {
6293 point++;
6294 continue;
6297 pph_start = needed;
6298 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6299 first_pt = point;
6300 if(buf) {
6301 pph->dwType = TT_POLYGON_TYPE;
6302 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6304 needed += sizeof(*pph);
6305 point++;
6306 while(point <= outline->contours[contour]) {
6307 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6308 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6309 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6310 cpfx = 0;
6311 do {
6312 if(buf)
6313 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6314 cpfx++;
6315 point++;
6316 } while(point <= outline->contours[contour] &&
6317 (outline->tags[point] & FT_Curve_Tag_On) ==
6318 (outline->tags[point-1] & FT_Curve_Tag_On));
6319 /* At the end of a contour Windows adds the start point, but
6320 only for Beziers */
6321 if(point > outline->contours[contour] &&
6322 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6323 if(buf)
6324 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6325 cpfx++;
6326 } else if(point <= outline->contours[contour] &&
6327 outline->tags[point] & FT_Curve_Tag_On) {
6328 /* add closing pt for bezier */
6329 if(buf)
6330 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6331 cpfx++;
6332 point++;
6334 if(buf) {
6335 ppc->wType = type;
6336 ppc->cpfx = cpfx;
6338 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6340 if(buf)
6341 pph->cb = needed - pph_start;
6343 break;
6345 case GGO_BEZIER:
6347 /* Convert the quadratic Beziers to cubic Beziers.
6348 The parametric eqn for a cubic Bezier is, from PLRM:
6349 r(t) = at^3 + bt^2 + ct + r0
6350 with the control points:
6351 r1 = r0 + c/3
6352 r2 = r1 + (c + b)/3
6353 r3 = r0 + c + b + a
6355 A quadratic Bezier has the form:
6356 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6358 So equating powers of t leads to:
6359 r1 = 2/3 p1 + 1/3 p0
6360 r2 = 2/3 p1 + 1/3 p2
6361 and of course r0 = p0, r3 = p2
6364 int contour, point = 0, first_pt;
6365 FT_Outline *outline = &ft_face->glyph->outline;
6366 TTPOLYGONHEADER *pph;
6367 TTPOLYCURVE *ppc;
6368 DWORD pph_start, cpfx, type;
6369 FT_Vector cubic_control[4];
6370 if(buflen == 0) buf = NULL;
6372 if (needsTransform && buf) {
6373 pFT_Outline_Transform(outline, &transMat);
6376 for(contour = 0; contour < outline->n_contours; contour++) {
6377 pph_start = needed;
6378 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6379 first_pt = point;
6380 if(buf) {
6381 pph->dwType = TT_POLYGON_TYPE;
6382 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6384 needed += sizeof(*pph);
6385 point++;
6386 while(point <= outline->contours[contour]) {
6387 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6388 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6389 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6390 cpfx = 0;
6391 do {
6392 if(type == TT_PRIM_LINE) {
6393 if(buf)
6394 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6395 cpfx++;
6396 point++;
6397 } else {
6398 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6399 so cpfx = 3n */
6401 /* FIXME: Possible optimization in endpoint calculation
6402 if there are two consecutive curves */
6403 cubic_control[0] = outline->points[point-1];
6404 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6405 cubic_control[0].x += outline->points[point].x + 1;
6406 cubic_control[0].y += outline->points[point].y + 1;
6407 cubic_control[0].x >>= 1;
6408 cubic_control[0].y >>= 1;
6410 if(point+1 > outline->contours[contour])
6411 cubic_control[3] = outline->points[first_pt];
6412 else {
6413 cubic_control[3] = outline->points[point+1];
6414 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6415 cubic_control[3].x += outline->points[point].x + 1;
6416 cubic_control[3].y += outline->points[point].y + 1;
6417 cubic_control[3].x >>= 1;
6418 cubic_control[3].y >>= 1;
6421 /* r1 = 1/3 p0 + 2/3 p1
6422 r2 = 1/3 p2 + 2/3 p1 */
6423 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6424 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6425 cubic_control[2] = cubic_control[1];
6426 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6427 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6428 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6429 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6430 if(buf) {
6431 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6432 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6433 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6435 cpfx += 3;
6436 point++;
6438 } while(point <= outline->contours[contour] &&
6439 (outline->tags[point] & FT_Curve_Tag_On) ==
6440 (outline->tags[point-1] & FT_Curve_Tag_On));
6441 /* At the end of a contour Windows adds the start point,
6442 but only for Beziers and we've already done that.
6444 if(point <= outline->contours[contour] &&
6445 outline->tags[point] & FT_Curve_Tag_On) {
6446 /* This is the closing pt of a bezier, but we've already
6447 added it, so just inc point and carry on */
6448 point++;
6450 if(buf) {
6451 ppc->wType = type;
6452 ppc->cpfx = cpfx;
6454 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6456 if(buf)
6457 pph->cb = needed - pph_start;
6459 break;
6462 default:
6463 FIXME("Unsupported format %d\n", format);
6464 return GDI_ERROR;
6466 return needed;
6469 static BOOL get_bitmap_text_metrics(GdiFont *font)
6471 FT_Face ft_face = font->ft_face;
6472 FT_WinFNT_HeaderRec winfnt_header;
6473 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6474 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6475 font->potm->otmSize = size;
6477 #define TM font->potm->otmTextMetrics
6478 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6480 TM.tmHeight = winfnt_header.pixel_height;
6481 TM.tmAscent = winfnt_header.ascent;
6482 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6483 TM.tmInternalLeading = winfnt_header.internal_leading;
6484 TM.tmExternalLeading = winfnt_header.external_leading;
6485 TM.tmAveCharWidth = winfnt_header.avg_width;
6486 TM.tmMaxCharWidth = winfnt_header.max_width;
6487 TM.tmWeight = winfnt_header.weight;
6488 TM.tmOverhang = 0;
6489 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6490 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6491 TM.tmFirstChar = winfnt_header.first_char;
6492 TM.tmLastChar = winfnt_header.last_char;
6493 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6494 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6495 TM.tmItalic = winfnt_header.italic;
6496 TM.tmUnderlined = font->underline;
6497 TM.tmStruckOut = font->strikeout;
6498 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6499 TM.tmCharSet = winfnt_header.charset;
6501 else
6503 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6504 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6505 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6506 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6507 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6508 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6509 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6510 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6511 TM.tmOverhang = 0;
6512 TM.tmDigitizedAspectX = 96; /* FIXME */
6513 TM.tmDigitizedAspectY = 96; /* FIXME */
6514 TM.tmFirstChar = 1;
6515 TM.tmLastChar = 255;
6516 TM.tmDefaultChar = 32;
6517 TM.tmBreakChar = 32;
6518 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6519 TM.tmUnderlined = font->underline;
6520 TM.tmStruckOut = font->strikeout;
6521 /* NB inverted meaning of TMPF_FIXED_PITCH */
6522 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6523 TM.tmCharSet = font->charset;
6525 #undef TM
6527 return TRUE;
6531 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6533 double scale_x, scale_y;
6535 if (font->aveWidth)
6537 scale_x = (double)font->aveWidth;
6538 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6540 else
6541 scale_x = font->scale_y;
6543 scale_x *= fabs(font->font_desc.matrix.eM11);
6544 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6546 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6547 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6549 SCALE_Y(ptm->tmHeight);
6550 SCALE_Y(ptm->tmAscent);
6551 SCALE_Y(ptm->tmDescent);
6552 SCALE_Y(ptm->tmInternalLeading);
6553 SCALE_Y(ptm->tmExternalLeading);
6554 SCALE_Y(ptm->tmOverhang);
6556 SCALE_X(ptm->tmAveCharWidth);
6557 SCALE_X(ptm->tmMaxCharWidth);
6559 #undef SCALE_X
6560 #undef SCALE_Y
6563 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6565 double scale_x, scale_y;
6567 if (font->aveWidth)
6569 scale_x = (double)font->aveWidth;
6570 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6572 else
6573 scale_x = font->scale_y;
6575 scale_x *= fabs(font->font_desc.matrix.eM11);
6576 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6578 scale_font_metrics(font, &potm->otmTextMetrics);
6580 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6581 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6583 SCALE_Y(potm->otmAscent);
6584 SCALE_Y(potm->otmDescent);
6585 SCALE_Y(potm->otmLineGap);
6586 SCALE_Y(potm->otmsCapEmHeight);
6587 SCALE_Y(potm->otmsXHeight);
6588 SCALE_Y(potm->otmrcFontBox.top);
6589 SCALE_Y(potm->otmrcFontBox.bottom);
6590 SCALE_X(potm->otmrcFontBox.left);
6591 SCALE_X(potm->otmrcFontBox.right);
6592 SCALE_Y(potm->otmMacAscent);
6593 SCALE_Y(potm->otmMacDescent);
6594 SCALE_Y(potm->otmMacLineGap);
6595 SCALE_X(potm->otmptSubscriptSize.x);
6596 SCALE_Y(potm->otmptSubscriptSize.y);
6597 SCALE_X(potm->otmptSubscriptOffset.x);
6598 SCALE_Y(potm->otmptSubscriptOffset.y);
6599 SCALE_X(potm->otmptSuperscriptSize.x);
6600 SCALE_Y(potm->otmptSuperscriptSize.y);
6601 SCALE_X(potm->otmptSuperscriptOffset.x);
6602 SCALE_Y(potm->otmptSuperscriptOffset.y);
6603 SCALE_Y(potm->otmsStrikeoutSize);
6604 SCALE_Y(potm->otmsStrikeoutPosition);
6605 SCALE_Y(potm->otmsUnderscoreSize);
6606 SCALE_Y(potm->otmsUnderscorePosition);
6608 #undef SCALE_X
6609 #undef SCALE_Y
6612 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6614 if(!font->potm)
6616 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6618 /* Make sure that the font has sane width/height ratio */
6619 if (font->aveWidth)
6621 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6623 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6624 font->aveWidth = 0;
6628 *ptm = font->potm->otmTextMetrics;
6629 scale_font_metrics(font, ptm);
6630 return TRUE;
6633 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6635 int i;
6637 for(i = 0; i < ft_face->num_charmaps; i++)
6639 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6640 return TRUE;
6642 return FALSE;
6645 static BOOL get_outline_text_metrics(GdiFont *font)
6647 BOOL ret = FALSE;
6648 FT_Face ft_face = font->ft_face;
6649 UINT needed, lenfam, lensty, lenface, lenfull;
6650 TT_OS2 *pOS2;
6651 TT_HoriHeader *pHori;
6652 TT_Postscript *pPost;
6653 FT_Fixed x_scale, y_scale;
6654 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
6655 char *cp;
6656 INT ascent, descent;
6658 TRACE("font=%p\n", font);
6660 if(!FT_IS_SCALABLE(ft_face))
6661 return FALSE;
6663 needed = sizeof(*font->potm);
6665 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6666 family_nameW = strdupW(font->name);
6668 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
6669 if (!style_nameW)
6670 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6671 if (!style_nameW)
6673 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
6674 style_nameW = towstr( CP_ACP, ft_face->style_name );
6676 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
6678 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
6679 if (!face_nameW)
6680 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6681 if (!face_nameW)
6683 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
6684 face_nameW = strdupW(font->name);
6686 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
6687 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
6689 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
6690 if (!full_nameW)
6691 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6692 if (!full_nameW)
6694 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
6695 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
6696 full_nameW = strdupW(fake_nameW);
6698 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
6700 /* These names should be read from the TT name table */
6702 /* length of otmpFamilyName */
6703 needed += lenfam;
6705 /* length of otmpFaceName */
6706 needed += lenface;
6708 /* length of otmpStyleName */
6709 needed += lensty;
6711 /* length of otmpFullName */
6712 needed += lenfull;
6715 x_scale = ft_face->size->metrics.x_scale;
6716 y_scale = ft_face->size->metrics.y_scale;
6718 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6719 if(!pOS2) {
6720 FIXME("Can't find OS/2 table - not TT font?\n");
6721 goto end;
6724 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6725 if(!pHori) {
6726 FIXME("Can't find HHEA table - not TT font?\n");
6727 goto end;
6730 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6732 TRACE("OS/2 winA = %d winD = %d typoA = %d typoD = %d typoLG = %d avgW %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
6733 pOS2->usWinAscent, pOS2->usWinDescent,
6734 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6735 pOS2->xAvgCharWidth,
6736 ft_face->ascender, ft_face->descender, ft_face->height,
6737 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6738 ft_face->bbox.yMax, ft_face->bbox.yMin);
6740 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6741 font->potm->otmSize = needed;
6743 #define TM font->potm->otmTextMetrics
6745 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6746 ascent = pHori->Ascender;
6747 descent = -pHori->Descender;
6748 } else {
6749 ascent = pOS2->usWinAscent;
6750 descent = pOS2->usWinDescent;
6753 font->ntmCellHeight = ascent + descent;
6754 font->ntmAvgWidth = pOS2->xAvgCharWidth;
6756 if(font->yMax) {
6757 TM.tmAscent = font->yMax;
6758 TM.tmDescent = -font->yMin;
6759 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6760 } else {
6761 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6762 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6763 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6764 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6767 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6769 /* MSDN says:
6770 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6772 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6773 ((ascent + descent) -
6774 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6776 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6777 if (TM.tmAveCharWidth == 0) {
6778 TM.tmAveCharWidth = 1;
6780 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6781 TM.tmWeight = FW_REGULAR;
6782 if (font->fake_bold)
6783 TM.tmWeight = FW_BOLD;
6784 else
6786 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6788 if (pOS2->usWeightClass > FW_MEDIUM)
6789 TM.tmWeight = pOS2->usWeightClass;
6791 else if (pOS2->usWeightClass <= FW_MEDIUM)
6792 TM.tmWeight = pOS2->usWeightClass;
6794 TM.tmOverhang = 0;
6795 TM.tmDigitizedAspectX = 96; /* FIXME */
6796 TM.tmDigitizedAspectY = 96; /* FIXME */
6797 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6798 * symbol range to 0 - f0ff
6801 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6803 TM.tmFirstChar = 0;
6804 switch(GetACP())
6806 case 1257: /* Baltic */
6807 TM.tmLastChar = 0xf8fd;
6808 break;
6809 default:
6810 TM.tmLastChar = 0xf0ff;
6812 TM.tmBreakChar = 0x20;
6813 TM.tmDefaultChar = 0x1f;
6815 else
6817 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6818 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6820 if(pOS2->usFirstCharIndex <= 1)
6821 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6822 else if (pOS2->usFirstCharIndex > 0xff)
6823 TM.tmBreakChar = 0x20;
6824 else
6825 TM.tmBreakChar = pOS2->usFirstCharIndex;
6826 TM.tmDefaultChar = TM.tmBreakChar - 1;
6828 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6829 TM.tmUnderlined = font->underline;
6830 TM.tmStruckOut = font->strikeout;
6832 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6833 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6834 (pOS2->version == 0xFFFFU ||
6835 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6836 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6837 else
6838 TM.tmPitchAndFamily = 0;
6840 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6842 case PAN_FAMILY_SCRIPT:
6843 TM.tmPitchAndFamily |= FF_SCRIPT;
6844 break;
6846 case PAN_FAMILY_DECORATIVE:
6847 TM.tmPitchAndFamily |= FF_DECORATIVE;
6848 break;
6850 case PAN_ANY:
6851 case PAN_NO_FIT:
6852 case PAN_FAMILY_TEXT_DISPLAY:
6853 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6854 /* which is clearly not what the panose spec says. */
6855 default:
6856 if(TM.tmPitchAndFamily == 0 || /* fixed */
6857 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6858 TM.tmPitchAndFamily = FF_MODERN;
6859 else
6861 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6863 case PAN_ANY:
6864 case PAN_NO_FIT:
6865 default:
6866 TM.tmPitchAndFamily |= FF_DONTCARE;
6867 break;
6869 case PAN_SERIF_COVE:
6870 case PAN_SERIF_OBTUSE_COVE:
6871 case PAN_SERIF_SQUARE_COVE:
6872 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6873 case PAN_SERIF_SQUARE:
6874 case PAN_SERIF_THIN:
6875 case PAN_SERIF_BONE:
6876 case PAN_SERIF_EXAGGERATED:
6877 case PAN_SERIF_TRIANGLE:
6878 TM.tmPitchAndFamily |= FF_ROMAN;
6879 break;
6881 case PAN_SERIF_NORMAL_SANS:
6882 case PAN_SERIF_OBTUSE_SANS:
6883 case PAN_SERIF_PERP_SANS:
6884 case PAN_SERIF_FLARED:
6885 case PAN_SERIF_ROUNDED:
6886 TM.tmPitchAndFamily |= FF_SWISS;
6887 break;
6890 break;
6893 if(FT_IS_SCALABLE(ft_face))
6894 TM.tmPitchAndFamily |= TMPF_VECTOR;
6896 if(FT_IS_SFNT(ft_face))
6898 if (font->ntmFlags & NTM_PS_OPENTYPE)
6899 TM.tmPitchAndFamily |= TMPF_DEVICE;
6900 else
6901 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6904 TM.tmCharSet = font->charset;
6906 font->potm->otmFiller = 0;
6907 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6908 font->potm->otmfsSelection = pOS2->fsSelection;
6909 font->potm->otmfsType = pOS2->fsType;
6910 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6911 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6912 font->potm->otmItalicAngle = 0; /* POST table */
6913 font->potm->otmEMSquare = ft_face->units_per_EM;
6914 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6915 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6916 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6917 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6918 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6919 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6920 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6921 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6922 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6923 font->potm->otmMacAscent = TM.tmAscent;
6924 font->potm->otmMacDescent = -TM.tmDescent;
6925 font->potm->otmMacLineGap = font->potm->otmLineGap;
6926 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6927 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6928 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6929 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6930 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6931 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6932 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6933 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6934 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6935 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6936 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6937 if(!pPost) {
6938 font->potm->otmsUnderscoreSize = 0;
6939 font->potm->otmsUnderscorePosition = 0;
6940 } else {
6941 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6942 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6944 #undef TM
6946 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6947 cp = (char*)font->potm + sizeof(*font->potm);
6948 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6949 strcpyW((WCHAR*)cp, family_nameW);
6950 cp += lenfam;
6951 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6952 strcpyW((WCHAR*)cp, style_nameW);
6953 cp += lensty;
6954 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6955 strcpyW((WCHAR*)cp, face_nameW);
6956 cp += lenface;
6957 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6958 strcpyW((WCHAR*)cp, full_nameW);
6959 ret = TRUE;
6961 end:
6962 HeapFree(GetProcessHeap(), 0, style_nameW);
6963 HeapFree(GetProcessHeap(), 0, family_nameW);
6964 HeapFree(GetProcessHeap(), 0, face_nameW);
6965 HeapFree(GetProcessHeap(), 0, full_nameW);
6966 return ret;
6969 /*************************************************************
6970 * freetype_GetGlyphOutline
6972 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6973 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6975 struct freetype_physdev *physdev = get_freetype_dev( dev );
6976 DWORD ret;
6977 ABC abc;
6979 if (!physdev->font)
6981 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6982 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6985 GDI_CheckNotLock();
6986 EnterCriticalSection( &freetype_cs );
6987 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
6988 LeaveCriticalSection( &freetype_cs );
6989 return ret;
6992 /*************************************************************
6993 * freetype_GetTextMetrics
6995 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6997 struct freetype_physdev *physdev = get_freetype_dev( dev );
6998 BOOL ret;
7000 if (!physdev->font)
7002 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
7003 return dev->funcs->pGetTextMetrics( dev, metrics );
7006 GDI_CheckNotLock();
7007 EnterCriticalSection( &freetype_cs );
7008 ret = get_text_metrics( physdev->font, metrics );
7009 LeaveCriticalSection( &freetype_cs );
7010 return ret;
7013 /*************************************************************
7014 * freetype_GetOutlineTextMetrics
7016 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
7018 struct freetype_physdev *physdev = get_freetype_dev( dev );
7019 UINT ret = 0;
7021 if (!physdev->font)
7023 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
7024 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
7027 TRACE("font=%p\n", physdev->font);
7029 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
7031 GDI_CheckNotLock();
7032 EnterCriticalSection( &freetype_cs );
7034 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
7036 if(cbSize >= physdev->font->potm->otmSize)
7038 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
7039 scale_outline_font_metrics(physdev->font, potm);
7041 ret = physdev->font->potm->otmSize;
7043 LeaveCriticalSection( &freetype_cs );
7044 return ret;
7047 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
7049 child->font = alloc_font();
7050 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
7051 if(!child->font->ft_face)
7053 free_font(child->font);
7054 child->font = NULL;
7055 return FALSE;
7058 child->font->font_desc = font->font_desc;
7059 child->font->ntmFlags = child->face->ntmFlags;
7060 child->font->orientation = font->orientation;
7061 child->font->scale_y = font->scale_y;
7062 child->font->name = strdupW(child->face->family->FamilyName);
7063 child->font->base_font = font;
7064 TRACE("created child font %p for base %p\n", child->font, font);
7065 return TRUE;
7068 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
7070 FT_UInt g;
7071 CHILD_FONT *child_font;
7073 if(font->base_font)
7074 font = font->base_font;
7076 *linked_font = font;
7078 if((*glyph = get_glyph_index(font, c)))
7080 *glyph = get_GSUB_vert_glyph(font, *glyph);
7081 return TRUE;
7084 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7086 if(!child_font->font)
7087 if(!load_child_font(font, child_font))
7088 continue;
7090 if(!child_font->font->ft_face)
7091 continue;
7092 g = get_glyph_index(child_font->font, c);
7093 g = get_GSUB_vert_glyph(child_font->font, g);
7094 if(g)
7096 *glyph = g;
7097 *linked_font = child_font->font;
7098 return TRUE;
7101 return FALSE;
7104 /*************************************************************
7105 * freetype_GetCharWidth
7107 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7109 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7110 UINT c;
7111 GLYPHMETRICS gm;
7112 ABC abc;
7113 struct freetype_physdev *physdev = get_freetype_dev( dev );
7115 if (!physdev->font)
7117 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7118 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7121 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7123 GDI_CheckNotLock();
7124 EnterCriticalSection( &freetype_cs );
7125 for(c = firstChar; c <= lastChar; c++) {
7126 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7127 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
7129 LeaveCriticalSection( &freetype_cs );
7130 return TRUE;
7133 /*************************************************************
7134 * freetype_GetCharABCWidths
7136 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7138 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7139 UINT c;
7140 GLYPHMETRICS gm;
7141 struct freetype_physdev *physdev = get_freetype_dev( dev );
7143 if (!physdev->font)
7145 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7146 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7149 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7151 GDI_CheckNotLock();
7152 EnterCriticalSection( &freetype_cs );
7154 for(c = firstChar; c <= lastChar; c++, buffer++)
7155 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
7157 LeaveCriticalSection( &freetype_cs );
7158 return TRUE;
7161 /*************************************************************
7162 * freetype_GetCharABCWidthsI
7164 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7166 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7167 UINT c;
7168 GLYPHMETRICS gm;
7169 struct freetype_physdev *physdev = get_freetype_dev( dev );
7171 if (!physdev->font)
7173 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7174 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7177 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7178 return FALSE;
7180 GDI_CheckNotLock();
7181 EnterCriticalSection( &freetype_cs );
7183 for(c = 0; c < count; c++, buffer++)
7184 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
7185 &gm, buffer, 0, NULL, &identity );
7187 LeaveCriticalSection( &freetype_cs );
7188 return TRUE;
7191 /*************************************************************
7192 * freetype_GetTextExtentExPoint
7194 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
7195 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
7197 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7198 INT idx;
7199 INT nfit = 0, ext;
7200 ABC abc;
7201 GLYPHMETRICS gm;
7202 TEXTMETRICW tm;
7203 struct freetype_physdev *physdev = get_freetype_dev( dev );
7205 if (!physdev->font)
7207 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7208 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
7211 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
7213 GDI_CheckNotLock();
7214 EnterCriticalSection( &freetype_cs );
7216 size->cx = 0;
7217 get_text_metrics( physdev->font, &tm );
7218 size->cy = tm.tmHeight;
7220 for(idx = 0; idx < count; idx++) {
7221 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7222 size->cx += abc.abcA + abc.abcB + abc.abcC;
7223 ext = size->cx;
7224 if (! pnfit || ext <= max_ext) {
7225 ++nfit;
7226 if (dxs)
7227 dxs[idx] = ext;
7231 if (pnfit)
7232 *pnfit = nfit;
7234 LeaveCriticalSection( &freetype_cs );
7235 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7236 return TRUE;
7239 /*************************************************************
7240 * freetype_GetTextExtentExPointI
7242 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
7243 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
7245 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7246 INT idx;
7247 INT nfit = 0, ext;
7248 ABC abc;
7249 GLYPHMETRICS gm;
7250 TEXTMETRICW tm;
7251 struct freetype_physdev *physdev = get_freetype_dev( dev );
7253 if (!physdev->font)
7255 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7256 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
7259 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
7261 GDI_CheckNotLock();
7262 EnterCriticalSection( &freetype_cs );
7264 size->cx = 0;
7265 get_text_metrics(physdev->font, &tm);
7266 size->cy = tm.tmHeight;
7268 for(idx = 0; idx < count; idx++) {
7269 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
7270 &gm, &abc, 0, NULL, &identity );
7271 size->cx += abc.abcA + abc.abcB + abc.abcC;
7272 ext = size->cx;
7273 if (! pnfit || ext <= max_ext) {
7274 ++nfit;
7275 if (dxs)
7276 dxs[idx] = ext;
7280 if (pnfit)
7281 *pnfit = nfit;
7283 LeaveCriticalSection( &freetype_cs );
7284 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7285 return TRUE;
7288 /*************************************************************
7289 * freetype_GetFontData
7291 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7293 struct freetype_physdev *physdev = get_freetype_dev( dev );
7295 if (!physdev->font)
7297 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7298 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7301 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7302 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7303 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7305 return get_font_data( physdev->font, table, offset, buf, cbData );
7308 /*************************************************************
7309 * freetype_GetTextFace
7311 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7313 INT n;
7314 struct freetype_physdev *physdev = get_freetype_dev( dev );
7316 if (!physdev->font)
7318 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7319 return dev->funcs->pGetTextFace( dev, count, str );
7322 n = strlenW(physdev->font->name) + 1;
7323 if (str)
7325 lstrcpynW(str, physdev->font->name, count);
7326 n = min(count, n);
7328 return n;
7331 /*************************************************************
7332 * freetype_GetTextCharsetInfo
7334 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7336 struct freetype_physdev *physdev = get_freetype_dev( dev );
7338 if (!physdev->font)
7340 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7341 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7343 if (fs) *fs = physdev->font->fs;
7344 return physdev->font->charset;
7347 /* Retrieve a list of supported Unicode ranges for a given font.
7348 * Can be called with NULL gs to calculate the buffer size. Returns
7349 * the number of ranges found.
7351 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7353 DWORD num_ranges = 0;
7355 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7357 FT_UInt glyph_code;
7358 FT_ULong char_code, char_code_prev;
7360 glyph_code = 0;
7361 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7363 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7364 face->num_glyphs, glyph_code, char_code);
7366 if (!glyph_code) return 0;
7368 if (gs)
7370 gs->ranges[0].wcLow = (USHORT)char_code;
7371 gs->ranges[0].cGlyphs = 0;
7372 gs->cGlyphsSupported = 0;
7375 num_ranges = 1;
7376 while (glyph_code)
7378 if (char_code < char_code_prev)
7380 ERR("expected increasing char code from FT_Get_Next_Char\n");
7381 return 0;
7383 if (char_code - char_code_prev > 1)
7385 num_ranges++;
7386 if (gs)
7388 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7389 gs->ranges[num_ranges - 1].cGlyphs = 1;
7390 gs->cGlyphsSupported++;
7393 else if (gs)
7395 gs->ranges[num_ranges - 1].cGlyphs++;
7396 gs->cGlyphsSupported++;
7398 char_code_prev = char_code;
7399 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7402 else
7403 FIXME("encoding %u not supported\n", face->charmap->encoding);
7405 return num_ranges;
7408 /*************************************************************
7409 * freetype_GetFontUnicodeRanges
7411 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7413 struct freetype_physdev *physdev = get_freetype_dev( dev );
7414 DWORD size, num_ranges;
7416 if (!physdev->font)
7418 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7419 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7422 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7423 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7424 if (glyphset)
7426 glyphset->cbThis = size;
7427 glyphset->cRanges = num_ranges;
7428 glyphset->flAccel = 0;
7430 return size;
7433 /*************************************************************
7434 * freetype_FontIsLinked
7436 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7438 struct freetype_physdev *physdev = get_freetype_dev( dev );
7439 BOOL ret;
7441 if (!physdev->font)
7443 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7444 return dev->funcs->pFontIsLinked( dev );
7447 GDI_CheckNotLock();
7448 EnterCriticalSection( &freetype_cs );
7449 ret = !list_empty(&physdev->font->child_fonts);
7450 LeaveCriticalSection( &freetype_cs );
7451 return ret;
7454 /*************************************************************************
7455 * GetRasterizerCaps (GDI32.@)
7457 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7459 lprs->nSize = sizeof(RASTERIZER_STATUS);
7460 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
7461 lprs->nLanguageID = 0;
7462 return TRUE;
7465 /*************************************************************
7466 * freetype_GdiRealizationInfo
7468 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7470 struct freetype_physdev *physdev = get_freetype_dev( dev );
7471 realization_info_t *info = ptr;
7473 if (!physdev->font)
7475 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7476 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7479 FIXME("(%p, %p): stub!\n", physdev->font, info);
7481 info->flags = 1;
7482 if(FT_IS_SCALABLE(physdev->font->ft_face))
7483 info->flags |= 2;
7485 info->cache_num = physdev->font->cache_num;
7486 info->unknown2 = -1;
7487 return TRUE;
7490 /*************************************************************************
7491 * Kerning support for TrueType fonts
7493 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7495 struct TT_kern_table
7497 USHORT version;
7498 USHORT nTables;
7501 struct TT_kern_subtable
7503 USHORT version;
7504 USHORT length;
7505 union
7507 USHORT word;
7508 struct
7510 USHORT horizontal : 1;
7511 USHORT minimum : 1;
7512 USHORT cross_stream: 1;
7513 USHORT override : 1;
7514 USHORT reserved1 : 4;
7515 USHORT format : 8;
7516 } bits;
7517 } coverage;
7520 struct TT_format0_kern_subtable
7522 USHORT nPairs;
7523 USHORT searchRange;
7524 USHORT entrySelector;
7525 USHORT rangeShift;
7528 struct TT_kern_pair
7530 USHORT left;
7531 USHORT right;
7532 short value;
7535 static DWORD parse_format0_kern_subtable(GdiFont *font,
7536 const struct TT_format0_kern_subtable *tt_f0_ks,
7537 const USHORT *glyph_to_char,
7538 KERNINGPAIR *kern_pair, DWORD cPairs)
7540 USHORT i, nPairs;
7541 const struct TT_kern_pair *tt_kern_pair;
7543 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7545 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7547 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7548 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7549 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7551 if (!kern_pair || !cPairs)
7552 return nPairs;
7554 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7556 nPairs = min(nPairs, cPairs);
7558 for (i = 0; i < nPairs; i++)
7560 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7561 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7562 /* this algorithm appears to better match what Windows does */
7563 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7564 if (kern_pair->iKernAmount < 0)
7566 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7567 kern_pair->iKernAmount -= font->ppem;
7569 else if (kern_pair->iKernAmount > 0)
7571 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7572 kern_pair->iKernAmount += font->ppem;
7574 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7576 TRACE("left %u right %u value %d\n",
7577 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7579 kern_pair++;
7581 TRACE("copied %u entries\n", nPairs);
7582 return nPairs;
7585 /*************************************************************
7586 * freetype_GetKerningPairs
7588 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7590 DWORD length;
7591 void *buf;
7592 const struct TT_kern_table *tt_kern_table;
7593 const struct TT_kern_subtable *tt_kern_subtable;
7594 USHORT i, nTables;
7595 USHORT *glyph_to_char;
7596 GdiFont *font;
7597 struct freetype_physdev *physdev = get_freetype_dev( dev );
7599 if (!(font = physdev->font))
7601 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7602 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7605 GDI_CheckNotLock();
7606 EnterCriticalSection( &freetype_cs );
7607 if (font->total_kern_pairs != (DWORD)-1)
7609 if (cPairs && kern_pair)
7611 cPairs = min(cPairs, font->total_kern_pairs);
7612 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7614 else cPairs = font->total_kern_pairs;
7616 LeaveCriticalSection( &freetype_cs );
7617 return cPairs;
7620 font->total_kern_pairs = 0;
7622 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7624 if (length == GDI_ERROR)
7626 TRACE("no kerning data in the font\n");
7627 LeaveCriticalSection( &freetype_cs );
7628 return 0;
7631 buf = HeapAlloc(GetProcessHeap(), 0, length);
7632 if (!buf)
7634 WARN("Out of memory\n");
7635 LeaveCriticalSection( &freetype_cs );
7636 return 0;
7639 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7641 /* build a glyph index to char code map */
7642 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7643 if (!glyph_to_char)
7645 WARN("Out of memory allocating a glyph index to char code map\n");
7646 HeapFree(GetProcessHeap(), 0, buf);
7647 LeaveCriticalSection( &freetype_cs );
7648 return 0;
7651 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7653 FT_UInt glyph_code;
7654 FT_ULong char_code;
7656 glyph_code = 0;
7657 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7659 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7660 font->ft_face->num_glyphs, glyph_code, char_code);
7662 while (glyph_code)
7664 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7666 /* FIXME: This doesn't match what Windows does: it does some fancy
7667 * things with duplicate glyph index to char code mappings, while
7668 * we just avoid overriding existing entries.
7670 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7671 glyph_to_char[glyph_code] = (USHORT)char_code;
7673 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7676 else
7678 ULONG n;
7680 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7681 for (n = 0; n <= 65535; n++)
7682 glyph_to_char[n] = (USHORT)n;
7685 tt_kern_table = buf;
7686 nTables = GET_BE_WORD(tt_kern_table->nTables);
7687 TRACE("version %u, nTables %u\n",
7688 GET_BE_WORD(tt_kern_table->version), nTables);
7690 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7692 for (i = 0; i < nTables; i++)
7694 struct TT_kern_subtable tt_kern_subtable_copy;
7696 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7697 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7698 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7700 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7701 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7702 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7704 /* According to the TrueType specification this is the only format
7705 * that will be properly interpreted by Windows and OS/2
7707 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7709 DWORD new_chunk, old_total = font->total_kern_pairs;
7711 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7712 glyph_to_char, NULL, 0);
7713 font->total_kern_pairs += new_chunk;
7715 if (!font->kern_pairs)
7716 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7717 font->total_kern_pairs * sizeof(*font->kern_pairs));
7718 else
7719 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7720 font->total_kern_pairs * sizeof(*font->kern_pairs));
7722 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7723 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7725 else
7726 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7728 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7731 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7732 HeapFree(GetProcessHeap(), 0, buf);
7734 if (cPairs && kern_pair)
7736 cPairs = min(cPairs, font->total_kern_pairs);
7737 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7739 else cPairs = font->total_kern_pairs;
7741 LeaveCriticalSection( &freetype_cs );
7742 return cPairs;
7745 static const struct gdi_dc_funcs freetype_funcs =
7747 NULL, /* pAbortDoc */
7748 NULL, /* pAbortPath */
7749 NULL, /* pAlphaBlend */
7750 NULL, /* pAngleArc */
7751 NULL, /* pArc */
7752 NULL, /* pArcTo */
7753 NULL, /* pBeginPath */
7754 NULL, /* pBlendImage */
7755 NULL, /* pChord */
7756 NULL, /* pCloseFigure */
7757 NULL, /* pCreateCompatibleDC */
7758 freetype_CreateDC, /* pCreateDC */
7759 freetype_DeleteDC, /* pDeleteDC */
7760 NULL, /* pDeleteObject */
7761 NULL, /* pDeviceCapabilities */
7762 NULL, /* pEllipse */
7763 NULL, /* pEndDoc */
7764 NULL, /* pEndPage */
7765 NULL, /* pEndPath */
7766 freetype_EnumFonts, /* pEnumFonts */
7767 NULL, /* pEnumICMProfiles */
7768 NULL, /* pExcludeClipRect */
7769 NULL, /* pExtDeviceMode */
7770 NULL, /* pExtEscape */
7771 NULL, /* pExtFloodFill */
7772 NULL, /* pExtSelectClipRgn */
7773 NULL, /* pExtTextOut */
7774 NULL, /* pFillPath */
7775 NULL, /* pFillRgn */
7776 NULL, /* pFlattenPath */
7777 freetype_FontIsLinked, /* pFontIsLinked */
7778 NULL, /* pFrameRgn */
7779 NULL, /* pGdiComment */
7780 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7781 NULL, /* pGetBoundsRect */
7782 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7783 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7784 freetype_GetCharWidth, /* pGetCharWidth */
7785 NULL, /* pGetDeviceCaps */
7786 NULL, /* pGetDeviceGammaRamp */
7787 freetype_GetFontData, /* pGetFontData */
7788 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7789 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7790 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7791 NULL, /* pGetICMProfile */
7792 NULL, /* pGetImage */
7793 freetype_GetKerningPairs, /* pGetKerningPairs */
7794 NULL, /* pGetNearestColor */
7795 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7796 NULL, /* pGetPixel */
7797 NULL, /* pGetSystemPaletteEntries */
7798 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7799 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7800 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7801 freetype_GetTextFace, /* pGetTextFace */
7802 freetype_GetTextMetrics, /* pGetTextMetrics */
7803 NULL, /* pGradientFill */
7804 NULL, /* pIntersectClipRect */
7805 NULL, /* pInvertRgn */
7806 NULL, /* pLineTo */
7807 NULL, /* pModifyWorldTransform */
7808 NULL, /* pMoveTo */
7809 NULL, /* pOffsetClipRgn */
7810 NULL, /* pOffsetViewportOrg */
7811 NULL, /* pOffsetWindowOrg */
7812 NULL, /* pPaintRgn */
7813 NULL, /* pPatBlt */
7814 NULL, /* pPie */
7815 NULL, /* pPolyBezier */
7816 NULL, /* pPolyBezierTo */
7817 NULL, /* pPolyDraw */
7818 NULL, /* pPolyPolygon */
7819 NULL, /* pPolyPolyline */
7820 NULL, /* pPolygon */
7821 NULL, /* pPolyline */
7822 NULL, /* pPolylineTo */
7823 NULL, /* pPutImage */
7824 NULL, /* pRealizeDefaultPalette */
7825 NULL, /* pRealizePalette */
7826 NULL, /* pRectangle */
7827 NULL, /* pResetDC */
7828 NULL, /* pRestoreDC */
7829 NULL, /* pRoundRect */
7830 NULL, /* pSaveDC */
7831 NULL, /* pScaleViewportExt */
7832 NULL, /* pScaleWindowExt */
7833 NULL, /* pSelectBitmap */
7834 NULL, /* pSelectBrush */
7835 NULL, /* pSelectClipPath */
7836 freetype_SelectFont, /* pSelectFont */
7837 NULL, /* pSelectPalette */
7838 NULL, /* pSelectPen */
7839 NULL, /* pSetArcDirection */
7840 NULL, /* pSetBkColor */
7841 NULL, /* pSetBkMode */
7842 NULL, /* pSetDCBrushColor */
7843 NULL, /* pSetDCPenColor */
7844 NULL, /* pSetDIBColorTable */
7845 NULL, /* pSetDIBitsToDevice */
7846 NULL, /* pSetDeviceClipping */
7847 NULL, /* pSetDeviceGammaRamp */
7848 NULL, /* pSetLayout */
7849 NULL, /* pSetMapMode */
7850 NULL, /* pSetMapperFlags */
7851 NULL, /* pSetPixel */
7852 NULL, /* pSetPolyFillMode */
7853 NULL, /* pSetROP2 */
7854 NULL, /* pSetRelAbs */
7855 NULL, /* pSetStretchBltMode */
7856 NULL, /* pSetTextAlign */
7857 NULL, /* pSetTextCharacterExtra */
7858 NULL, /* pSetTextColor */
7859 NULL, /* pSetTextJustification */
7860 NULL, /* pSetViewportExt */
7861 NULL, /* pSetViewportOrg */
7862 NULL, /* pSetWindowExt */
7863 NULL, /* pSetWindowOrg */
7864 NULL, /* pSetWorldTransform */
7865 NULL, /* pStartDoc */
7866 NULL, /* pStartPage */
7867 NULL, /* pStretchBlt */
7868 NULL, /* pStretchDIBits */
7869 NULL, /* pStrokeAndFillPath */
7870 NULL, /* pStrokePath */
7871 NULL, /* pUnrealizePalette */
7872 NULL, /* pWidenPath */
7873 NULL, /* wine_get_wgl_driver */
7874 GDI_PRIORITY_FONT_DRV /* priority */
7877 #else /* HAVE_FREETYPE */
7879 /*************************************************************************/
7881 BOOL WineEngInit(void)
7883 return FALSE;
7885 BOOL WineEngDestroyFontInstance(HFONT hfont)
7887 return FALSE;
7890 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7892 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7893 return 1;
7896 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7898 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7899 return TRUE;
7902 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7904 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7905 return NULL;
7908 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
7909 LPCWSTR font_file, LPCWSTR font_path )
7911 FIXME("stub\n");
7912 return FALSE;
7915 /*************************************************************************
7916 * GetRasterizerCaps (GDI32.@)
7918 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7920 lprs->nSize = sizeof(RASTERIZER_STATUS);
7921 lprs->wFlags = 0;
7922 lprs->nLanguageID = 0;
7923 return TRUE;
7926 #endif /* HAVE_FREETYPE */