gdi32: Reset ppem to zero if we fail to find a matching height.
[wine.git] / dlls / gdi32 / freetype.c
blob3d61ad1130761096290a04f93e36c09294f207c3
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 unsigned int refcount;
263 WCHAR *StyleName;
264 WCHAR *FullName;
265 WCHAR *file;
266 dev_t dev;
267 ino_t ino;
268 void *font_data_ptr;
269 DWORD font_data_size;
270 FT_Long face_index;
271 FONTSIGNATURE fs;
272 DWORD ntmFlags;
273 FT_Fixed font_version;
274 BOOL scalable;
275 Bitmap_Size size; /* set if face is a bitmap */
276 DWORD flags; /* ADDFONT flags */
277 struct tagFamily *family;
278 /* Cached data for Enum */
279 struct enum_data *cached_enum_data;
280 } Face;
282 #define ADDFONT_EXTERNAL_FONT 0x01
283 #define ADDFONT_ALLOW_BITMAP 0x02
284 #define ADDFONT_ADD_TO_CACHE 0x04
285 #define ADDFONT_ADD_RESOURCE 0x08 /* added through AddFontResource */
286 #define ADDFONT_VERTICAL_FONT 0x10
287 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
289 typedef struct tagFamily {
290 struct list entry;
291 unsigned int refcount;
292 WCHAR *FamilyName;
293 WCHAR *EnglishName;
294 struct list faces;
295 struct list *replacement;
296 } Family;
298 typedef struct {
299 GLYPHMETRICS gm;
300 ABC abc; /* metrics of the unrotated char */
301 BOOL init;
302 } GM;
304 typedef struct {
305 FLOAT eM11, eM12;
306 FLOAT eM21, eM22;
307 } FMAT2;
309 typedef struct {
310 DWORD hash;
311 LOGFONTW lf;
312 FMAT2 matrix;
313 BOOL can_use_bitmap;
314 } FONT_DESC;
316 typedef struct tagGdiFont GdiFont;
318 typedef struct {
319 struct list entry;
320 Face *face;
321 GdiFont *font;
322 } CHILD_FONT;
324 struct tagGdiFont {
325 struct list entry;
326 struct list unused_entry;
327 unsigned int refcount;
328 GM **gm;
329 DWORD gmsize;
330 OUTLINETEXTMETRICW *potm;
331 DWORD total_kern_pairs;
332 KERNINGPAIR *kern_pairs;
333 struct list child_fonts;
335 /* the following members can be accessed without locking, they are never modified after creation */
336 FT_Face ft_face;
337 struct font_mapping *mapping;
338 LPWSTR name;
339 int charset;
340 int codepage;
341 BOOL fake_italic;
342 BOOL fake_bold;
343 BYTE underline;
344 BYTE strikeout;
345 INT orientation;
346 FONT_DESC font_desc;
347 LONG aveWidth, ppem;
348 double scale_y;
349 SHORT yMax;
350 SHORT yMin;
351 DWORD ntmFlags;
352 DWORD aa_flags;
353 UINT ntmCellHeight, ntmAvgWidth;
354 FONTSIGNATURE fs;
355 GdiFont *base_font;
356 VOID *GSUB_Table;
357 const VOID *vert_feature;
358 DWORD cache_num;
361 typedef struct {
362 struct list entry;
363 const WCHAR *font_name;
364 FONTSIGNATURE fs;
365 struct list links;
366 } SYSTEM_LINKS;
368 struct enum_charset_element {
369 DWORD mask;
370 DWORD charset;
371 WCHAR name[LF_FACESIZE];
374 struct enum_charset_list {
375 DWORD total;
376 struct enum_charset_element element[32];
379 #define GM_BLOCK_SIZE 128
380 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
382 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
383 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
384 static unsigned int unused_font_count;
385 #define UNUSED_CACHE_SIZE 10
386 static struct list system_links = LIST_INIT(system_links);
388 static struct list font_subst_list = LIST_INIT(font_subst_list);
390 static struct list font_list = LIST_INIT(font_list);
392 struct freetype_physdev
394 struct gdi_physdev dev;
395 GdiFont *font;
398 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
400 return (struct freetype_physdev *)dev;
403 static const struct gdi_dc_funcs freetype_funcs;
405 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
406 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
407 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
409 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
410 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
411 'W','i','n','d','o','w','s','\\',
412 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
413 'F','o','n','t','s','\0'};
415 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
416 'W','i','n','d','o','w','s',' ','N','T','\\',
417 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
418 'F','o','n','t','s','\0'};
420 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
421 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
422 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
423 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
425 static const WCHAR * const SystemFontValues[] = {
426 System_Value,
427 OEMFont_Value,
428 FixedSys_Value,
429 NULL
432 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
433 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
435 /* Interesting and well-known (frequently-assumed!) font names */
436 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
437 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 };
438 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
439 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
440 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
441 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
442 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
443 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
445 static const WCHAR arial[] = {'A','r','i','a','l',0};
446 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
447 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};
448 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};
449 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
450 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
451 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
452 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
453 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
454 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
456 static const WCHAR *default_serif_list[] =
458 times_new_roman,
459 liberation_serif,
460 bitstream_vera_serif,
461 NULL
464 static const WCHAR *default_fixed_list[] =
466 courier_new,
467 liberation_mono,
468 bitstream_vera_sans_mono,
469 NULL
472 static const WCHAR *default_sans_list[] =
474 arial,
475 liberation_sans,
476 bitstream_vera_sans,
477 NULL
480 typedef struct {
481 WCHAR *name;
482 INT charset;
483 } NameCs;
485 typedef struct tagFontSubst {
486 struct list entry;
487 NameCs from;
488 NameCs to;
489 } FontSubst;
491 /* Registry font cache key and value names */
492 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
493 'F','o','n','t','s',0};
494 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
495 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
496 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
497 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
498 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
499 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
500 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
501 static const WCHAR face_size_value[] = {'S','i','z','e',0};
502 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
503 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
504 static const WCHAR face_flags_value[] = {'F','l','a','g','s',0};
505 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
506 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
507 static const WCHAR face_file_name_value[] = {'F','i','l','e',' ','N','a','m','e','\0'};
508 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
511 struct font_mapping
513 struct list entry;
514 int refcount;
515 dev_t dev;
516 ino_t ino;
517 void *data;
518 size_t size;
521 static struct list mappings_list = LIST_INIT( mappings_list );
523 static UINT default_aa_flags;
524 static HKEY hkey_font_cache;
526 static CRITICAL_SECTION freetype_cs;
527 static CRITICAL_SECTION_DEBUG critsect_debug =
529 0, 0, &freetype_cs,
530 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
531 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
533 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
535 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
537 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
538 static BOOL use_default_fallback = FALSE;
540 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL *vert);
541 static BOOL get_outline_text_metrics(GdiFont *font);
542 static BOOL get_bitmap_text_metrics(GdiFont *font);
543 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
544 static void remove_face_from_cache( Face *face );
546 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
547 'W','i','n','d','o','w','s',' ','N','T','\\',
548 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
549 'S','y','s','t','e','m','L','i','n','k',0};
551 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
552 'F','o','n','t','L','i','n','k','\\',
553 'S','y','s','t','e','m','L','i','n','k',0};
555 /****************************************
556 * Notes on .fon files
558 * The fonts System, FixedSys and Terminal are special. There are typically multiple
559 * versions installed for different resolutions and codepages. Windows stores which one to use
560 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
561 * Key Meaning
562 * FIXEDFON.FON FixedSys
563 * FONTS.FON System
564 * OEMFONT.FON Terminal
565 * LogPixels Current dpi set by the display control panel applet
566 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
567 * also has a LogPixels value that appears to mirror this)
569 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
570 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
571 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
572 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
573 * so that makes sense.
575 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
576 * to be mapped into the registry on Windows 2000 at least).
577 * I have
578 * woafont=app850.fon
579 * ega80woa.fon=ega80850.fon
580 * ega40woa.fon=ega40850.fon
581 * cga80woa.fon=cga80850.fon
582 * cga40woa.fon=cga40850.fon
585 /* These are all structures needed for the GSUB table */
587 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
589 typedef struct {
590 DWORD version;
591 WORD ScriptList;
592 WORD FeatureList;
593 WORD LookupList;
594 } GSUB_Header;
596 typedef struct {
597 CHAR ScriptTag[4];
598 WORD Script;
599 } GSUB_ScriptRecord;
601 typedef struct {
602 WORD ScriptCount;
603 GSUB_ScriptRecord ScriptRecord[1];
604 } GSUB_ScriptList;
606 typedef struct {
607 CHAR LangSysTag[4];
608 WORD LangSys;
609 } GSUB_LangSysRecord;
611 typedef struct {
612 WORD DefaultLangSys;
613 WORD LangSysCount;
614 GSUB_LangSysRecord LangSysRecord[1];
615 } GSUB_Script;
617 typedef struct {
618 WORD LookupOrder; /* Reserved */
619 WORD ReqFeatureIndex;
620 WORD FeatureCount;
621 WORD FeatureIndex[1];
622 } GSUB_LangSys;
624 typedef struct {
625 CHAR FeatureTag[4];
626 WORD Feature;
627 } GSUB_FeatureRecord;
629 typedef struct {
630 WORD FeatureCount;
631 GSUB_FeatureRecord FeatureRecord[1];
632 } GSUB_FeatureList;
634 typedef struct {
635 WORD FeatureParams; /* Reserved */
636 WORD LookupCount;
637 WORD LookupListIndex[1];
638 } GSUB_Feature;
640 typedef struct {
641 WORD LookupCount;
642 WORD Lookup[1];
643 } GSUB_LookupList;
645 typedef struct {
646 WORD LookupType;
647 WORD LookupFlag;
648 WORD SubTableCount;
649 WORD SubTable[1];
650 } GSUB_LookupTable;
652 typedef struct {
653 WORD CoverageFormat;
654 WORD GlyphCount;
655 WORD GlyphArray[1];
656 } GSUB_CoverageFormat1;
658 typedef struct {
659 WORD Start;
660 WORD End;
661 WORD StartCoverageIndex;
662 } GSUB_RangeRecord;
664 typedef struct {
665 WORD CoverageFormat;
666 WORD RangeCount;
667 GSUB_RangeRecord RangeRecord[1];
668 } GSUB_CoverageFormat2;
670 typedef struct {
671 WORD SubstFormat; /* = 1 */
672 WORD Coverage;
673 WORD DeltaGlyphID;
674 } GSUB_SingleSubstFormat1;
676 typedef struct {
677 WORD SubstFormat; /* = 2 */
678 WORD Coverage;
679 WORD GlyphCount;
680 WORD Substitute[1];
681 }GSUB_SingleSubstFormat2;
683 #ifdef HAVE_CARBON_CARBON_H
684 static char *find_cache_dir(void)
686 FSRef ref;
687 OSErr err;
688 static char cached_path[MAX_PATH];
689 static const char *wine = "/Wine", *fonts = "/Fonts";
691 if(*cached_path) return cached_path;
693 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
694 if(err != noErr)
696 WARN("can't create cached data folder\n");
697 return NULL;
699 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
700 if(err != noErr)
702 WARN("can't create cached data path\n");
703 *cached_path = '\0';
704 return NULL;
706 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
708 ERR("Could not create full path\n");
709 *cached_path = '\0';
710 return NULL;
712 strcat(cached_path, wine);
714 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
716 WARN("Couldn't mkdir %s\n", cached_path);
717 *cached_path = '\0';
718 return NULL;
720 strcat(cached_path, fonts);
721 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
723 WARN("Couldn't mkdir %s\n", cached_path);
724 *cached_path = '\0';
725 return NULL;
727 return cached_path;
730 /******************************************************************
731 * expand_mac_font
733 * Extracts individual TrueType font files from a Mac suitcase font
734 * and saves them into the user's caches directory (see
735 * find_cache_dir()).
736 * Returns a NULL terminated array of filenames.
738 * We do this because they are apps that try to read ttf files
739 * themselves and they don't like Mac suitcase files.
741 static char **expand_mac_font(const char *path)
743 FSRef ref;
744 SInt16 res_ref;
745 OSStatus s;
746 unsigned int idx;
747 const char *out_dir;
748 const char *filename;
749 int output_len;
750 struct {
751 char **array;
752 unsigned int size, max_size;
753 } ret;
755 TRACE("path %s\n", path);
757 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
758 if(s != noErr)
760 WARN("failed to get ref\n");
761 return NULL;
764 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
765 if(s != noErr)
767 TRACE("no data fork, so trying resource fork\n");
768 res_ref = FSOpenResFile(&ref, fsRdPerm);
769 if(res_ref == -1)
771 TRACE("unable to open resource fork\n");
772 return NULL;
776 ret.size = 0;
777 ret.max_size = 10;
778 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
779 if(!ret.array)
781 CloseResFile(res_ref);
782 return NULL;
785 out_dir = find_cache_dir();
787 filename = strrchr(path, '/');
788 if(!filename) filename = path;
789 else filename++;
791 /* output filename has the form out_dir/filename_%04x.ttf */
792 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
794 UseResFile(res_ref);
795 idx = 1;
796 while(1)
798 FamRec *fam_rec;
799 unsigned short *num_faces_ptr, num_faces, face;
800 AsscEntry *assoc;
801 Handle fond;
802 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
804 fond = Get1IndResource(fond_res, idx);
805 if(!fond) break;
806 TRACE("got fond resource %d\n", idx);
807 HLock(fond);
809 fam_rec = *(FamRec**)fond;
810 num_faces_ptr = (unsigned short *)(fam_rec + 1);
811 num_faces = GET_BE_WORD(*num_faces_ptr);
812 num_faces++;
813 assoc = (AsscEntry*)(num_faces_ptr + 1);
814 TRACE("num faces %04x\n", num_faces);
815 for(face = 0; face < num_faces; face++, assoc++)
817 Handle sfnt;
818 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
819 unsigned short size, font_id;
820 char *output;
822 size = GET_BE_WORD(assoc->fontSize);
823 font_id = GET_BE_WORD(assoc->fontID);
824 if(size != 0)
826 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
827 continue;
830 TRACE("trying to load sfnt id %04x\n", font_id);
831 sfnt = GetResource(sfnt_res, font_id);
832 if(!sfnt)
834 TRACE("can't get sfnt resource %04x\n", font_id);
835 continue;
838 output = HeapAlloc(GetProcessHeap(), 0, output_len);
839 if(output)
841 int fd;
843 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
845 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
846 if(fd != -1 || errno == EEXIST)
848 if(fd != -1)
850 unsigned char *sfnt_data;
852 HLock(sfnt);
853 sfnt_data = *(unsigned char**)sfnt;
854 write(fd, sfnt_data, GetHandleSize(sfnt));
855 HUnlock(sfnt);
856 close(fd);
858 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
860 ret.max_size *= 2;
861 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
863 ret.array[ret.size++] = output;
865 else
867 WARN("unable to create %s\n", output);
868 HeapFree(GetProcessHeap(), 0, output);
871 ReleaseResource(sfnt);
873 HUnlock(fond);
874 ReleaseResource(fond);
875 idx++;
877 CloseResFile(res_ref);
879 return ret.array;
882 #endif /* HAVE_CARBON_CARBON_H */
884 static inline BOOL is_win9x(void)
886 return GetVersion() & 0x80000000;
889 This function builds an FT_Fixed from a double. It fails if the absolute
890 value of the float number is greater than 32768.
892 static inline FT_Fixed FT_FixedFromFloat(double f)
894 return f * 0x10000;
898 This function builds an FT_Fixed from a FIXED. It simply put f.value
899 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
901 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
903 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
906 static BOOL is_hinting_enabled(void)
908 static int enabled = -1;
910 if (enabled == -1)
912 /* Use the >= 2.2.0 function if available */
913 if (pFT_Get_TrueType_Engine_Type)
915 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
916 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
918 #ifdef FT_DRIVER_HAS_HINTER
919 else
921 /* otherwise if we've been compiled with < 2.2.0 headers use the internal macro */
922 FT_Module mod = pFT_Get_Module(library, "truetype");
923 enabled = (mod && FT_DRIVER_HAS_HINTER(mod));
925 #endif
926 else enabled = FALSE;
927 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
929 return enabled;
932 static BOOL is_subpixel_rendering_enabled( void )
934 #ifdef HAVE_FREETYPE_FTLCDFIL_H
935 static int enabled = -1;
936 if (enabled == -1)
938 enabled = (pFT_Library_SetLcdFilter &&
939 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature);
940 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
942 return enabled;
943 #else
944 return FALSE;
945 #endif
949 static const struct list *get_face_list_from_family(const Family *family)
951 if (!list_empty(&family->faces))
952 return &family->faces;
953 else
954 return family->replacement;
957 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
959 Family *family;
960 Face *face;
961 const WCHAR *file;
963 TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
965 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
967 const struct list *face_list;
968 if(face_name && strcmpiW(face_name, family->FamilyName))
969 continue;
970 face_list = get_face_list_from_family(family);
971 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
973 if (!face->file)
974 continue;
975 file = strrchrW(face->file, '/');
976 if(!file)
977 file = face->file;
978 else
979 file++;
980 if(strcmpiW(file, file_name)) continue;
981 face->refcount++;
982 return face;
985 return NULL;
988 static Family *find_family_from_name(const WCHAR *name)
990 Family *family;
992 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
994 if(!strcmpiW(family->FamilyName, name))
995 return family;
998 return NULL;
1001 static Family *find_family_from_any_name(const WCHAR *name)
1003 Family *family;
1005 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1007 if(!strcmpiW(family->FamilyName, name))
1008 return family;
1009 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
1010 return family;
1013 return NULL;
1016 static void DumpSubstList(void)
1018 FontSubst *psub;
1020 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
1022 if(psub->from.charset != -1 || psub->to.charset != -1)
1023 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
1024 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
1025 else
1026 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
1027 debugstr_w(psub->to.name));
1029 return;
1032 static LPWSTR strdupW(LPCWSTR p)
1034 LPWSTR ret;
1035 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
1036 ret = HeapAlloc(GetProcessHeap(), 0, len);
1037 memcpy(ret, p, len);
1038 return ret;
1041 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1042 INT from_charset)
1044 FontSubst *element;
1046 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1048 if(!strcmpiW(element->from.name, from_name) &&
1049 (element->from.charset == from_charset ||
1050 element->from.charset == -1))
1051 return element;
1054 return NULL;
1057 #define ADD_FONT_SUBST_FORCE 1
1059 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1061 FontSubst *from_exist, *to_exist;
1063 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1065 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1067 list_remove(&from_exist->entry);
1068 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
1069 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
1070 HeapFree(GetProcessHeap(), 0, from_exist);
1071 from_exist = NULL;
1074 if(!from_exist)
1076 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1078 if(to_exist)
1080 HeapFree(GetProcessHeap(), 0, subst->to.name);
1081 subst->to.name = strdupW(to_exist->to.name);
1084 list_add_tail(subst_list, &subst->entry);
1086 return TRUE;
1089 HeapFree(GetProcessHeap(), 0, subst->from.name);
1090 HeapFree(GetProcessHeap(), 0, subst->to.name);
1091 HeapFree(GetProcessHeap(), 0, subst);
1092 return FALSE;
1095 static WCHAR *towstr(UINT cp, const char *str)
1097 int len;
1098 WCHAR *wstr;
1100 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1101 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1102 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1103 return wstr;
1106 static char *strWtoA(UINT cp, const WCHAR *str)
1108 int len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL );
1109 char *ret = HeapAlloc( GetProcessHeap(), 0, len );
1110 WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL );
1111 return ret;
1114 static void split_subst_info(NameCs *nc, LPSTR str)
1116 CHAR *p = strrchr(str, ',');
1118 nc->charset = -1;
1119 if(p && *(p+1)) {
1120 nc->charset = strtol(p+1, NULL, 10);
1121 *p = '\0';
1123 nc->name = towstr(CP_ACP, str);
1126 static void LoadSubstList(void)
1128 FontSubst *psub;
1129 HKEY hkey;
1130 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1131 LPSTR value;
1132 LPVOID data;
1134 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1135 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1136 &hkey) == ERROR_SUCCESS) {
1138 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1139 &valuelen, &datalen, NULL, NULL);
1141 valuelen++; /* returned value doesn't include room for '\0' */
1142 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1143 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1145 dlen = datalen;
1146 vlen = valuelen;
1147 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1148 &dlen) == ERROR_SUCCESS) {
1149 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1151 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1152 split_subst_info(&psub->from, value);
1153 split_subst_info(&psub->to, data);
1155 /* Win 2000 doesn't allow mapping between different charsets
1156 or mapping of DEFAULT_CHARSET */
1157 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1158 psub->to.charset == DEFAULT_CHARSET) {
1159 HeapFree(GetProcessHeap(), 0, psub->to.name);
1160 HeapFree(GetProcessHeap(), 0, psub->from.name);
1161 HeapFree(GetProcessHeap(), 0, psub);
1162 } else {
1163 add_font_subst(&font_subst_list, psub, 0);
1165 /* reset dlen and vlen */
1166 dlen = datalen;
1167 vlen = valuelen;
1169 HeapFree(GetProcessHeap(), 0, data);
1170 HeapFree(GetProcessHeap(), 0, value);
1171 RegCloseKey(hkey);
1176 static const LANGID mac_langid_table[] =
1178 MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */
1179 MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */
1180 MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */
1181 MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */
1182 MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */
1183 MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */
1184 MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */
1185 MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */
1186 MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */
1187 MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */
1188 MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */
1189 MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */
1190 MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */
1191 MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */
1192 MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */
1193 MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */
1194 MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */
1195 MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */
1196 MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */
1197 MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
1198 MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */
1199 MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */
1200 MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */
1201 MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */
1202 MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */
1203 MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */
1204 MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */
1205 MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */
1206 MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */
1207 MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */
1208 MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */
1209 MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */
1210 MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */
1211 MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
1212 MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */
1213 MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */
1214 MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */
1215 MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */
1216 MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */
1217 MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */
1218 MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */
1219 0, /* TT_MAC_LANGID_YIDDISH */
1220 MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */
1221 MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */
1222 MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */
1223 MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */
1224 MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */
1225 MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */
1226 MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */
1227 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */
1228 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
1229 MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */
1230 MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */
1231 0, /* TT_MAC_LANGID_MOLDAVIAN */
1232 MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */
1233 MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */
1234 MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */
1235 MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */
1236 MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
1237 MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */
1238 0, /* TT_MAC_LANGID_KURDISH */
1239 MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */
1240 MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */
1241 MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */
1242 MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */
1243 MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */
1244 MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */
1245 MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */
1246 MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */
1247 MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */
1248 MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */
1249 MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */
1250 MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */
1251 MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */
1252 MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */
1253 MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */
1254 MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */
1255 0, /* TT_MAC_LANGID_BURMESE */
1256 MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */
1257 MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */
1258 MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */
1259 MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */
1260 0, /* TT_MAC_LANGID_TAGALOG */
1261 MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
1262 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
1263 MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */
1264 MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */
1265 0, /* TT_MAC_LANGID_GALLA */
1266 0, /* TT_MAC_LANGID_SOMALI */
1267 MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */
1268 0, /* TT_MAC_LANGID_RUANDA */
1269 0, /* TT_MAC_LANGID_RUNDI */
1270 0, /* TT_MAC_LANGID_CHEWA */
1271 MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */
1272 MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */
1273 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
1274 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
1275 MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */
1276 MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */
1277 MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */
1278 0, /* TT_MAC_LANGID_LATIN */
1279 MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */
1280 0, /* TT_MAC_LANGID_GUARANI */
1281 0, /* TT_MAC_LANGID_AYMARA */
1282 MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */
1283 MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */
1284 0, /* TT_MAC_LANGID_DZONGKHA */
1285 0, /* TT_MAC_LANGID_JAVANESE */
1286 0, /* TT_MAC_LANGID_SUNDANESE */
1287 MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */
1288 MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */
1289 MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */
1290 MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */
1291 MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
1292 MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */
1293 MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */
1294 0, /* TT_MAC_LANGID_TONGAN */
1295 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
1296 MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */
1297 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
1300 static inline WORD get_mac_code_page( const FT_SfntName *name )
1302 if (name->encoding_id == TT_MAC_ID_SIMPLIFIED_CHINESE) return 10008; /* special case */
1303 return 10000 + name->encoding_id;
1306 static int match_name_table_language( const FT_SfntName *name, LANGID lang )
1308 LANGID name_lang;
1309 int res = 0;
1311 switch (name->platform_id)
1313 case TT_PLATFORM_MICROSOFT:
1314 res += 5; /* prefer the Microsoft name */
1315 switch (name->encoding_id)
1317 case TT_MS_ID_UNICODE_CS:
1318 case TT_MS_ID_SYMBOL_CS:
1319 name_lang = name->language_id;
1320 break;
1321 default:
1322 return 0;
1324 break;
1325 case TT_PLATFORM_MACINTOSH:
1326 if (!IsValidCodePage( get_mac_code_page( name ))) return 0;
1327 if (name->language_id >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
1328 name_lang = mac_langid_table[name->language_id];
1329 break;
1330 case TT_PLATFORM_APPLE_UNICODE:
1331 res += 2; /* prefer Unicode encodings */
1332 switch (name->encoding_id)
1334 case TT_APPLE_ID_DEFAULT:
1335 case TT_APPLE_ID_ISO_10646:
1336 case TT_APPLE_ID_UNICODE_2_0:
1337 if (name->language_id >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
1338 name_lang = mac_langid_table[name->language_id];
1339 break;
1340 default:
1341 return 0;
1343 break;
1344 default:
1345 return 0;
1347 if (name_lang == lang) res += 30;
1348 else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20;
1349 else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10;
1350 return res;
1353 static WCHAR *copy_name_table_string( const FT_SfntName *name )
1355 WCHAR *ret;
1356 WORD codepage;
1357 int i;
1359 switch (name->platform_id)
1361 case TT_PLATFORM_APPLE_UNICODE:
1362 case TT_PLATFORM_MICROSOFT:
1363 ret = HeapAlloc( GetProcessHeap(), 0, name->string_len + sizeof(WCHAR) );
1364 for (i = 0; i < name->string_len / 2; i++)
1365 ret[i] = (name->string[i * 2] << 8) | name->string[i * 2 + 1];
1366 ret[i] = 0;
1367 return ret;
1368 case TT_PLATFORM_MACINTOSH:
1369 codepage = get_mac_code_page( name );
1370 i = MultiByteToWideChar( codepage, 0, (char *)name->string, name->string_len, NULL, 0 );
1371 ret = HeapAlloc( GetProcessHeap(), 0, (i + 1) * sizeof(WCHAR) );
1372 MultiByteToWideChar( codepage, 0, (char *)name->string, name->string_len, ret, i );
1373 ret[i] = 0;
1374 return ret;
1376 return NULL;
1379 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, LANGID language_id)
1381 FT_SfntName name;
1382 FT_UInt num_names, name_index;
1383 int res, best_lang = 0, best_index = -1;
1385 if (!FT_IS_SFNT(ft_face)) return NULL;
1387 num_names = pFT_Get_Sfnt_Name_Count( ft_face );
1389 for (name_index = 0; name_index < num_names; name_index++)
1391 if (pFT_Get_Sfnt_Name( ft_face, name_index, &name )) continue;
1392 if (name.name_id != name_id) continue;
1393 res = match_name_table_language( &name, language_id );
1394 if (res > best_lang)
1396 best_lang = res;
1397 best_index = name_index;
1401 if (best_index != -1 && !pFT_Get_Sfnt_Name( ft_face, best_index, &name ))
1403 WCHAR *ret = copy_name_table_string( &name );
1404 TRACE( "name %u found platform %u lang %04x %s\n",
1405 name_id, name.platform_id, name.language_id, debugstr_w( ret ));
1406 return ret;
1408 return NULL;
1411 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1413 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1414 if (f1->scalable) return TRUE;
1415 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1416 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1419 static void release_family( Family *family )
1421 if (--family->refcount) return;
1422 assert( list_empty( &family->faces ));
1423 list_remove( &family->entry );
1424 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1425 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1426 HeapFree( GetProcessHeap(), 0, family );
1429 static void release_face( Face *face )
1431 if (--face->refcount) return;
1432 if (face->family)
1434 if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
1435 list_remove( &face->entry );
1436 release_family( face->family );
1438 HeapFree( GetProcessHeap(), 0, face->file );
1439 HeapFree( GetProcessHeap(), 0, face->StyleName );
1440 HeapFree( GetProcessHeap(), 0, face->FullName );
1441 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1442 HeapFree( GetProcessHeap(), 0, face );
1445 static inline int style_order(const Face *face)
1447 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1449 case NTM_REGULAR:
1450 return 0;
1451 case NTM_BOLD:
1452 return 1;
1453 case NTM_ITALIC:
1454 return 2;
1455 case NTM_BOLD | NTM_ITALIC:
1456 return 3;
1457 default:
1458 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1459 debugstr_w(face->family->FamilyName),
1460 debugstr_w(face->StyleName),
1461 face->ntmFlags);
1462 return 9999;
1466 static BOOL insert_face_in_family_list( Face *face, Family *family )
1468 Face *cursor;
1470 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1472 if (faces_equal( face, cursor ))
1474 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1475 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1476 cursor->font_version, face->font_version);
1478 if (face->file && face->dev == cursor->dev && face->ino == cursor->ino)
1480 cursor->refcount++;
1481 TRACE("Font %s already in list, refcount now %d\n",
1482 debugstr_w(face->file), cursor->refcount);
1483 return FALSE;
1485 if (face->font_version <= cursor->font_version)
1487 TRACE("Original font %s is newer so skipping %s\n",
1488 debugstr_w(cursor->file), debugstr_w(face->file));
1489 return FALSE;
1491 else
1493 TRACE("Replacing original %s with %s\n",
1494 debugstr_w(cursor->file), debugstr_w(face->file));
1495 list_add_before( &cursor->entry, &face->entry );
1496 face->family = family;
1497 family->refcount++;
1498 face->refcount++;
1499 release_face( cursor );
1500 return TRUE;
1503 else
1504 TRACE("Adding new %s\n", debugstr_w(face->file));
1506 if (style_order( face ) < style_order( cursor )) break;
1509 list_add_before( &cursor->entry, &face->entry );
1510 face->family = family;
1511 family->refcount++;
1512 face->refcount++;
1513 return TRUE;
1516 /****************************************************************
1517 * NB This function stores the ptrs to the strings to save copying.
1518 * Don't free them after calling.
1520 static Family *create_family( WCHAR *name, WCHAR *english_name )
1522 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1523 family->refcount = 1;
1524 family->FamilyName = name;
1525 family->EnglishName = english_name;
1526 list_init( &family->faces );
1527 family->replacement = &family->faces;
1528 list_add_tail( &font_list, &family->entry );
1530 return family;
1533 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1535 DWORD type, size = sizeof(DWORD);
1537 if (RegQueryValueExW(hkey, value, NULL, &type, (BYTE *)data, &size) ||
1538 type != REG_DWORD || size != sizeof(DWORD))
1540 *data = 0;
1541 return ERROR_BAD_CONFIGURATION;
1543 return ERROR_SUCCESS;
1546 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1548 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1551 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1553 DWORD needed, strike_index = 0;
1554 HKEY hkey_strike;
1556 /* If we have a File Name key then this is a real font, not just the parent
1557 key of a bunch of non-scalable strikes */
1558 needed = buffer_size;
1559 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1561 Face *face;
1562 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1563 face->cached_enum_data = NULL;
1564 face->family = NULL;
1566 face->refcount = 1;
1567 face->file = strdupW( buffer );
1568 face->StyleName = strdupW(face_name);
1570 needed = buffer_size;
1571 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1572 face->FullName = strdupW( buffer );
1573 else
1574 face->FullName = NULL;
1576 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1577 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1578 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1579 reg_load_dword(hkey_face, face_flags_value, (DWORD*)&face->flags);
1581 needed = sizeof(face->fs);
1582 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1584 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1586 face->scalable = TRUE;
1587 memset(&face->size, 0, sizeof(face->size));
1589 else
1591 face->scalable = FALSE;
1592 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1593 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1594 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1595 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1596 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1598 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1599 face->size.height, face->size.width, face->size.size >> 6,
1600 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1603 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1604 face->fs.fsCsb[0], face->fs.fsCsb[1],
1605 face->fs.fsUsb[0], face->fs.fsUsb[1],
1606 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1608 if (insert_face_in_family_list(face, family))
1609 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1611 release_face( face );
1614 /* load bitmap strikes */
1616 needed = buffer_size;
1617 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1619 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1621 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1622 RegCloseKey(hkey_strike);
1624 needed = buffer_size;
1628 /* move vertical fonts after their horizontal counterpart */
1629 /* assumes that font_list is already sorted by family name */
1630 static void reorder_vertical_fonts(void)
1632 Family *family, *next, *vert_family;
1633 struct list *ptr, *vptr;
1634 struct list vertical_families = LIST_INIT( vertical_families );
1636 LIST_FOR_EACH_ENTRY_SAFE( family, next, &font_list, Family, entry )
1638 if (family->FamilyName[0] != '@') continue;
1639 list_remove( &family->entry );
1640 list_add_tail( &vertical_families, &family->entry );
1643 ptr = list_head( &font_list );
1644 vptr = list_head( &vertical_families );
1645 while (ptr && vptr)
1647 family = LIST_ENTRY( ptr, Family, entry );
1648 vert_family = LIST_ENTRY( vptr, Family, entry );
1649 if (strcmpiW( family->FamilyName, vert_family->FamilyName + 1 ) > 0)
1651 list_remove( vptr );
1652 list_add_before( ptr, vptr );
1653 vptr = list_head( &vertical_families );
1655 else ptr = list_next( &font_list, ptr );
1657 list_move_tail( &font_list, &vertical_families );
1660 static void load_font_list_from_cache(HKEY hkey_font_cache)
1662 DWORD size, family_index = 0;
1663 Family *family;
1664 HKEY hkey_family;
1665 WCHAR buffer[4096];
1667 size = sizeof(buffer);
1668 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1670 WCHAR *english_family = NULL;
1671 WCHAR *family_name = strdupW( buffer );
1672 DWORD face_index = 0;
1674 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1675 TRACE("opened family key %s\n", debugstr_w(family_name));
1676 size = sizeof(buffer);
1677 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1678 english_family = strdupW( buffer );
1680 family = create_family(family_name, english_family);
1682 if(english_family)
1684 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1685 subst->from.name = strdupW(english_family);
1686 subst->from.charset = -1;
1687 subst->to.name = strdupW(family_name);
1688 subst->to.charset = -1;
1689 add_font_subst(&font_subst_list, subst, 0);
1692 size = sizeof(buffer);
1693 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1695 WCHAR *face_name = strdupW( buffer );
1696 HKEY hkey_face;
1698 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1700 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1701 RegCloseKey(hkey_face);
1703 HeapFree( GetProcessHeap(), 0, face_name );
1704 size = sizeof(buffer);
1706 RegCloseKey(hkey_family);
1707 release_family( family );
1708 size = sizeof(buffer);
1711 reorder_vertical_fonts();
1714 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1716 LONG ret;
1717 HKEY hkey_wine_fonts;
1719 /* We don't want to create the fonts key as volatile, so open this first */
1720 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1721 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1722 if(ret != ERROR_SUCCESS)
1724 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1725 return ret;
1728 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1729 KEY_ALL_ACCESS, NULL, hkey, disposition);
1730 RegCloseKey(hkey_wine_fonts);
1731 return ret;
1734 static void add_face_to_cache(Face *face)
1736 HKEY hkey_family, hkey_face;
1737 WCHAR *face_key_name;
1739 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1740 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1741 if(face->family->EnglishName)
1742 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1743 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1745 if(face->scalable)
1746 face_key_name = face->StyleName;
1747 else
1749 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1750 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1751 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1753 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1754 &hkey_face, NULL);
1755 if(!face->scalable)
1756 HeapFree(GetProcessHeap(), 0, face_key_name);
1758 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1759 (strlenW(face->file) + 1) * sizeof(WCHAR));
1760 if (face->FullName)
1761 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1762 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1764 reg_save_dword(hkey_face, face_index_value, face->face_index);
1765 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1766 reg_save_dword(hkey_face, face_version_value, face->font_version);
1767 if (face->flags) reg_save_dword(hkey_face, face_flags_value, face->flags);
1769 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1771 if(!face->scalable)
1773 reg_save_dword(hkey_face, face_height_value, face->size.height);
1774 reg_save_dword(hkey_face, face_width_value, face->size.width);
1775 reg_save_dword(hkey_face, face_size_value, face->size.size);
1776 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1777 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1778 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1780 RegCloseKey(hkey_face);
1781 RegCloseKey(hkey_family);
1784 static void remove_face_from_cache( Face *face )
1786 HKEY hkey_family;
1788 RegOpenKeyExW( hkey_font_cache, face->family->FamilyName, 0, KEY_ALL_ACCESS, &hkey_family );
1790 if (face->scalable)
1792 RegDeleteKeyW( hkey_family, face->StyleName );
1794 else
1796 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1797 WCHAR *face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1798 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1799 RegDeleteKeyW( hkey_family, face_key_name );
1800 HeapFree(GetProcessHeap(), 0, face_key_name);
1802 RegCloseKey(hkey_family);
1805 static WCHAR *prepend_at(WCHAR *family)
1807 WCHAR *str;
1809 if (!family)
1810 return NULL;
1812 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1813 str[0] = '@';
1814 strcpyW(str + 1, family);
1815 HeapFree(GetProcessHeap(), 0, family);
1816 return str;
1819 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1821 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT) );
1822 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1824 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1825 if (!*name)
1827 *name = *english;
1828 *english = NULL;
1830 else if (!strcmpiW( *name, *english ))
1832 HeapFree( GetProcessHeap(), 0, *english );
1833 *english = NULL;
1836 if (vertical)
1838 *name = prepend_at( *name );
1839 *english = prepend_at( *english );
1843 static Family *get_family( FT_Face ft_face, BOOL vertical )
1845 Family *family;
1846 WCHAR *name, *english_name;
1848 get_family_names( ft_face, &name, &english_name, vertical );
1850 family = find_family_from_name( name );
1852 if (!family)
1854 family = create_family( name, english_name );
1855 if (english_name)
1857 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1858 subst->from.name = strdupW( english_name );
1859 subst->from.charset = -1;
1860 subst->to.name = strdupW( name );
1861 subst->to.charset = -1;
1862 add_font_subst( &font_subst_list, subst, 0 );
1865 else
1867 HeapFree( GetProcessHeap(), 0, name );
1868 HeapFree( GetProcessHeap(), 0, english_name );
1869 family->refcount++;
1872 return family;
1875 static inline FT_Fixed get_font_version( FT_Face ft_face )
1877 FT_Fixed version = 0;
1878 TT_Header *header;
1880 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1881 if (header) version = header->Font_Revision;
1883 return version;
1886 static inline DWORD get_ntm_flags( FT_Face ft_face )
1888 DWORD flags = 0;
1889 FT_ULong table_size = 0;
1891 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1892 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1893 if (flags == 0) flags = NTM_REGULAR;
1895 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1896 flags |= NTM_PS_OPENTYPE;
1898 return flags;
1901 static inline void get_bitmap_size( FT_Face ft_face, Bitmap_Size *face_size )
1903 My_FT_Bitmap_Size *size;
1904 FT_WinFNT_HeaderRec winfnt_header;
1906 size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1907 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1908 size->height, size->width, size->size >> 6,
1909 size->x_ppem >> 6, size->y_ppem >> 6);
1910 face_size->height = size->height;
1911 face_size->width = size->width;
1912 face_size->size = size->size;
1913 face_size->x_ppem = size->x_ppem;
1914 face_size->y_ppem = size->y_ppem;
1916 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header )) {
1917 face_size->internal_leading = winfnt_header.internal_leading;
1918 if (winfnt_header.external_leading > 0 &&
1919 (face_size->height ==
1920 winfnt_header.pixel_height + winfnt_header.external_leading))
1921 face_size->height = winfnt_header.pixel_height;
1925 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1927 TT_OS2 *os2;
1928 FT_UInt dummy;
1929 CHARSETINFO csi;
1930 FT_WinFNT_HeaderRec winfnt_header;
1931 int i;
1933 memset( fs, 0, sizeof(*fs) );
1935 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1936 if (os2)
1938 fs->fsUsb[0] = os2->ulUnicodeRange1;
1939 fs->fsUsb[1] = os2->ulUnicodeRange2;
1940 fs->fsUsb[2] = os2->ulUnicodeRange3;
1941 fs->fsUsb[3] = os2->ulUnicodeRange4;
1943 if (os2->version == 0)
1945 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1946 fs->fsCsb[0] = FS_LATIN1;
1947 else
1948 fs->fsCsb[0] = FS_SYMBOL;
1950 else
1952 fs->fsCsb[0] = os2->ulCodePageRange1;
1953 fs->fsCsb[1] = os2->ulCodePageRange2;
1956 else
1958 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1960 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1961 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1962 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1963 *fs = csi.fs;
1967 if (fs->fsCsb[0] == 0)
1969 /* let's see if we can find any interesting cmaps */
1970 for (i = 0; i < ft_face->num_charmaps; i++)
1972 switch (ft_face->charmaps[i]->encoding)
1974 case FT_ENCODING_UNICODE:
1975 case FT_ENCODING_APPLE_ROMAN:
1976 fs->fsCsb[0] |= FS_LATIN1;
1977 break;
1978 case FT_ENCODING_MS_SYMBOL:
1979 fs->fsCsb[0] |= FS_SYMBOL;
1980 break;
1981 default:
1982 break;
1988 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1989 DWORD flags )
1991 struct stat st;
1992 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1994 face->refcount = 1;
1995 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
1996 if (!face->StyleName) face->StyleName = towstr( CP_ACP, ft_face->style_name );
1998 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
1999 if (flags & ADDFONT_VERTICAL_FONT)
2000 face->FullName = prepend_at( face->FullName );
2002 face->dev = 0;
2003 face->ino = 0;
2004 if (file)
2006 face->file = towstr( CP_UNIXCP, file );
2007 face->font_data_ptr = NULL;
2008 face->font_data_size = 0;
2009 if (!stat( file, &st ))
2011 face->dev = st.st_dev;
2012 face->ino = st.st_ino;
2015 else
2017 face->file = NULL;
2018 face->font_data_ptr = font_data_ptr;
2019 face->font_data_size = font_data_size;
2022 face->face_index = face_index;
2023 get_fontsig( ft_face, &face->fs );
2024 face->ntmFlags = get_ntm_flags( ft_face );
2025 face->font_version = get_font_version( ft_face );
2027 if (FT_IS_SCALABLE( ft_face ))
2029 memset( &face->size, 0, sizeof(face->size) );
2030 face->scalable = TRUE;
2032 else
2034 get_bitmap_size( ft_face, &face->size );
2035 face->scalable = FALSE;
2038 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
2039 face->flags = flags;
2040 face->family = NULL;
2041 face->cached_enum_data = NULL;
2043 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
2044 face->fs.fsCsb[0], face->fs.fsCsb[1],
2045 face->fs.fsUsb[0], face->fs.fsUsb[1],
2046 face->fs.fsUsb[2], face->fs.fsUsb[3]);
2048 return face;
2051 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
2052 FT_Long face_index, DWORD flags )
2054 Face *face;
2055 Family *family;
2057 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags );
2058 family = get_family( ft_face, flags & ADDFONT_VERTICAL_FONT );
2059 if (insert_face_in_family_list( face, family ))
2061 if (flags & ADDFONT_ADD_TO_CACHE)
2062 add_face_to_cache( face );
2064 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
2065 debugstr_w(face->StyleName));
2067 release_face( face );
2068 release_family( family );
2071 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
2072 FT_Long face_index, BOOL allow_bitmap )
2074 FT_Error err;
2075 TT_OS2 *pOS2;
2076 FT_Face ft_face;
2078 if (file)
2080 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
2081 err = pFT_New_Face(library, file, face_index, &ft_face);
2083 else
2085 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
2086 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
2089 if (err != 0)
2091 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
2092 return NULL;
2095 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
2096 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
2098 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
2099 goto fail;
2102 if (!FT_IS_SFNT( ft_face ))
2104 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
2106 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
2107 goto fail;
2110 else
2112 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
2113 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
2114 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
2116 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
2117 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
2118 goto fail;
2121 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
2122 we don't want to load these. */
2123 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
2125 FT_ULong len = 0;
2127 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
2129 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
2130 goto fail;
2135 if (!ft_face->family_name || !ft_face->style_name)
2137 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
2138 goto fail;
2141 return ft_face;
2142 fail:
2143 pFT_Done_Face( ft_face );
2144 return NULL;
2147 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
2149 FT_Face ft_face;
2150 FT_Long face_index = 0, num_faces;
2151 INT ret = 0;
2153 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
2154 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
2156 #ifdef HAVE_CARBON_CARBON_H
2157 if(file)
2159 char **mac_list = expand_mac_font(file);
2160 if(mac_list)
2162 BOOL had_one = FALSE;
2163 char **cursor;
2164 for(cursor = mac_list; *cursor; cursor++)
2166 had_one = TRUE;
2167 AddFontToList(*cursor, NULL, 0, flags);
2168 HeapFree(GetProcessHeap(), 0, *cursor);
2170 HeapFree(GetProcessHeap(), 0, mac_list);
2171 if(had_one)
2172 return 1;
2175 #endif /* HAVE_CARBON_CARBON_H */
2177 do {
2178 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_ALLOW_BITMAP );
2179 if (!ft_face) return 0;
2181 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
2183 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
2184 pFT_Done_Face(ft_face);
2185 return 0;
2188 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags);
2189 ++ret;
2191 if (FT_HAS_VERTICAL(ft_face))
2193 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index,
2194 flags | ADDFONT_VERTICAL_FONT);
2195 ++ret;
2198 num_faces = ft_face->num_faces;
2199 pFT_Done_Face(ft_face);
2200 } while(num_faces > ++face_index);
2201 return ret;
2204 static int remove_font_resource( const char *file, DWORD flags )
2206 Family *family, *family_next;
2207 Face *face, *face_next;
2208 struct stat st;
2209 int count = 0;
2211 if (stat( file, &st ) == -1) return 0;
2212 LIST_FOR_EACH_ENTRY_SAFE( family, family_next, &font_list, Family, entry )
2214 family->refcount++;
2215 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, Face, entry )
2217 if (!face->file) continue;
2218 if (LOWORD(face->flags) != LOWORD(flags)) continue;
2219 if (st.st_dev == face->dev && st.st_ino == face->ino)
2221 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount );
2222 release_face( face );
2223 count++;
2226 release_family( family );
2228 return count;
2231 static void DumpFontList(void)
2233 Family *family;
2234 Face *face;
2236 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2237 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
2238 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2239 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
2240 if(!face->scalable)
2241 TRACE(" %d", face->size.height);
2242 TRACE("\n");
2245 return;
2248 /***********************************************************
2249 * The replacement list is a way to map an entire font
2250 * family onto another family. For example adding
2252 * [HKCU\Software\Wine\Fonts\Replacements]
2253 * "Wingdings"="Winedings"
2255 * would enumerate the Winedings font both as Winedings and
2256 * Wingdings. However if a real Wingdings font is present the
2257 * replacement does not take place.
2260 static void LoadReplaceList(void)
2262 HKEY hkey;
2263 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2264 LPWSTR value;
2265 LPVOID data;
2267 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2268 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
2270 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2271 &valuelen, &datalen, NULL, NULL);
2273 valuelen++; /* returned value doesn't include room for '\0' */
2274 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2275 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2277 dlen = datalen;
2278 vlen = valuelen;
2279 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
2280 &dlen) == ERROR_SUCCESS) {
2281 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
2282 /* "NewName"="Oldname" */
2283 if(!find_family_from_any_name(value))
2285 Family * const family = find_family_from_any_name(data);
2286 if (family != NULL)
2288 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2289 if (new_family != NULL)
2291 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
2292 new_family->FamilyName = strdupW(value);
2293 new_family->EnglishName = NULL;
2294 list_init(&new_family->faces);
2295 new_family->replacement = &family->faces;
2296 list_add_tail(&font_list, &new_family->entry);
2299 else
2301 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2304 else
2306 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2308 /* reset dlen and vlen */
2309 dlen = datalen;
2310 vlen = valuelen;
2312 HeapFree(GetProcessHeap(), 0, data);
2313 HeapFree(GetProcessHeap(), 0, value);
2314 RegCloseKey(hkey);
2318 static const WCHAR *font_links_list[] =
2320 Lucida_Sans_Unicode,
2321 Microsoft_Sans_Serif,
2322 Tahoma
2325 static const struct font_links_defaults_list
2327 /* Keyed off substitution for "MS Shell Dlg" */
2328 const WCHAR *shelldlg;
2329 /* Maximum of four substitutes, plus terminating NULL pointer */
2330 const WCHAR *substitutes[5];
2331 } font_links_defaults_list[] =
2333 /* Non East-Asian */
2334 { Tahoma, /* FIXME unverified ordering */
2335 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2337 /* Below lists are courtesy of
2338 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2340 /* Japanese */
2341 { MS_UI_Gothic,
2342 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2344 /* Chinese Simplified */
2345 { SimSun,
2346 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2348 /* Korean */
2349 { Gulim,
2350 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2352 /* Chinese Traditional */
2353 { PMingLiU,
2354 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2359 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2361 SYSTEM_LINKS *font_link;
2363 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2365 if(!strcmpiW(font_link->font_name, name))
2366 return font_link;
2369 return NULL;
2372 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2374 const WCHAR *value;
2375 int i;
2376 FontSubst *psub;
2377 Family *family;
2378 Face *face;
2379 const WCHAR *file;
2381 if (values)
2383 SYSTEM_LINKS *font_link;
2385 psub = get_font_subst(&font_subst_list, name, -1);
2386 /* Don't store fonts that are only substitutes for other fonts */
2387 if(psub)
2389 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2390 return;
2393 font_link = find_font_link(name);
2394 if (font_link == NULL)
2396 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2397 font_link->font_name = strdupW(name);
2398 list_init(&font_link->links);
2399 list_add_tail(&system_links, &font_link->entry);
2402 memset(&font_link->fs, 0, sizeof font_link->fs);
2403 for (i = 0; values[i] != NULL; i++)
2405 const struct list *face_list;
2406 CHILD_FONT *child_font;
2408 value = values[i];
2409 if (!strcmpiW(name,value))
2410 continue;
2411 psub = get_font_subst(&font_subst_list, value, -1);
2412 if(psub)
2413 value = psub->to.name;
2414 family = find_family_from_name(value);
2415 if (!family)
2416 continue;
2417 file = NULL;
2418 /* Use first extant filename for this Family */
2419 face_list = get_face_list_from_family(family);
2420 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2422 if (!face->file)
2423 continue;
2424 file = strrchrW(face->file, '/');
2425 if (!file)
2426 file = face->file;
2427 else
2428 file++;
2429 break;
2431 if (!file)
2432 continue;
2433 face = find_face_from_filename(file, value);
2434 if(!face)
2436 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2437 continue;
2440 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2441 child_font->face = face;
2442 child_font->font = NULL;
2443 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2444 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2445 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2446 child_font->face->face_index);
2447 list_add_tail(&font_link->links, &child_font->entry);
2449 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2455 /*************************************************************
2456 * init_system_links
2458 static BOOL init_system_links(void)
2460 HKEY hkey;
2461 BOOL ret = FALSE;
2462 DWORD type, max_val, max_data, val_len, data_len, index;
2463 WCHAR *value, *data;
2464 WCHAR *entry, *next;
2465 SYSTEM_LINKS *font_link, *system_font_link;
2466 CHILD_FONT *child_font;
2467 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2468 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2469 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2470 Face *face;
2471 FontSubst *psub;
2472 UINT i, j;
2474 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2476 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2477 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2478 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2479 val_len = max_val + 1;
2480 data_len = max_data;
2481 index = 0;
2482 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2484 psub = get_font_subst(&font_subst_list, value, -1);
2485 /* Don't store fonts that are only substitutes for other fonts */
2486 if(psub)
2488 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2489 goto next;
2491 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2492 font_link->font_name = strdupW(value);
2493 memset(&font_link->fs, 0, sizeof font_link->fs);
2494 list_init(&font_link->links);
2495 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2497 WCHAR *face_name;
2498 CHILD_FONT *child_font;
2500 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2502 next = entry + strlenW(entry) + 1;
2504 face_name = strchrW(entry, ',');
2505 if(face_name)
2507 *face_name++ = 0;
2508 while(isspaceW(*face_name))
2509 face_name++;
2511 psub = get_font_subst(&font_subst_list, face_name, -1);
2512 if(psub)
2513 face_name = psub->to.name;
2515 face = find_face_from_filename(entry, face_name);
2516 if(!face)
2518 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2519 continue;
2522 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2523 child_font->face = face;
2524 child_font->font = NULL;
2525 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2526 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2527 TRACE("Adding file %s index %ld\n",
2528 debugstr_w(child_font->face->file), child_font->face->face_index);
2529 list_add_tail(&font_link->links, &child_font->entry);
2531 list_add_tail(&system_links, &font_link->entry);
2532 next:
2533 val_len = max_val + 1;
2534 data_len = max_data;
2537 HeapFree(GetProcessHeap(), 0, value);
2538 HeapFree(GetProcessHeap(), 0, data);
2539 RegCloseKey(hkey);
2543 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2544 if (!psub) {
2545 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2546 goto skip_internal;
2549 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2551 const FontSubst *psub2;
2552 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2554 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2556 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2557 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2559 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2560 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2562 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2564 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2568 skip_internal:
2570 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2571 that Tahoma has */
2573 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2574 system_font_link->font_name = strdupW(System);
2575 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2576 list_init(&system_font_link->links);
2578 face = find_face_from_filename(tahoma_ttf, Tahoma);
2579 if(face)
2581 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2582 child_font->face = face;
2583 child_font->font = NULL;
2584 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2585 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2586 TRACE("Found Tahoma in %s index %ld\n",
2587 debugstr_w(child_font->face->file), child_font->face->face_index);
2588 list_add_tail(&system_font_link->links, &child_font->entry);
2590 font_link = find_font_link(Tahoma);
2591 if (font_link != NULL)
2593 CHILD_FONT *font_link_entry;
2594 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2596 CHILD_FONT *new_child;
2597 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2598 new_child->face = font_link_entry->face;
2599 new_child->font = NULL;
2600 new_child->face->refcount++;
2601 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2602 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2603 list_add_tail(&system_font_link->links, &new_child->entry);
2606 list_add_tail(&system_links, &system_font_link->entry);
2607 return ret;
2610 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2612 DIR *dir;
2613 struct dirent *dent;
2614 char path[MAX_PATH];
2616 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2618 dir = opendir(dirname);
2619 if(!dir) {
2620 WARN("Can't open directory %s\n", debugstr_a(dirname));
2621 return FALSE;
2623 while((dent = readdir(dir)) != NULL) {
2624 struct stat statbuf;
2626 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2627 continue;
2629 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2631 sprintf(path, "%s/%s", dirname, dent->d_name);
2633 if(stat(path, &statbuf) == -1)
2635 WARN("Can't stat %s\n", debugstr_a(path));
2636 continue;
2638 if(S_ISDIR(statbuf.st_mode))
2639 ReadFontDir(path, external_fonts);
2640 else
2642 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2643 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2644 AddFontToList(path, NULL, 0, addfont_flags);
2647 closedir(dir);
2648 return TRUE;
2651 #ifdef SONAME_LIBFONTCONFIG
2653 static BOOL fontconfig_enabled;
2655 static UINT parse_aa_pattern( FcPattern *pattern )
2657 FcBool antialias;
2658 int rgba;
2659 UINT aa_flags = 0;
2661 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2662 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2664 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2666 switch (rgba)
2668 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2669 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2670 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2671 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2672 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2675 return aa_flags;
2678 static void init_fontconfig(void)
2680 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2682 if (!fc_handle)
2684 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2685 return;
2688 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2689 LOAD_FUNCPTR(FcConfigSubstitute);
2690 LOAD_FUNCPTR(FcFontList);
2691 LOAD_FUNCPTR(FcFontSetDestroy);
2692 LOAD_FUNCPTR(FcInit);
2693 LOAD_FUNCPTR(FcObjectSetAdd);
2694 LOAD_FUNCPTR(FcObjectSetCreate);
2695 LOAD_FUNCPTR(FcObjectSetDestroy);
2696 LOAD_FUNCPTR(FcPatternCreate);
2697 LOAD_FUNCPTR(FcPatternDestroy);
2698 LOAD_FUNCPTR(FcPatternGetBool);
2699 LOAD_FUNCPTR(FcPatternGetInteger);
2700 LOAD_FUNCPTR(FcPatternGetString);
2701 #undef LOAD_FUNCPTR
2703 if (pFcInit())
2705 FcPattern *pattern = pFcPatternCreate();
2706 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2707 default_aa_flags = parse_aa_pattern( pattern );
2708 pFcPatternDestroy( pattern );
2709 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2710 fontconfig_enabled = TRUE;
2714 static void load_fontconfig_fonts(void)
2716 FcPattern *pat;
2717 FcObjectSet *os;
2718 FcFontSet *fontset;
2719 int i, len;
2720 char *file;
2721 const char *ext;
2723 if (!fontconfig_enabled) return;
2725 pat = pFcPatternCreate();
2726 os = pFcObjectSetCreate();
2727 pFcObjectSetAdd(os, FC_FILE);
2728 pFcObjectSetAdd(os, FC_SCALABLE);
2729 pFcObjectSetAdd(os, FC_ANTIALIAS);
2730 pFcObjectSetAdd(os, FC_RGBA);
2731 fontset = pFcFontList(NULL, pat, os);
2732 if(!fontset) return;
2733 for(i = 0; i < fontset->nfont; i++) {
2734 FcBool scalable;
2735 DWORD aa_flags;
2737 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2738 continue;
2740 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2742 /* We're just interested in OT/TT fonts for now, so this hack just
2743 picks up the scalable fonts without extensions .pf[ab] to save time
2744 loading every other font */
2746 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2748 TRACE("not scalable\n");
2749 continue;
2752 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2753 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2755 len = strlen( file );
2756 if(len < 4) continue;
2757 ext = &file[ len - 3 ];
2758 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2759 AddFontToList(file, NULL, 0,
2760 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2762 pFcFontSetDestroy(fontset);
2763 pFcObjectSetDestroy(os);
2764 pFcPatternDestroy(pat);
2767 #elif defined(HAVE_CARBON_CARBON_H)
2769 static void load_mac_font_callback(const void *value, void *context)
2771 CFStringRef pathStr = value;
2772 CFIndex len;
2773 char* path;
2775 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2776 path = HeapAlloc(GetProcessHeap(), 0, len);
2777 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2779 TRACE("font file %s\n", path);
2780 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2782 HeapFree(GetProcessHeap(), 0, path);
2785 static void load_mac_fonts(void)
2787 CFStringRef removeDupesKey;
2788 CFBooleanRef removeDupesValue;
2789 CFDictionaryRef options;
2790 CTFontCollectionRef col;
2791 CFArrayRef descs;
2792 CFMutableSetRef paths;
2793 CFIndex i;
2795 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2796 removeDupesValue = kCFBooleanTrue;
2797 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2798 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2799 col = CTFontCollectionCreateFromAvailableFonts(options);
2800 if (options) CFRelease(options);
2801 if (!col)
2803 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2804 return;
2807 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2808 CFRelease(col);
2809 if (!descs)
2811 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2812 return;
2815 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2816 if (!paths)
2818 WARN("CFSetCreateMutable failed\n");
2819 CFRelease(descs);
2820 return;
2823 for (i = 0; i < CFArrayGetCount(descs); i++)
2825 CTFontDescriptorRef desc;
2826 CTFontRef font;
2827 ATSFontRef atsFont;
2828 OSStatus status;
2829 FSRef fsref;
2830 CFURLRef url;
2831 CFStringRef ext;
2832 CFStringRef path;
2834 desc = CFArrayGetValueAtIndex(descs, i);
2836 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2837 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2838 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2839 if (!font) continue;
2841 atsFont = CTFontGetPlatformFont(font, NULL);
2842 if (!atsFont)
2844 CFRelease(font);
2845 continue;
2848 status = ATSFontGetFileReference(atsFont, &fsref);
2849 CFRelease(font);
2850 if (status != noErr) continue;
2852 url = CFURLCreateFromFSRef(NULL, &fsref);
2853 if (!url) continue;
2855 ext = CFURLCopyPathExtension(url);
2856 if (ext)
2858 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2859 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2860 CFRelease(ext);
2861 if (skip)
2863 CFRelease(url);
2864 continue;
2868 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2869 CFRelease(url);
2870 if (!path) continue;
2872 CFSetAddValue(paths, path);
2873 CFRelease(path);
2876 CFRelease(descs);
2878 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2879 CFRelease(paths);
2882 #endif
2884 static char *get_data_dir_path( LPCWSTR file )
2886 char *unix_name = NULL;
2887 const char *data_dir = wine_get_data_dir();
2889 if (!data_dir) data_dir = wine_get_build_dir();
2891 if (data_dir)
2893 INT len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2895 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2896 strcpy(unix_name, data_dir);
2897 strcat(unix_name, "/fonts/");
2899 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2901 return unix_name;
2904 static BOOL load_font_from_data_dir(LPCWSTR file)
2906 BOOL ret = FALSE;
2907 char *unix_name = get_data_dir_path( file );
2909 if (unix_name)
2911 EnterCriticalSection( &freetype_cs );
2912 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
2913 LeaveCriticalSection( &freetype_cs );
2914 HeapFree(GetProcessHeap(), 0, unix_name);
2916 return ret;
2919 static char *get_winfonts_dir_path(LPCWSTR file)
2921 static const WCHAR slashW[] = {'\\','\0'};
2922 WCHAR windowsdir[MAX_PATH];
2924 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2925 strcatW(windowsdir, fontsW);
2926 strcatW(windowsdir, slashW);
2927 strcatW(windowsdir, file);
2928 return wine_get_unix_file_name( windowsdir );
2931 static void load_system_fonts(void)
2933 HKEY hkey;
2934 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2935 const WCHAR * const *value;
2936 DWORD dlen, type;
2937 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2938 char *unixname;
2940 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2941 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2942 strcatW(windowsdir, fontsW);
2943 for(value = SystemFontValues; *value; value++) {
2944 dlen = sizeof(data);
2945 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2946 type == REG_SZ) {
2947 BOOL added = FALSE;
2949 sprintfW(pathW, fmtW, windowsdir, data);
2950 if((unixname = wine_get_unix_file_name(pathW))) {
2951 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
2952 HeapFree(GetProcessHeap(), 0, unixname);
2954 if (!added)
2955 load_font_from_data_dir(data);
2958 RegCloseKey(hkey);
2962 /*************************************************************
2964 * This adds registry entries for any externally loaded fonts
2965 * (fonts from fontconfig or FontDirs). It also deletes entries
2966 * of no longer existing fonts.
2969 static void update_reg_entries(void)
2971 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2972 LPWSTR valueW;
2973 DWORD len;
2974 Family *family;
2975 Face *face;
2976 WCHAR *file, *path;
2977 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2979 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2980 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2981 ERR("Can't create Windows font reg key\n");
2982 goto end;
2985 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2986 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2987 ERR("Can't create Windows font reg key\n");
2988 goto end;
2991 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2992 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2993 ERR("Can't create external font reg key\n");
2994 goto end;
2997 /* enumerate the fonts and add external ones to the two keys */
2999 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
3000 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
3001 char *buffer;
3002 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
3004 if(face->FullName)
3006 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
3007 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3008 strcpyW(valueW, face->FullName);
3010 else
3012 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
3013 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3014 strcpyW(valueW, family->FamilyName);
3017 buffer = strWtoA( CP_UNIXCP, face->file );
3018 path = wine_get_dos_file_name( buffer );
3019 HeapFree( GetProcessHeap(), 0, buffer );
3021 if (path)
3022 file = path;
3023 else if ((file = strrchrW(face->file, '/')))
3024 file++;
3025 else
3026 file = face->file;
3028 len = strlenW(file) + 1;
3029 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3030 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3031 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3033 HeapFree(GetProcessHeap(), 0, path);
3034 HeapFree(GetProcessHeap(), 0, valueW);
3037 end:
3038 if(external_key) RegCloseKey(external_key);
3039 if(win9x_key) RegCloseKey(win9x_key);
3040 if(winnt_key) RegCloseKey(winnt_key);
3041 return;
3044 static void delete_external_font_keys(void)
3046 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
3047 DWORD dlen, vlen, datalen, valuelen, i, type;
3048 LPWSTR valueW;
3049 LPVOID data;
3051 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
3052 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
3053 ERR("Can't create Windows font reg key\n");
3054 goto end;
3057 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
3058 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
3059 ERR("Can't create Windows font reg key\n");
3060 goto end;
3063 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
3064 ERR("Can't create external font reg key\n");
3065 goto end;
3068 /* Delete all external fonts added last time */
3070 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3071 &valuelen, &datalen, NULL, NULL);
3072 valuelen++; /* returned value doesn't include room for '\0' */
3073 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3074 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3076 dlen = datalen * sizeof(WCHAR);
3077 vlen = valuelen;
3078 i = 0;
3079 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
3080 &dlen) == ERROR_SUCCESS) {
3082 RegDeleteValueW(winnt_key, valueW);
3083 RegDeleteValueW(win9x_key, valueW);
3084 /* reset dlen and vlen */
3085 dlen = datalen;
3086 vlen = valuelen;
3088 HeapFree(GetProcessHeap(), 0, data);
3089 HeapFree(GetProcessHeap(), 0, valueW);
3091 /* Delete the old external fonts key */
3092 RegCloseKey(external_key);
3093 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
3095 end:
3096 if(win9x_key) RegCloseKey(win9x_key);
3097 if(winnt_key) RegCloseKey(winnt_key);
3100 /*************************************************************
3101 * WineEngAddFontResourceEx
3104 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3106 INT ret = 0;
3108 GDI_CheckNotLock();
3110 if (ft_handle) /* do it only if we have freetype up and running */
3112 char *unixname;
3114 EnterCriticalSection( &freetype_cs );
3116 if((unixname = wine_get_unix_file_name(file)))
3118 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3120 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3121 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
3122 HeapFree(GetProcessHeap(), 0, unixname);
3124 if (!ret && !strchrW(file, '\\')) {
3125 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
3126 if ((unixname = get_winfonts_dir_path( file )))
3128 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3129 HeapFree(GetProcessHeap(), 0, unixname);
3131 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
3132 if (!ret && (unixname = get_data_dir_path( file )))
3134 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3135 HeapFree(GetProcessHeap(), 0, unixname);
3139 LeaveCriticalSection( &freetype_cs );
3141 return ret;
3144 /*************************************************************
3145 * WineEngAddFontMemResourceEx
3148 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3150 GDI_CheckNotLock();
3152 if (ft_handle) /* do it only if we have freetype up and running */
3154 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
3156 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
3157 memcpy(pFontCopy, pbFont, cbFont);
3159 EnterCriticalSection( &freetype_cs );
3160 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3161 LeaveCriticalSection( &freetype_cs );
3163 if (*pcFonts == 0)
3165 TRACE("AddFontToList failed\n");
3166 HeapFree(GetProcessHeap(), 0, pFontCopy);
3167 return 0;
3169 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
3170 * For now return something unique but quite random
3172 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
3173 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
3176 *pcFonts = 0;
3177 return 0;
3180 /*************************************************************
3181 * WineEngRemoveFontResourceEx
3184 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3186 INT ret = 0;
3188 GDI_CheckNotLock();
3190 if (ft_handle) /* do it only if we have freetype up and running */
3192 char *unixname;
3194 EnterCriticalSection( &freetype_cs );
3196 if ((unixname = wine_get_unix_file_name(file)))
3198 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3200 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3201 ret = remove_font_resource( unixname, addfont_flags );
3202 HeapFree(GetProcessHeap(), 0, unixname);
3204 if (!ret && !strchrW(file, '\\'))
3206 if ((unixname = get_winfonts_dir_path( file )))
3208 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3209 HeapFree(GetProcessHeap(), 0, unixname);
3211 if (!ret && (unixname = get_data_dir_path( file )))
3213 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3214 HeapFree(GetProcessHeap(), 0, unixname);
3218 LeaveCriticalSection( &freetype_cs );
3220 return ret;
3223 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
3225 WCHAR *fullname;
3226 char *unix_name;
3227 int file_len;
3229 if (!font_file) return NULL;
3231 file_len = strlenW( font_file );
3233 if (font_path && font_path[0])
3235 int path_len = strlenW( font_path );
3236 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
3237 if (!fullname) return NULL;
3238 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
3239 fullname[path_len] = '\\';
3240 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
3242 else
3244 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
3245 if (!len) return NULL;
3246 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3247 if (!fullname) return NULL;
3248 GetFullPathNameW( font_file, len, fullname, NULL );
3251 unix_name = wine_get_unix_file_name( fullname );
3252 HeapFree( GetProcessHeap(), 0, fullname );
3253 return unix_name;
3256 #include <pshpack1.h>
3257 struct fontdir
3259 WORD num_of_resources;
3260 WORD res_id;
3261 WORD dfVersion;
3262 DWORD dfSize;
3263 CHAR dfCopyright[60];
3264 WORD dfType;
3265 WORD dfPoints;
3266 WORD dfVertRes;
3267 WORD dfHorizRes;
3268 WORD dfAscent;
3269 WORD dfInternalLeading;
3270 WORD dfExternalLeading;
3271 BYTE dfItalic;
3272 BYTE dfUnderline;
3273 BYTE dfStrikeOut;
3274 WORD dfWeight;
3275 BYTE dfCharSet;
3276 WORD dfPixWidth;
3277 WORD dfPixHeight;
3278 BYTE dfPitchAndFamily;
3279 WORD dfAvgWidth;
3280 WORD dfMaxWidth;
3281 BYTE dfFirstChar;
3282 BYTE dfLastChar;
3283 BYTE dfDefaultChar;
3284 BYTE dfBreakChar;
3285 WORD dfWidthBytes;
3286 DWORD dfDevice;
3287 DWORD dfFace;
3288 DWORD dfReserved;
3289 CHAR szFaceName[LF_FACESIZE];
3292 #include <poppack.h>
3294 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
3295 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
3297 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
3299 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3300 Face *face;
3301 WCHAR *name, *english_name;
3302 ENUMLOGFONTEXW elf;
3303 NEWTEXTMETRICEXW ntm;
3304 DWORD type;
3306 if (!ft_face) return FALSE;
3307 face = create_face( ft_face, 0, unix_name, NULL, 0, 0 );
3308 get_family_names( ft_face, &name, &english_name, FALSE );
3309 pFT_Done_Face( ft_face );
3311 GetEnumStructs( face, name, &elf, &ntm, &type );
3312 release_face( face );
3313 HeapFree( GetProcessHeap(), 0, name );
3314 HeapFree( GetProcessHeap(), 0, english_name );
3316 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3318 memset( fd, 0, sizeof(*fd) );
3320 fd->num_of_resources = 1;
3321 fd->res_id = 0;
3322 fd->dfVersion = 0x200;
3323 fd->dfSize = sizeof(*fd);
3324 strcpy( fd->dfCopyright, "Wine fontdir" );
3325 fd->dfType = 0x4003; /* 0x0080 set if private */
3326 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3327 fd->dfVertRes = 72;
3328 fd->dfHorizRes = 72;
3329 fd->dfAscent = ntm.ntmTm.tmAscent;
3330 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3331 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3332 fd->dfItalic = ntm.ntmTm.tmItalic;
3333 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3334 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3335 fd->dfWeight = ntm.ntmTm.tmWeight;
3336 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3337 fd->dfPixWidth = 0;
3338 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3339 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3340 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3341 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3342 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3343 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3344 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3345 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3346 fd->dfWidthBytes = 0;
3347 fd->dfDevice = 0;
3348 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3349 fd->dfReserved = 0;
3350 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3352 return TRUE;
3355 #define NE_FFLAGS_LIBMODULE 0x8000
3356 #define NE_OSFLAGS_WINDOWS 0x02
3358 static const char dos_string[0x40] = "This is a TrueType resource file";
3359 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3361 #include <pshpack2.h>
3363 struct ne_typeinfo
3365 WORD type_id;
3366 WORD count;
3367 DWORD res;
3370 struct ne_nameinfo
3372 WORD off;
3373 WORD len;
3374 WORD flags;
3375 WORD id;
3376 DWORD res;
3379 struct rsrc_tab
3381 WORD align;
3382 struct ne_typeinfo fontdir_type;
3383 struct ne_nameinfo fontdir_name;
3384 struct ne_typeinfo scalable_type;
3385 struct ne_nameinfo scalable_name;
3386 WORD end_of_rsrc;
3387 BYTE fontdir_res_name[8];
3390 #include <poppack.h>
3392 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3394 BOOL ret = FALSE;
3395 HANDLE file;
3396 DWORD size, written;
3397 BYTE *ptr, *start;
3398 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3399 char *font_fileA, *last_part, *ext;
3400 IMAGE_DOS_HEADER dos;
3401 IMAGE_OS2_HEADER ne =
3403 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3404 0, 0, 0, 0, 0, 0,
3405 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3406 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3408 struct rsrc_tab rsrc_tab =
3411 { 0x8007, 1, 0 },
3412 { 0, 0, 0x0c50, 0x2c, 0 },
3413 { 0x80cc, 1, 0 },
3414 { 0, 0, 0x0c50, 0x8001, 0 },
3416 { 7,'F','O','N','T','D','I','R'}
3419 memset( &dos, 0, sizeof(dos) );
3420 dos.e_magic = IMAGE_DOS_SIGNATURE;
3421 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3423 /* import name is last part\0, resident name is last part without extension
3424 non-resident name is "FONTRES:" + lfFaceName */
3426 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3427 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3428 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3430 last_part = strrchr( font_fileA, '\\' );
3431 if (last_part) last_part++;
3432 else last_part = font_fileA;
3433 import_name_len = strlen( last_part ) + 1;
3435 ext = strchr( last_part, '.' );
3436 if (ext) res_name_len = ext - last_part;
3437 else res_name_len = import_name_len - 1;
3439 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3441 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3442 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3443 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3444 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3445 ne.ne_cbenttab = 2;
3446 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3448 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3449 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3450 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3451 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3453 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3454 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3456 if (!ptr)
3458 HeapFree( GetProcessHeap(), 0, font_fileA );
3459 return FALSE;
3462 memcpy( ptr, &dos, sizeof(dos) );
3463 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3464 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3466 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3467 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3469 ptr = start + dos.e_lfanew + ne.ne_restab;
3470 *ptr++ = res_name_len;
3471 memcpy( ptr, last_part, res_name_len );
3473 ptr = start + dos.e_lfanew + ne.ne_imptab;
3474 *ptr++ = import_name_len;
3475 memcpy( ptr, last_part, import_name_len );
3477 ptr = start + ne.ne_nrestab;
3478 *ptr++ = non_res_name_len;
3479 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3480 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3482 ptr = start + (rsrc_tab.scalable_name.off << 4);
3483 memcpy( ptr, font_fileA, font_file_len );
3485 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3486 memcpy( ptr, fontdir, fontdir->dfSize );
3488 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3489 if (file != INVALID_HANDLE_VALUE)
3491 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3492 ret = TRUE;
3493 CloseHandle( file );
3496 HeapFree( GetProcessHeap(), 0, start );
3497 HeapFree( GetProcessHeap(), 0, font_fileA );
3499 return ret;
3502 /*************************************************************
3503 * WineEngCreateScalableFontResource
3506 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3507 LPCWSTR font_file, LPCWSTR font_path )
3509 char *unix_name = get_ttf_file_name( font_file, font_path );
3510 struct fontdir fontdir;
3511 BOOL ret = FALSE;
3513 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3514 SetLastError( ERROR_INVALID_PARAMETER );
3515 else
3517 if (hidden) fontdir.dfType |= 0x80;
3518 ret = create_fot( resource, font_file, &fontdir );
3521 HeapFree( GetProcessHeap(), 0, unix_name );
3522 return ret;
3525 static const struct nls_update_font_list
3527 UINT ansi_cp, oem_cp;
3528 const char *oem, *fixed, *system;
3529 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3530 /* these are for font substitutes */
3531 const char *shelldlg, *tmsrmn;
3532 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3533 *helv_0, *tmsrmn_0;
3534 const struct subst
3536 const char *from, *to;
3537 } arial_0, courier_new_0, times_new_roman_0;
3538 } nls_update_font_list[] =
3540 /* Latin 1 (United States) */
3541 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3542 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3543 "Tahoma","Times New Roman",
3544 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3545 { 0 }, { 0 }, { 0 }
3547 /* Latin 1 (Multilingual) */
3548 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3549 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3550 "Tahoma","Times New Roman", /* FIXME unverified */
3551 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3552 { 0 }, { 0 }, { 0 }
3554 /* Eastern Europe */
3555 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3556 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3557 "Tahoma","Times New Roman", /* FIXME unverified */
3558 "Fixedsys,238", "System,238",
3559 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3560 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3561 { "Arial CE,0", "Arial,238" },
3562 { "Courier New CE,0", "Courier New,238" },
3563 { "Times New Roman CE,0", "Times New Roman,238" }
3565 /* Cyrillic */
3566 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3567 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3568 "Tahoma","Times New Roman", /* FIXME unverified */
3569 "Fixedsys,204", "System,204",
3570 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3571 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3572 { "Arial Cyr,0", "Arial,204" },
3573 { "Courier New Cyr,0", "Courier New,204" },
3574 { "Times New Roman Cyr,0", "Times New Roman,204" }
3576 /* Greek */
3577 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3578 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3579 "Tahoma","Times New Roman", /* FIXME unverified */
3580 "Fixedsys,161", "System,161",
3581 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3582 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3583 { "Arial Greek,0", "Arial,161" },
3584 { "Courier New Greek,0", "Courier New,161" },
3585 { "Times New Roman Greek,0", "Times New Roman,161" }
3587 /* Turkish */
3588 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3589 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3590 "Tahoma","Times New Roman", /* FIXME unverified */
3591 "Fixedsys,162", "System,162",
3592 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3593 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3594 { "Arial Tur,0", "Arial,162" },
3595 { "Courier New Tur,0", "Courier New,162" },
3596 { "Times New Roman Tur,0", "Times New Roman,162" }
3598 /* Hebrew */
3599 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3600 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3601 "Tahoma","Times New Roman", /* FIXME unverified */
3602 "Fixedsys,177", "System,177",
3603 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3604 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3605 { 0 }, { 0 }, { 0 }
3607 /* Arabic */
3608 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3609 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3610 "Microsoft Sans Serif","Times New Roman",
3611 "Fixedsys,178", "System,178",
3612 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3613 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3614 { 0 }, { 0 }, { 0 }
3616 /* Baltic */
3617 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3618 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3619 "Tahoma","Times New Roman", /* FIXME unverified */
3620 "Fixedsys,186", "System,186",
3621 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3622 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3623 { "Arial Baltic,0", "Arial,186" },
3624 { "Courier New Baltic,0", "Courier New,186" },
3625 { "Times New Roman Baltic,0", "Times New Roman,186" }
3627 /* Vietnamese */
3628 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3629 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3630 "Tahoma","Times New Roman", /* FIXME unverified */
3631 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3632 { 0 }, { 0 }, { 0 }
3634 /* Thai */
3635 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3636 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3637 "Tahoma","Times New Roman", /* FIXME unverified */
3638 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3639 { 0 }, { 0 }, { 0 }
3641 /* Japanese */
3642 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3643 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3644 "MS UI Gothic","MS Serif",
3645 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3646 { 0 }, { 0 }, { 0 }
3648 /* Chinese Simplified */
3649 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3650 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3651 "SimSun", "NSimSun",
3652 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3653 { 0 }, { 0 }, { 0 }
3655 /* Korean */
3656 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3657 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3658 "Gulim", "Batang",
3659 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3660 { 0 }, { 0 }, { 0 }
3662 /* Chinese Traditional */
3663 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3664 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3665 "PMingLiU", "MingLiU",
3666 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3667 { 0 }, { 0 }, { 0 }
3671 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3673 return ( ansi_cp == 932 /* CP932 for Japanese */
3674 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3675 || ansi_cp == 949 /* CP949 for Korean */
3676 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3679 static inline HKEY create_fonts_NT_registry_key(void)
3681 HKEY hkey = 0;
3683 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3684 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3685 return hkey;
3688 static inline HKEY create_fonts_9x_registry_key(void)
3690 HKEY hkey = 0;
3692 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3693 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3694 return hkey;
3697 static inline HKEY create_config_fonts_registry_key(void)
3699 HKEY hkey = 0;
3701 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3702 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3703 return hkey;
3706 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3708 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3710 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3711 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3712 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3713 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3716 static void set_value_key(HKEY hkey, const char *name, const char *value)
3718 if (value)
3719 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3720 else if (name)
3721 RegDeleteValueA(hkey, name);
3724 static void update_font_association_info(UINT current_ansi_codepage)
3726 static const char *font_assoc_reg_key = "System\\CurrentControlSet\\Control\\FontAssoc";
3727 static const char *assoc_charset_subkey = "Associated Charset";
3729 if (is_dbcs_ansi_cp(current_ansi_codepage))
3731 HKEY hkey;
3732 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, font_assoc_reg_key, &hkey) == ERROR_SUCCESS)
3734 HKEY hsubkey;
3735 if (RegCreateKeyA(hkey, assoc_charset_subkey, &hsubkey) == ERROR_SUCCESS)
3737 switch (current_ansi_codepage)
3739 case 932:
3740 set_value_key(hsubkey, "ANSI(00)", "NO");
3741 set_value_key(hsubkey, "OEM(FF)", "NO");
3742 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3743 break;
3744 case 936:
3745 case 949:
3746 case 950:
3747 set_value_key(hsubkey, "ANSI(00)", "YES");
3748 set_value_key(hsubkey, "OEM(FF)", "YES");
3749 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3750 break;
3752 RegCloseKey(hsubkey);
3755 /* TODO: Associated DefaultFonts */
3757 RegCloseKey(hkey);
3760 else
3761 RegDeleteTreeA(HKEY_LOCAL_MACHINE, font_assoc_reg_key);
3764 static void update_font_info(void)
3766 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3767 char buf[40], cpbuf[40];
3768 DWORD len, type;
3769 HKEY hkey = 0;
3770 UINT i, ansi_cp = 0, oem_cp = 0;
3771 DWORD screen_dpi = 96, font_dpi = 0;
3772 BOOL done = FALSE;
3774 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3775 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3776 &hkey) == ERROR_SUCCESS)
3778 reg_load_dword(hkey, logpixels, &screen_dpi);
3779 RegCloseKey(hkey);
3782 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3783 return;
3785 reg_load_dword(hkey, logpixels, &font_dpi);
3787 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3788 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3789 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3790 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3791 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3793 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3794 if (is_dbcs_ansi_cp(ansi_cp))
3795 use_default_fallback = TRUE;
3797 buf[0] = 0;
3798 len = sizeof(buf);
3799 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3801 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3803 RegCloseKey(hkey);
3804 return;
3806 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3807 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3809 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3810 ansi_cp, oem_cp, screen_dpi);
3812 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3813 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3814 RegCloseKey(hkey);
3816 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3818 HKEY hkey;
3820 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3821 nls_update_font_list[i].oem_cp == oem_cp)
3823 hkey = create_config_fonts_registry_key();
3824 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3825 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3826 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3827 RegCloseKey(hkey);
3829 hkey = create_fonts_NT_registry_key();
3830 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3831 RegCloseKey(hkey);
3833 hkey = create_fonts_9x_registry_key();
3834 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3835 RegCloseKey(hkey);
3837 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3839 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3840 strlen(nls_update_font_list[i].shelldlg)+1);
3841 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3842 strlen(nls_update_font_list[i].tmsrmn)+1);
3844 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3845 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3846 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3847 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3848 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3849 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3850 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3851 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3853 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3854 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3855 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3857 RegCloseKey(hkey);
3859 done = TRUE;
3861 else
3863 /* Delete the FontSubstitutes from other locales */
3864 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3866 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3867 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3868 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3869 RegCloseKey(hkey);
3873 if (!done)
3874 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3876 /* update locale dependent font association info in registry.
3877 update only when codepages changed, not logpixels. */
3878 if (strcmp(buf, cpbuf) != 0)
3879 update_font_association_info(ansi_cp);
3882 static BOOL init_freetype(void)
3884 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3885 if(!ft_handle) {
3886 WINE_MESSAGE(
3887 "Wine cannot find the FreeType font library. To enable Wine to\n"
3888 "use TrueType fonts please install a version of FreeType greater than\n"
3889 "or equal to 2.0.5.\n"
3890 "http://www.freetype.org\n");
3891 return FALSE;
3894 #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;}
3896 LOAD_FUNCPTR(FT_Done_Face)
3897 LOAD_FUNCPTR(FT_Get_Char_Index)
3898 LOAD_FUNCPTR(FT_Get_First_Char)
3899 LOAD_FUNCPTR(FT_Get_Module)
3900 LOAD_FUNCPTR(FT_Get_Next_Char)
3901 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3902 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3903 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3904 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3905 LOAD_FUNCPTR(FT_Init_FreeType)
3906 LOAD_FUNCPTR(FT_Library_Version)
3907 LOAD_FUNCPTR(FT_Load_Glyph)
3908 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3909 LOAD_FUNCPTR(FT_Matrix_Multiply)
3910 #ifndef FT_MULFIX_INLINED
3911 LOAD_FUNCPTR(FT_MulFix)
3912 #endif
3913 LOAD_FUNCPTR(FT_New_Face)
3914 LOAD_FUNCPTR(FT_New_Memory_Face)
3915 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3916 LOAD_FUNCPTR(FT_Outline_Transform)
3917 LOAD_FUNCPTR(FT_Outline_Translate)
3918 LOAD_FUNCPTR(FT_Render_Glyph)
3919 LOAD_FUNCPTR(FT_Select_Charmap)
3920 LOAD_FUNCPTR(FT_Set_Charmap)
3921 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3922 LOAD_FUNCPTR(FT_Vector_Transform)
3923 LOAD_FUNCPTR(FT_Vector_Unit)
3924 #undef LOAD_FUNCPTR
3925 /* Don't warn if these ones are missing */
3926 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3927 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3928 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3929 #endif
3931 if(pFT_Init_FreeType(&library) != 0) {
3932 ERR("Can't init FreeType library\n");
3933 wine_dlclose(ft_handle, NULL, 0);
3934 ft_handle = NULL;
3935 return FALSE;
3937 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3939 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3940 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3941 ((FT_Version.minor << 8) & 0x00ff00) |
3942 ((FT_Version.patch ) & 0x0000ff);
3944 font_driver = &freetype_funcs;
3945 return TRUE;
3947 sym_not_found:
3948 WINE_MESSAGE(
3949 "Wine cannot find certain functions that it needs inside the FreeType\n"
3950 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3951 "FreeType to at least version 2.1.4.\n"
3952 "http://www.freetype.org\n");
3953 wine_dlclose(ft_handle, NULL, 0);
3954 ft_handle = NULL;
3955 return FALSE;
3958 static void init_font_list(void)
3960 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3961 static const WCHAR pathW[] = {'P','a','t','h',0};
3962 HKEY hkey;
3963 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3964 WCHAR windowsdir[MAX_PATH];
3965 char *unixname;
3966 const char *data_dir;
3968 delete_external_font_keys();
3970 /* load the system bitmap fonts */
3971 load_system_fonts();
3973 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3974 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3975 strcatW(windowsdir, fontsW);
3976 if((unixname = wine_get_unix_file_name(windowsdir)))
3978 ReadFontDir(unixname, FALSE);
3979 HeapFree(GetProcessHeap(), 0, unixname);
3982 /* load the system truetype fonts */
3983 data_dir = wine_get_data_dir();
3984 if (!data_dir) data_dir = wine_get_build_dir();
3985 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3987 strcpy(unixname, data_dir);
3988 strcat(unixname, "/fonts/");
3989 ReadFontDir(unixname, TRUE);
3990 HeapFree(GetProcessHeap(), 0, unixname);
3993 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3994 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3995 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3996 will skip these. */
3997 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3998 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3999 &hkey) == ERROR_SUCCESS)
4001 LPWSTR data, valueW;
4002 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
4003 &valuelen, &datalen, NULL, NULL);
4005 valuelen++; /* returned value doesn't include room for '\0' */
4006 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
4007 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
4008 if (valueW && data)
4010 dlen = datalen * sizeof(WCHAR);
4011 vlen = valuelen;
4012 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
4013 &dlen) == ERROR_SUCCESS)
4015 if(data[0] && (data[1] == ':'))
4017 if((unixname = wine_get_unix_file_name(data)))
4019 AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
4020 HeapFree(GetProcessHeap(), 0, unixname);
4023 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
4025 WCHAR pathW[MAX_PATH];
4026 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
4027 BOOL added = FALSE;
4029 sprintfW(pathW, fmtW, windowsdir, data);
4030 if((unixname = wine_get_unix_file_name(pathW)))
4032 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
4033 HeapFree(GetProcessHeap(), 0, unixname);
4035 if (!added)
4036 load_font_from_data_dir(data);
4038 /* reset dlen and vlen */
4039 dlen = datalen;
4040 vlen = valuelen;
4043 HeapFree(GetProcessHeap(), 0, data);
4044 HeapFree(GetProcessHeap(), 0, valueW);
4045 RegCloseKey(hkey);
4048 #ifdef SONAME_LIBFONTCONFIG
4049 load_fontconfig_fonts();
4050 #elif defined(HAVE_CARBON_CARBON_H)
4051 load_mac_fonts();
4052 #endif
4054 /* then look in any directories that we've specified in the config file */
4055 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
4056 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
4058 DWORD len;
4059 LPWSTR valueW;
4060 LPSTR valueA, ptr;
4062 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
4064 len += sizeof(WCHAR);
4065 valueW = HeapAlloc( GetProcessHeap(), 0, len );
4066 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
4068 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
4069 valueA = HeapAlloc( GetProcessHeap(), 0, len );
4070 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
4071 TRACE( "got font path %s\n", debugstr_a(valueA) );
4072 ptr = valueA;
4073 while (ptr)
4075 const char* home;
4076 LPSTR next = strchr( ptr, ':' );
4077 if (next) *next++ = 0;
4078 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
4079 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
4081 strcpy( unixname, home );
4082 strcat( unixname, ptr + 1 );
4083 ReadFontDir( unixname, TRUE );
4084 HeapFree( GetProcessHeap(), 0, unixname );
4086 else
4087 ReadFontDir( ptr, TRUE );
4088 ptr = next;
4090 HeapFree( GetProcessHeap(), 0, valueA );
4092 HeapFree( GetProcessHeap(), 0, valueW );
4094 RegCloseKey(hkey);
4098 static BOOL move_to_front(const WCHAR *name)
4100 Family *family, *cursor2;
4101 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
4103 if(!strcmpiW(family->FamilyName, name))
4105 list_remove(&family->entry);
4106 list_add_head(&font_list, &family->entry);
4107 return TRUE;
4110 return FALSE;
4113 static BOOL set_default(const WCHAR **name_list)
4115 while (*name_list)
4117 if (move_to_front(*name_list)) return TRUE;
4118 name_list++;
4121 return FALSE;
4124 static void reorder_font_list(void)
4126 set_default( default_serif_list );
4127 set_default( default_fixed_list );
4128 set_default( default_sans_list );
4131 /*************************************************************
4132 * WineEngInit
4134 * Initialize FreeType library and create a list of available faces
4136 BOOL WineEngInit(void)
4138 DWORD disposition;
4139 HANDLE font_mutex;
4141 /* update locale dependent font info in registry */
4142 update_font_info();
4144 if(!init_freetype()) return FALSE;
4146 #ifdef SONAME_LIBFONTCONFIG
4147 init_fontconfig();
4148 #endif
4150 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
4152 ERR("Failed to create font mutex\n");
4153 return FALSE;
4155 WaitForSingleObject(font_mutex, INFINITE);
4157 create_font_cache_key(&hkey_font_cache, &disposition);
4159 if(disposition == REG_CREATED_NEW_KEY)
4160 init_font_list();
4161 else
4162 load_font_list_from_cache(hkey_font_cache);
4164 reorder_font_list();
4166 DumpFontList();
4167 LoadSubstList();
4168 DumpSubstList();
4169 LoadReplaceList();
4171 if(disposition == REG_CREATED_NEW_KEY)
4172 update_reg_entries();
4174 init_system_links();
4176 ReleaseMutex(font_mutex);
4177 return TRUE;
4181 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
4183 TT_OS2 *pOS2;
4184 TT_HoriHeader *pHori;
4186 LONG ppem;
4187 const LONG MAX_PPEM = (1 << 16) - 1;
4189 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4190 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4192 if(height == 0) height = 16;
4194 /* Calc. height of EM square:
4196 * For +ve lfHeight we have
4197 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
4198 * Re-arranging gives:
4199 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4201 * For -ve lfHeight we have
4202 * |lfHeight| = ppem
4203 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4204 * with il = winAscent + winDescent - units_per_em]
4208 if(height > 0) {
4209 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
4210 ppem = MulDiv(ft_face->units_per_EM, height,
4211 pHori->Ascender - pHori->Descender);
4212 else
4213 ppem = MulDiv(ft_face->units_per_EM, height,
4214 pOS2->usWinAscent + pOS2->usWinDescent);
4215 if(ppem > MAX_PPEM) {
4216 WARN("Ignoring too large height %d, ppem %d\n", height, ppem);
4217 ppem = 1;
4220 else if(height >= -MAX_PPEM)
4221 ppem = -height;
4222 else {
4223 WARN("Ignoring too large height %d\n", height);
4224 ppem = 1;
4227 return ppem;
4230 static struct font_mapping *map_font_file( const char *name )
4232 struct font_mapping *mapping;
4233 struct stat st;
4234 int fd;
4236 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
4237 if (fstat( fd, &st ) == -1) goto error;
4239 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
4241 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
4243 mapping->refcount++;
4244 close( fd );
4245 return mapping;
4248 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
4249 goto error;
4251 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
4252 close( fd );
4254 if (mapping->data == MAP_FAILED)
4256 HeapFree( GetProcessHeap(), 0, mapping );
4257 return NULL;
4259 mapping->refcount = 1;
4260 mapping->dev = st.st_dev;
4261 mapping->ino = st.st_ino;
4262 mapping->size = st.st_size;
4263 list_add_tail( &mappings_list, &mapping->entry );
4264 return mapping;
4266 error:
4267 close( fd );
4268 return NULL;
4271 static void unmap_font_file( struct font_mapping *mapping )
4273 if (!--mapping->refcount)
4275 list_remove( &mapping->entry );
4276 munmap( mapping->data, mapping->size );
4277 HeapFree( GetProcessHeap(), 0, mapping );
4281 static LONG load_VDMX(GdiFont*, LONG);
4283 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
4285 FT_Error err;
4286 FT_Face ft_face;
4287 void *data_ptr;
4288 DWORD data_size;
4290 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
4292 if (face->file)
4294 char *filename = strWtoA( CP_UNIXCP, face->file );
4295 font->mapping = map_font_file( filename );
4296 HeapFree( GetProcessHeap(), 0, filename );
4297 if (!font->mapping)
4299 WARN("failed to map %s\n", debugstr_w(face->file));
4300 return 0;
4302 data_ptr = font->mapping->data;
4303 data_size = font->mapping->size;
4305 else
4307 data_ptr = face->font_data_ptr;
4308 data_size = face->font_data_size;
4311 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
4312 if(err) {
4313 ERR("FT_New_Face rets %d\n", err);
4314 return 0;
4317 /* set it here, as load_VDMX needs it */
4318 font->ft_face = ft_face;
4320 if(FT_IS_SCALABLE(ft_face)) {
4321 /* load the VDMX table if we have one */
4322 font->ppem = load_VDMX(font, height);
4323 if(font->ppem == 0)
4324 font->ppem = calc_ppem_for_height(ft_face, height);
4325 TRACE("height %d => ppem %d\n", height, font->ppem);
4327 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
4328 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
4329 } else {
4330 font->ppem = height;
4331 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
4332 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
4334 return ft_face;
4338 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
4340 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4341 a single face with the requested charset. The idea is to check if
4342 the selected font supports the current ANSI codepage, if it does
4343 return the corresponding charset, else return the first charset */
4345 CHARSETINFO csi;
4346 int acp = GetACP(), i;
4347 DWORD fs0;
4349 *cp = acp;
4350 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
4352 const SYSTEM_LINKS *font_link;
4354 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4355 return csi.ciCharset;
4357 font_link = find_font_link(family_name);
4358 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4359 return csi.ciCharset;
4362 for(i = 0; i < 32; i++) {
4363 fs0 = 1L << i;
4364 if(face->fs.fsCsb[0] & fs0) {
4365 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4366 *cp = csi.ciACP;
4367 return csi.ciCharset;
4369 else
4370 FIXME("TCI failing on %x\n", fs0);
4374 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4375 face->fs.fsCsb[0], debugstr_w(face->file));
4376 *cp = acp;
4377 return DEFAULT_CHARSET;
4380 static GdiFont *alloc_font(void)
4382 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4383 ret->refcount = 1;
4384 ret->gmsize = 1;
4385 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4386 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4387 ret->potm = NULL;
4388 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4389 ret->total_kern_pairs = (DWORD)-1;
4390 ret->kern_pairs = NULL;
4391 list_init(&ret->child_fonts);
4392 return ret;
4395 static void free_font(GdiFont *font)
4397 CHILD_FONT *child, *child_next;
4398 DWORD i;
4400 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
4402 list_remove(&child->entry);
4403 if(child->font)
4404 free_font(child->font);
4405 release_face( child->face );
4406 HeapFree(GetProcessHeap(), 0, child);
4409 if (font->ft_face) pFT_Done_Face(font->ft_face);
4410 if (font->mapping) unmap_font_file( font->mapping );
4411 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4412 HeapFree(GetProcessHeap(), 0, font->potm);
4413 HeapFree(GetProcessHeap(), 0, font->name);
4414 for (i = 0; i < font->gmsize; i++)
4415 HeapFree(GetProcessHeap(),0,font->gm[i]);
4416 HeapFree(GetProcessHeap(), 0, font->gm);
4417 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4418 HeapFree(GetProcessHeap(), 0, font);
4422 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4424 FT_Face ft_face = font->ft_face;
4425 FT_ULong len;
4426 FT_Error err;
4428 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4430 if(!buf)
4431 len = 0;
4432 else
4433 len = cbData;
4435 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4437 /* make sure value of len is the value freetype says it needs */
4438 if (buf && len)
4440 FT_ULong needed = 0;
4441 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4442 if( !err && needed < len) len = needed;
4444 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4445 if (err)
4447 TRACE("Can't find table %c%c%c%c\n",
4448 /* bytes were reversed */
4449 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4450 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4451 return GDI_ERROR;
4453 return len;
4456 /*************************************************************
4457 * load_VDMX
4459 * load the vdmx entry for the specified height
4462 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4463 ( ( (FT_ULong)_x4 << 24 ) | \
4464 ( (FT_ULong)_x3 << 16 ) | \
4465 ( (FT_ULong)_x2 << 8 ) | \
4466 (FT_ULong)_x1 )
4468 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4470 typedef struct {
4471 BYTE bCharSet;
4472 BYTE xRatio;
4473 BYTE yStartRatio;
4474 BYTE yEndRatio;
4475 } Ratios;
4477 typedef struct {
4478 WORD recs;
4479 BYTE startsz;
4480 BYTE endsz;
4481 } VDMX_group;
4483 static LONG load_VDMX(GdiFont *font, LONG height)
4485 WORD hdr[3], tmp;
4486 VDMX_group group;
4487 BYTE devXRatio, devYRatio;
4488 USHORT numRecs, numRatios;
4489 DWORD result, offset = -1;
4490 LONG ppem = 0;
4491 int i;
4493 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
4495 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4496 return ppem;
4498 /* FIXME: need the real device aspect ratio */
4499 devXRatio = 1;
4500 devYRatio = 1;
4502 numRecs = GET_BE_WORD(hdr[1]);
4503 numRatios = GET_BE_WORD(hdr[2]);
4505 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4506 for(i = 0; i < numRatios; i++) {
4507 Ratios ratio;
4509 offset = (3 * 2) + (i * sizeof(Ratios));
4510 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4511 offset = -1;
4513 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4515 if((ratio.xRatio == 0 &&
4516 ratio.yStartRatio == 0 &&
4517 ratio.yEndRatio == 0) ||
4518 (devXRatio == ratio.xRatio &&
4519 devYRatio >= ratio.yStartRatio &&
4520 devYRatio <= ratio.yEndRatio))
4522 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4523 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4524 offset = GET_BE_WORD(tmp);
4525 break;
4529 if(offset == -1) {
4530 FIXME("No suitable ratio found\n");
4531 return ppem;
4534 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4535 USHORT recs;
4536 BYTE startsz, endsz;
4537 WORD *vTable;
4539 recs = GET_BE_WORD(group.recs);
4540 startsz = group.startsz;
4541 endsz = group.endsz;
4543 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4545 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4546 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4547 if(result == GDI_ERROR) {
4548 FIXME("Failed to retrieve vTable\n");
4549 goto end;
4552 if(height > 0) {
4553 for(i = 0; i < recs; i++) {
4554 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4555 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4556 ppem = GET_BE_WORD(vTable[i * 3]);
4558 if(yMax + -yMin == height) {
4559 font->yMax = yMax;
4560 font->yMin = yMin;
4561 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4562 break;
4564 if(yMax + -yMin > height) {
4565 if(--i < 0) {
4566 ppem = 0;
4567 goto end; /* failed */
4569 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4570 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4571 ppem = GET_BE_WORD(vTable[i * 3]);
4572 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4573 break;
4576 if(!font->yMax) {
4577 ppem = 0;
4578 TRACE("ppem not found for height %d\n", height);
4580 } else {
4581 ppem = -height;
4582 if(ppem < startsz || ppem > endsz)
4584 ppem = 0;
4585 goto end;
4588 for(i = 0; i < recs; i++) {
4589 USHORT yPelHeight;
4590 yPelHeight = GET_BE_WORD(vTable[i * 3]);
4592 if(yPelHeight > ppem)
4594 ppem = 0;
4595 break; /* failed */
4598 if(yPelHeight == ppem) {
4599 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4600 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4601 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
4602 break;
4606 end:
4607 HeapFree(GetProcessHeap(), 0, vTable);
4610 return ppem;
4613 static void dump_gdi_font_list(void)
4615 GdiFont *font;
4617 TRACE("---------- Font Cache ----------\n");
4618 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct tagGdiFont, entry )
4619 TRACE("font=%p ref=%u %s %d\n", font, font->refcount,
4620 debugstr_w(font->font_desc.lf.lfFaceName), font->font_desc.lf.lfHeight);
4623 static void grab_font( GdiFont *font )
4625 if (!font->refcount++)
4627 list_remove( &font->unused_entry );
4628 unused_font_count--;
4632 static void release_font( GdiFont *font )
4634 if (!font) return;
4635 if (!--font->refcount)
4637 TRACE( "font %p\n", font );
4639 /* add it to the unused list */
4640 list_add_head( &unused_gdi_font_list, &font->unused_entry );
4641 if (unused_font_count > UNUSED_CACHE_SIZE)
4643 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct tagGdiFont, unused_entry );
4644 TRACE( "freeing %p\n", font );
4645 list_remove( &font->entry );
4646 list_remove( &font->unused_entry );
4647 free_font( font );
4649 else unused_font_count++;
4651 if (TRACE_ON(font)) dump_gdi_font_list();
4655 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4657 if(font->font_desc.hash != fd->hash) return TRUE;
4658 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4659 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4660 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4661 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4664 static void calc_hash(FONT_DESC *pfd)
4666 DWORD hash = 0, *ptr, two_chars;
4667 WORD *pwc;
4668 unsigned int i;
4670 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4671 hash ^= *ptr;
4672 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4673 hash ^= *ptr;
4674 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4675 two_chars = *ptr;
4676 pwc = (WCHAR *)&two_chars;
4677 if(!*pwc) break;
4678 *pwc = toupperW(*pwc);
4679 pwc++;
4680 *pwc = toupperW(*pwc);
4681 hash ^= two_chars;
4682 if(!*pwc) break;
4684 hash ^= !pfd->can_use_bitmap;
4685 pfd->hash = hash;
4686 return;
4689 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4691 GdiFont *ret;
4692 FONT_DESC fd;
4694 fd.lf = *plf;
4695 fd.matrix = *pmat;
4696 fd.can_use_bitmap = can_use_bitmap;
4697 calc_hash(&fd);
4699 /* try the in-use list */
4700 LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
4702 if(fontcmp(ret, &fd)) continue;
4703 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4704 list_remove( &ret->entry );
4705 list_add_head( &gdi_font_list, &ret->entry );
4706 grab_font( ret );
4707 return ret;
4709 return NULL;
4712 static void add_to_cache(GdiFont *font)
4714 static DWORD cache_num = 1;
4716 font->cache_num = cache_num++;
4717 list_add_head(&gdi_font_list, &font->entry);
4718 TRACE( "font %p\n", font );
4721 /*************************************************************
4722 * create_child_font_list
4724 static BOOL create_child_font_list(GdiFont *font)
4726 BOOL ret = FALSE;
4727 SYSTEM_LINKS *font_link;
4728 CHILD_FONT *font_link_entry, *new_child;
4729 FontSubst *psub;
4730 WCHAR* font_name;
4732 psub = get_font_subst(&font_subst_list, font->name, -1);
4733 font_name = psub ? psub->to.name : font->name;
4734 font_link = find_font_link(font_name);
4735 if (font_link != NULL)
4737 TRACE("found entry in system list\n");
4738 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4740 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4741 new_child->face = font_link_entry->face;
4742 new_child->font = NULL;
4743 new_child->face->refcount++;
4744 list_add_tail(&font->child_fonts, &new_child->entry);
4745 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4747 ret = TRUE;
4750 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4751 * Sans Serif. This is how asian windows get default fallbacks for fonts
4753 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4754 font->charset != OEM_CHARSET &&
4755 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4757 font_link = find_font_link(szDefaultFallbackLink);
4758 if (font_link != NULL)
4760 TRACE("found entry in default fallback list\n");
4761 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4763 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4764 new_child->face = font_link_entry->face;
4765 new_child->font = NULL;
4766 new_child->face->refcount++;
4767 list_add_tail(&font->child_fonts, &new_child->entry);
4768 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4770 ret = TRUE;
4774 return ret;
4777 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4779 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4781 if (pFT_Set_Charmap)
4783 FT_Int i;
4784 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4786 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4788 for (i = 0; i < ft_face->num_charmaps; i++)
4790 if (ft_face->charmaps[i]->encoding == encoding)
4792 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4793 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4795 switch (ft_face->charmaps[i]->platform_id)
4797 default:
4798 cmap_def = ft_face->charmaps[i];
4799 break;
4800 case 0: /* Apple Unicode */
4801 cmap0 = ft_face->charmaps[i];
4802 break;
4803 case 1: /* Macintosh */
4804 cmap1 = ft_face->charmaps[i];
4805 break;
4806 case 2: /* ISO */
4807 cmap2 = ft_face->charmaps[i];
4808 break;
4809 case 3: /* Microsoft */
4810 cmap3 = ft_face->charmaps[i];
4811 break;
4815 if (cmap3) /* prefer Microsoft cmap table */
4816 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4817 else if (cmap1)
4818 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4819 else if (cmap2)
4820 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4821 else if (cmap0)
4822 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4823 else if (cmap_def)
4824 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4826 return ft_err == FT_Err_Ok;
4829 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4833 /*************************************************************
4834 * freetype_CreateDC
4836 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4837 LPCWSTR output, const DEVMODEW *devmode )
4839 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4841 if (!physdev) return FALSE;
4842 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4843 return TRUE;
4847 /*************************************************************
4848 * freetype_DeleteDC
4850 static BOOL freetype_DeleteDC( PHYSDEV dev )
4852 struct freetype_physdev *physdev = get_freetype_dev( dev );
4853 release_font( physdev->font );
4854 HeapFree( GetProcessHeap(), 0, physdev );
4855 return TRUE;
4858 static FT_Encoding pick_charmap( FT_Face face, int charset )
4860 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
4861 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
4862 const FT_Encoding *encs = regular_order;
4864 if (charset == SYMBOL_CHARSET) encs = symbol_order;
4866 while (*encs != 0)
4868 if (select_charmap( face, *encs )) break;
4869 encs++;
4871 return *encs;
4874 #define GASP_GRIDFIT 0x01
4875 #define GASP_DOGRAY 0x02
4876 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4878 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
4880 DWORD size;
4881 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
4882 WORD *alloced = NULL, *ptr = buf;
4883 WORD num_recs, version;
4884 BOOL ret = FALSE;
4886 *flags = 0;
4887 size = get_font_data( font, GASP_TAG, 0, NULL, 0 );
4888 if (size == GDI_ERROR) return FALSE;
4889 if (size < 4 * sizeof(WORD)) return FALSE;
4890 if (size > sizeof(buf))
4892 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
4893 if (!ptr) return FALSE;
4896 get_font_data( font, GASP_TAG, 0, ptr, size );
4898 version = GET_BE_WORD( *ptr++ );
4899 num_recs = GET_BE_WORD( *ptr++ );
4901 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
4903 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
4904 goto done;
4907 while (num_recs--)
4909 *flags = GET_BE_WORD( *(ptr + 1) );
4910 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
4911 ptr += 2;
4913 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
4914 ret = TRUE;
4916 done:
4917 HeapFree( GetProcessHeap(), 0, alloced );
4918 return ret;
4921 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4923 const GSUB_ScriptList *script;
4924 const GSUB_Script *deflt = NULL;
4925 int i;
4926 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4928 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4929 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4931 const GSUB_Script *scr;
4932 int offset;
4934 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4935 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4937 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4938 return scr;
4939 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4940 deflt = scr;
4942 return deflt;
4945 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4947 int i;
4948 int offset;
4949 const GSUB_LangSys *Lang;
4951 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4953 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4955 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4956 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4958 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4959 return Lang;
4961 offset = GET_BE_WORD(script->DefaultLangSys);
4962 if (offset)
4964 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4965 return Lang;
4967 return NULL;
4970 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4972 int i;
4973 const GSUB_FeatureList *feature;
4974 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4976 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4977 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4979 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4980 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4982 const GSUB_Feature *feat;
4983 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4984 return feat;
4987 return NULL;
4990 static const char* get_opentype_script(const GdiFont *font)
4993 * I am not sure if this is the correct way to generate our script tag
4996 switch (font->charset)
4998 case ANSI_CHARSET: return "latn";
4999 case BALTIC_CHARSET: return "latn"; /* ?? */
5000 case CHINESEBIG5_CHARSET: return "hani";
5001 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5002 case GB2312_CHARSET: return "hani";
5003 case GREEK_CHARSET: return "grek";
5004 case HANGUL_CHARSET: return "hang";
5005 case RUSSIAN_CHARSET: return "cyrl";
5006 case SHIFTJIS_CHARSET: return "kana";
5007 case TURKISH_CHARSET: return "latn"; /* ?? */
5008 case VIETNAMESE_CHARSET: return "latn";
5009 case JOHAB_CHARSET: return "latn"; /* ?? */
5010 case ARABIC_CHARSET: return "arab";
5011 case HEBREW_CHARSET: return "hebr";
5012 case THAI_CHARSET: return "thai";
5013 default: return "latn";
5017 static const VOID * get_GSUB_vert_feature(const GdiFont *font)
5019 const GSUB_Header *header;
5020 const GSUB_Script *script;
5021 const GSUB_LangSys *language;
5022 const GSUB_Feature *feature;
5024 if (!font->GSUB_Table)
5025 return NULL;
5027 header = font->GSUB_Table;
5029 script = GSUB_get_script_table(header, get_opentype_script(font));
5030 if (!script)
5032 TRACE("Script not found\n");
5033 return NULL;
5035 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5036 if (!language)
5038 TRACE("Language not found\n");
5039 return NULL;
5041 feature = GSUB_get_feature(header, language, "vrt2");
5042 if (!feature)
5043 feature = GSUB_get_feature(header, language, "vert");
5044 if (!feature)
5046 TRACE("vrt2/vert feature not found\n");
5047 return NULL;
5049 return feature;
5052 /*************************************************************
5053 * freetype_SelectFont
5055 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
5057 struct freetype_physdev *physdev = get_freetype_dev( dev );
5058 GdiFont *ret;
5059 Face *face, *best, *best_bitmap;
5060 Family *family, *last_resort_family;
5061 const struct list *face_list;
5062 INT height, width = 0;
5063 unsigned int score = 0, new_score;
5064 signed int diff = 0, newdiff;
5065 BOOL bd, it, can_use_bitmap, want_vertical;
5066 LOGFONTW lf;
5067 CHARSETINFO csi;
5068 FMAT2 dcmat;
5069 FontSubst *psub = NULL;
5070 DC *dc = get_dc_ptr( dev->hdc );
5071 const SYSTEM_LINKS *font_link;
5073 if (!hfont) /* notification that the font has been changed by another driver */
5075 release_font( physdev->font );
5076 physdev->font = NULL;
5077 release_dc_ptr( dc );
5078 return 0;
5081 GetObjectW( hfont, sizeof(lf), &lf );
5082 lf.lfWidth = abs(lf.lfWidth);
5084 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
5086 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
5087 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
5088 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
5089 lf.lfEscapement);
5091 if(dc->GraphicsMode == GM_ADVANCED)
5093 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
5094 /* Try to avoid not necessary glyph transformations */
5095 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
5097 lf.lfHeight *= fabs(dcmat.eM11);
5098 lf.lfWidth *= fabs(dcmat.eM11);
5099 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
5102 else
5104 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
5105 font scaling abilities. */
5106 dcmat.eM11 = dcmat.eM22 = 1.0;
5107 dcmat.eM21 = dcmat.eM12 = 0;
5108 lf.lfOrientation = lf.lfEscapement;
5109 if (dc->vport2WorldValid)
5111 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
5112 lf.lfOrientation = -lf.lfOrientation;
5113 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
5114 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
5118 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
5119 dcmat.eM21, dcmat.eM22);
5121 GDI_CheckNotLock();
5122 EnterCriticalSection( &freetype_cs );
5124 /* check the cache first */
5125 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5126 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
5127 goto done;
5130 TRACE("not in cache\n");
5131 ret = alloc_font();
5133 ret->font_desc.matrix = dcmat;
5134 ret->font_desc.lf = lf;
5135 ret->font_desc.can_use_bitmap = can_use_bitmap;
5136 calc_hash(&ret->font_desc);
5138 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
5139 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
5140 original value lfCharSet. Note this is a special case for
5141 Symbol and doesn't happen at least for "Wingdings*" */
5143 if(!strcmpiW(lf.lfFaceName, SymbolW))
5144 lf.lfCharSet = SYMBOL_CHARSET;
5146 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
5147 switch(lf.lfCharSet) {
5148 case DEFAULT_CHARSET:
5149 csi.fs.fsCsb[0] = 0;
5150 break;
5151 default:
5152 FIXME("Untranslated charset %d\n", lf.lfCharSet);
5153 csi.fs.fsCsb[0] = 0;
5154 break;
5158 family = NULL;
5159 if(lf.lfFaceName[0] != '\0') {
5160 CHILD_FONT *font_link_entry;
5161 LPWSTR FaceName = lf.lfFaceName;
5163 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
5165 if(psub) {
5166 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
5167 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
5168 if (psub->to.charset != -1)
5169 lf.lfCharSet = psub->to.charset;
5172 /* We want a match on name and charset or just name if
5173 charset was DEFAULT_CHARSET. If the latter then
5174 we fixup the returned charset later in get_nearest_charset
5175 where we'll either use the charset of the current ansi codepage
5176 or if that's unavailable the first charset that the font supports.
5178 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5179 if (!strcmpiW(family->FamilyName, FaceName) ||
5180 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
5182 font_link = find_font_link(family->FamilyName);
5183 face_list = get_face_list_from_family(family);
5184 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5185 if (!(face->scalable || can_use_bitmap))
5186 continue;
5187 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5188 goto found;
5189 if (font_link != NULL &&
5190 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5191 goto found;
5192 if (!csi.fs.fsCsb[0])
5193 goto found;
5198 /* Search by full face name. */
5199 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5200 face_list = get_face_list_from_family(family);
5201 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5202 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
5203 (face->scalable || can_use_bitmap))
5205 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5206 goto found_face;
5207 font_link = find_font_link(family->FamilyName);
5208 if (font_link != NULL &&
5209 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5210 goto found_face;
5216 * Try check the SystemLink list first for a replacement font.
5217 * We may find good replacements there.
5219 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
5221 if(!strcmpiW(font_link->font_name, FaceName) ||
5222 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
5224 TRACE("found entry in system list\n");
5225 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5227 const SYSTEM_LINKS *links;
5229 face = font_link_entry->face;
5230 if (!(face->scalable || can_use_bitmap))
5231 continue;
5232 family = face->family;
5233 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5234 goto found;
5235 links = find_font_link(family->FamilyName);
5236 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
5237 goto found;
5243 psub = NULL; /* substitution is no more relevant */
5245 /* If requested charset was DEFAULT_CHARSET then try using charset
5246 corresponding to the current ansi codepage */
5247 if (!csi.fs.fsCsb[0])
5249 INT acp = GetACP();
5250 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
5251 FIXME("TCI failed on codepage %d\n", acp);
5252 csi.fs.fsCsb[0] = 0;
5253 } else
5254 lf.lfCharSet = csi.ciCharset;
5257 want_vertical = (lf.lfFaceName[0] == '@');
5259 /* Face families are in the top 4 bits of lfPitchAndFamily,
5260 so mask with 0xF0 before testing */
5262 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
5263 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
5264 strcpyW(lf.lfFaceName, defFixed);
5265 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
5266 strcpyW(lf.lfFaceName, defSerif);
5267 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
5268 strcpyW(lf.lfFaceName, defSans);
5269 else
5270 strcpyW(lf.lfFaceName, defSans);
5271 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5272 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
5273 font_link = find_font_link(family->FamilyName);
5274 face_list = get_face_list_from_family(family);
5275 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5276 if (!(face->scalable || can_use_bitmap))
5277 continue;
5278 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5279 goto found;
5280 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5281 goto found;
5286 last_resort_family = NULL;
5287 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5288 font_link = find_font_link(family->FamilyName);
5289 face_list = get_face_list_from_family(family);
5290 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5291 if(!(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical &&
5292 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5293 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
5294 if(face->scalable)
5295 goto found;
5296 if(can_use_bitmap && !last_resort_family)
5297 last_resort_family = family;
5302 if(last_resort_family) {
5303 family = last_resort_family;
5304 csi.fs.fsCsb[0] = 0;
5305 goto found;
5308 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5309 face_list = get_face_list_from_family(family);
5310 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5311 if(face->scalable && !(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical) {
5312 csi.fs.fsCsb[0] = 0;
5313 WARN("just using first face for now\n");
5314 goto found;
5316 if(can_use_bitmap && !last_resort_family)
5317 last_resort_family = family;
5320 if(!last_resort_family) {
5321 FIXME("can't find a single appropriate font - bailing\n");
5322 free_font(ret);
5323 ret = NULL;
5324 goto done;
5327 WARN("could only find a bitmap font - this will probably look awful!\n");
5328 family = last_resort_family;
5329 csi.fs.fsCsb[0] = 0;
5331 found:
5332 it = lf.lfItalic ? 1 : 0;
5333 bd = lf.lfWeight > 550 ? 1 : 0;
5335 height = lf.lfHeight;
5337 face = best = best_bitmap = NULL;
5338 font_link = find_font_link(family->FamilyName);
5339 face_list = get_face_list_from_family(family);
5340 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5342 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5343 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
5344 !csi.fs.fsCsb[0])
5346 BOOL italic, bold;
5348 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
5349 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
5350 new_score = (italic ^ it) + (bold ^ bd);
5351 if(!best || new_score <= score)
5353 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5354 italic, bold, it, bd);
5355 score = new_score;
5356 best = face;
5357 if(best->scalable && score == 0) break;
5358 if(!best->scalable)
5360 if(height > 0)
5361 newdiff = height - (signed int)(best->size.height);
5362 else
5363 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
5364 if(!best_bitmap || new_score < score ||
5365 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
5367 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
5368 diff = newdiff;
5369 best_bitmap = best;
5370 if(score == 0 && diff == 0) break;
5376 if(best)
5377 face = best->scalable ? best : best_bitmap;
5378 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
5379 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
5381 found_face:
5382 height = lf.lfHeight;
5384 ret->fs = face->fs;
5386 if(csi.fs.fsCsb[0]) {
5387 ret->charset = lf.lfCharSet;
5388 ret->codepage = csi.ciACP;
5390 else
5391 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
5393 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
5394 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
5396 ret->aveWidth = height ? lf.lfWidth : 0;
5398 if(!face->scalable) {
5399 /* Windows uses integer scaling factors for bitmap fonts */
5400 INT scale, scaled_height;
5401 GdiFont *cachedfont;
5403 /* FIXME: rotation of bitmap fonts is ignored */
5404 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
5405 if (ret->aveWidth)
5406 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
5407 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
5408 dcmat.eM11 = dcmat.eM22 = 1.0;
5409 /* As we changed the matrix, we need to search the cache for the font again,
5410 * otherwise we might explode the cache. */
5411 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5412 TRACE("Found cached font after non-scalable matrix rescale!\n");
5413 free_font( ret );
5414 ret = cachedfont;
5415 goto done;
5417 calc_hash(&ret->font_desc);
5419 if (height != 0) height = diff;
5420 height += face->size.height;
5422 scale = (height + face->size.height - 1) / face->size.height;
5423 scaled_height = scale * face->size.height;
5424 /* Only jump to the next height if the difference <= 25% original height */
5425 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
5426 /* The jump between unscaled and doubled is delayed by 1 */
5427 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
5428 ret->scale_y = scale;
5430 width = face->size.x_ppem >> 6;
5431 height = face->size.y_ppem >> 6;
5433 else
5434 ret->scale_y = 1.0;
5435 TRACE("font scale y: %f\n", ret->scale_y);
5437 ret->ft_face = OpenFontFace(ret, face, width, height);
5439 if (!ret->ft_face)
5441 free_font( ret );
5442 ret = NULL;
5443 goto done;
5446 ret->ntmFlags = face->ntmFlags;
5448 pick_charmap( ret->ft_face, ret->charset );
5450 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
5451 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
5452 ret->underline = lf.lfUnderline ? 0xff : 0;
5453 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
5454 create_child_font_list(ret);
5456 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
5458 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
5459 if (length != GDI_ERROR)
5461 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
5462 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
5463 TRACE("Loaded GSUB table of %i bytes\n",length);
5464 ret->vert_feature = get_GSUB_vert_feature(ret);
5465 if (!ret->vert_feature)
5467 TRACE("Vertical feature not found\n");
5468 HeapFree(GetProcessHeap(), 0, ret->GSUB_Table);
5469 ret->GSUB_Table = NULL;
5473 ret->aa_flags = HIWORD( face->flags );
5475 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
5477 add_to_cache(ret);
5478 done:
5479 if (ret)
5481 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
5483 switch (lf.lfQuality)
5485 case NONANTIALIASED_QUALITY:
5486 case ANTIALIASED_QUALITY:
5487 next->funcs->pSelectFont( dev, hfont, aa_flags );
5488 break;
5489 case CLEARTYPE_QUALITY:
5490 case CLEARTYPE_NATURAL_QUALITY:
5491 default:
5492 if (!*aa_flags) *aa_flags = ret->aa_flags;
5493 next->funcs->pSelectFont( dev, hfont, aa_flags );
5495 /* fixup the antialiasing flags for that font */
5496 switch (*aa_flags)
5498 case WINE_GGO_HRGB_BITMAP:
5499 case WINE_GGO_HBGR_BITMAP:
5500 case WINE_GGO_VRGB_BITMAP:
5501 case WINE_GGO_VBGR_BITMAP:
5502 if (is_subpixel_rendering_enabled()) break;
5503 *aa_flags = GGO_GRAY4_BITMAP;
5504 /* fall through */
5505 case GGO_GRAY2_BITMAP:
5506 case GGO_GRAY4_BITMAP:
5507 case GGO_GRAY8_BITMAP:
5508 case WINE_GGO_GRAY16_BITMAP:
5509 if (is_hinting_enabled())
5511 WORD gasp_flags;
5512 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
5514 TRACE( "font %s %d aa disabled by GASP\n",
5515 debugstr_w(lf.lfFaceName), lf.lfHeight );
5516 *aa_flags = GGO_BITMAP;
5521 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5522 release_font( physdev->font );
5523 physdev->font = ret;
5525 LeaveCriticalSection( &freetype_cs );
5526 release_dc_ptr( dc );
5527 return ret ? hfont : 0;
5530 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5532 HRSRC rsrc;
5533 HGLOBAL hMem;
5534 WCHAR *p;
5535 int i;
5537 id += IDS_FIRST_SCRIPT;
5538 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5539 if (!rsrc) return 0;
5540 hMem = LoadResource( gdi32_module, rsrc );
5541 if (!hMem) return 0;
5543 p = LockResource( hMem );
5544 id &= 0x000f;
5545 while (id--) p += *p + 1;
5547 i = min(LF_FACESIZE - 1, *p);
5548 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5549 buffer[i] = 0;
5550 return i;
5554 /***************************************************
5555 * create_enum_charset_list
5557 * This function creates charset enumeration list because in DEFAULT_CHARSET
5558 * case, the ANSI codepage's charset takes precedence over other charsets.
5559 * This function works as a filter other than DEFAULT_CHARSET case.
5561 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5563 CHARSETINFO csi;
5564 DWORD n = 0;
5566 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5567 csi.fs.fsCsb[0] != 0) {
5568 list->element[n].mask = csi.fs.fsCsb[0];
5569 list->element[n].charset = csi.ciCharset;
5570 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5571 n++;
5573 else { /* charset is DEFAULT_CHARSET or invalid. */
5574 INT acp, i;
5575 DWORD mask = 0;
5577 /* Set the current codepage's charset as the first element. */
5578 acp = GetACP();
5579 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5580 csi.fs.fsCsb[0] != 0) {
5581 list->element[n].mask = csi.fs.fsCsb[0];
5582 list->element[n].charset = csi.ciCharset;
5583 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5584 mask |= csi.fs.fsCsb[0];
5585 n++;
5588 /* Fill out left elements. */
5589 for (i = 0; i < 32; i++) {
5590 FONTSIGNATURE fs;
5591 fs.fsCsb[0] = 1L << i;
5592 fs.fsCsb[1] = 0;
5593 if (fs.fsCsb[0] & mask)
5594 continue; /* skip, already added. */
5595 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5596 continue; /* skip, this is an invalid fsCsb bit. */
5598 list->element[n].mask = fs.fsCsb[0];
5599 list->element[n].charset = csi.ciCharset;
5600 load_script_name( i, list->element[n].name );
5601 mask |= fs.fsCsb[0];
5602 n++;
5605 /* add catch all mask for remaining bits */
5606 if (~mask)
5608 list->element[n].mask = ~mask;
5609 list->element[n].charset = DEFAULT_CHARSET;
5610 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5611 n++;
5614 list->total = n;
5616 return n;
5619 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
5620 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5622 GdiFont *font;
5623 LONG width, height;
5625 if (face->cached_enum_data)
5627 TRACE("Cached\n");
5628 *pelf = face->cached_enum_data->elf;
5629 *pntm = face->cached_enum_data->ntm;
5630 *ptype = face->cached_enum_data->type;
5631 return;
5634 font = alloc_font();
5636 if(face->scalable) {
5637 height = 100;
5638 width = 0;
5639 } else {
5640 height = face->size.y_ppem >> 6;
5641 width = face->size.x_ppem >> 6;
5643 font->scale_y = 1.0;
5645 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5647 free_font(font);
5648 return;
5651 font->name = strdupW( family_name );
5652 font->ntmFlags = face->ntmFlags;
5654 if (get_outline_text_metrics(font))
5656 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5658 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5659 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5660 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5662 lstrcpynW(pelf->elfLogFont.lfFaceName,
5663 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5664 LF_FACESIZE);
5665 lstrcpynW(pelf->elfFullName,
5666 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5667 LF_FULLFACESIZE);
5668 lstrcpynW(pelf->elfStyle,
5669 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5670 LF_FACESIZE);
5672 else
5674 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5676 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5677 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5678 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5680 lstrcpynW(pelf->elfLogFont.lfFaceName, family_name, LF_FACESIZE);
5681 if (face->FullName)
5682 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5683 else
5684 lstrcpynW(pelf->elfFullName, family_name, LF_FULLFACESIZE);
5685 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5688 pntm->ntmTm.ntmFlags = face->ntmFlags;
5689 pntm->ntmFontSig = face->fs;
5691 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5693 pelf->elfLogFont.lfEscapement = 0;
5694 pelf->elfLogFont.lfOrientation = 0;
5695 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5696 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5697 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5698 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5699 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5700 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5701 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5702 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5703 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5704 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5705 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5707 *ptype = 0;
5708 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5709 *ptype |= TRUETYPE_FONTTYPE;
5710 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5711 *ptype |= DEVICE_FONTTYPE;
5712 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5713 *ptype |= RASTER_FONTTYPE;
5715 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5716 if (face->cached_enum_data)
5718 face->cached_enum_data->elf = *pelf;
5719 face->cached_enum_data->ntm = *pntm;
5720 face->cached_enum_data->type = *ptype;
5723 free_font(font);
5726 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5728 Face *face;
5729 const struct list *face_list;
5731 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5733 face_list = get_face_list_from_family(family);
5734 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5735 if (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName)) return TRUE;
5737 return FALSE;
5740 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5742 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5744 return (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName));
5747 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5748 FONTENUMPROCW proc, LPARAM lparam)
5750 ENUMLOGFONTEXW elf;
5751 NEWTEXTMETRICEXW ntm;
5752 DWORD type = 0;
5753 DWORD i;
5755 GetEnumStructs(face, face->family->FamilyName, &elf, &ntm, &type);
5756 for(i = 0; i < list->total; i++) {
5757 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5758 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5759 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
5760 i = list->total; /* break out of loop after enumeration */
5762 else
5764 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
5765 /* use the DEFAULT_CHARSET case only if no other charset is present */
5766 if (list->element[i].charset == DEFAULT_CHARSET &&
5767 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
5768 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5769 strcpyW(elf.elfScript, list->element[i].name);
5770 if (!elf.elfScript[0])
5771 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5773 /* Font Replacement */
5774 if (family != face->family)
5776 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5777 if (face->FullName)
5778 strcpyW(elf.elfFullName, face->FullName);
5779 else
5780 strcpyW(elf.elfFullName, family->FamilyName);
5782 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5783 debugstr_w(elf.elfLogFont.lfFaceName),
5784 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5785 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5786 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5787 ntm.ntmTm.ntmFlags);
5788 /* release section before callback (FIXME) */
5789 LeaveCriticalSection( &freetype_cs );
5790 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5791 EnterCriticalSection( &freetype_cs );
5793 return TRUE;
5796 /*************************************************************
5797 * freetype_EnumFonts
5799 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5801 Family *family;
5802 Face *face;
5803 const struct list *face_list;
5804 LOGFONTW lf;
5805 struct enum_charset_list enum_charsets;
5807 if (!plf)
5809 lf.lfCharSet = DEFAULT_CHARSET;
5810 lf.lfPitchAndFamily = 0;
5811 lf.lfFaceName[0] = 0;
5812 plf = &lf;
5815 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5817 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5819 GDI_CheckNotLock();
5820 EnterCriticalSection( &freetype_cs );
5821 if(plf->lfFaceName[0]) {
5822 FontSubst *psub;
5823 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5825 if(psub) {
5826 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5827 debugstr_w(psub->to.name));
5828 lf = *plf;
5829 strcpyW(lf.lfFaceName, psub->to.name);
5830 plf = &lf;
5833 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5834 if (!family_matches(family, plf)) continue;
5835 face_list = get_face_list_from_family(family);
5836 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5837 if (!face_matches(family->FamilyName, face, plf)) continue;
5838 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5841 } else {
5842 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5843 face_list = get_face_list_from_family(family);
5844 face = LIST_ENTRY(list_head(face_list), Face, entry);
5845 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5848 LeaveCriticalSection( &freetype_cs );
5849 return TRUE;
5852 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5854 pt->x.value = vec->x >> 6;
5855 pt->x.fract = (vec->x & 0x3f) << 10;
5856 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5857 pt->y.value = vec->y >> 6;
5858 pt->y.fract = (vec->y & 0x3f) << 10;
5859 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5860 return;
5863 /***************************************************
5864 * According to the MSDN documentation on WideCharToMultiByte,
5865 * certain codepages cannot set the default_used parameter.
5866 * This returns TRUE if the codepage can set that parameter, false else
5867 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5869 static BOOL codepage_sets_default_used(UINT codepage)
5871 switch (codepage)
5873 case CP_UTF7:
5874 case CP_UTF8:
5875 case CP_SYMBOL:
5876 return FALSE;
5877 default:
5878 return TRUE;
5883 * GSUB Table handling functions
5886 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5888 const GSUB_CoverageFormat1* cf1;
5890 cf1 = table;
5892 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5894 int count = GET_BE_WORD(cf1->GlyphCount);
5895 int i;
5896 TRACE("Coverage Format 1, %i glyphs\n",count);
5897 for (i = 0; i < count; i++)
5898 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5899 return i;
5900 return -1;
5902 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5904 const GSUB_CoverageFormat2* cf2;
5905 int i;
5906 int count;
5907 cf2 = (const GSUB_CoverageFormat2*)cf1;
5909 count = GET_BE_WORD(cf2->RangeCount);
5910 TRACE("Coverage Format 2, %i ranges\n",count);
5911 for (i = 0; i < count; i++)
5913 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5914 return -1;
5915 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5916 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5918 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5919 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5922 return -1;
5924 else
5925 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5927 return -1;
5930 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5932 int i;
5933 int offset;
5934 const GSUB_LookupList *lookup;
5935 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5937 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5938 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5940 const GSUB_LookupTable *look;
5941 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5942 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5943 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5944 if (GET_BE_WORD(look->LookupType) != 1)
5945 FIXME("We only handle SubType 1\n");
5946 else
5948 int j;
5950 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5952 const GSUB_SingleSubstFormat1 *ssf1;
5953 offset = GET_BE_WORD(look->SubTable[j]);
5954 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5955 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5957 int offset = GET_BE_WORD(ssf1->Coverage);
5958 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5959 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5961 TRACE(" Glyph 0x%x ->",glyph);
5962 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5963 TRACE(" 0x%x\n",glyph);
5966 else
5968 const GSUB_SingleSubstFormat2 *ssf2;
5969 INT index;
5970 INT offset;
5972 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5973 offset = GET_BE_WORD(ssf1->Coverage);
5974 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5975 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5976 TRACE(" Coverage index %i\n",index);
5977 if (index != -1)
5979 TRACE(" Glyph is 0x%x ->",glyph);
5980 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5981 TRACE("0x%x\n",glyph);
5987 return glyph;
5991 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5993 const GSUB_Header *header;
5994 const GSUB_Feature *feature;
5996 if (!font->GSUB_Table)
5997 return glyph;
5999 header = font->GSUB_Table;
6000 feature = font->vert_feature;
6002 return GSUB_apply_feature(header, feature, glyph);
6005 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
6007 FT_UInt glyphId;
6009 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
6010 WCHAR wc = (WCHAR)glyph;
6011 BOOL default_used;
6012 BOOL *default_used_pointer;
6013 FT_UInt ret;
6014 char buf;
6015 default_used_pointer = NULL;
6016 default_used = FALSE;
6017 if (codepage_sets_default_used(font->codepage))
6018 default_used_pointer = &default_used;
6019 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
6021 if (font->codepage == CP_SYMBOL && wc < 0x100)
6022 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
6023 else
6024 ret = 0;
6026 else
6027 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
6028 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
6029 return ret;
6032 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
6034 if (glyph < 0x100) glyph += 0xf000;
6035 /* there is a number of old pre-Unicode "broken" TTFs, which
6036 do have symbols at U+00XX instead of U+f0XX */
6037 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
6038 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
6040 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
6042 return glyphId;
6045 static FT_UInt get_default_char_index(GdiFont *font)
6047 FT_UInt default_char;
6049 if (FT_IS_SFNT(font->ft_face))
6051 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
6052 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
6054 else
6056 TEXTMETRICW textm;
6057 get_text_metrics(font, &textm);
6058 default_char = textm.tmDefaultChar;
6061 return default_char;
6064 /*************************************************************
6065 * freetype_GetGlyphIndices
6067 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
6069 struct freetype_physdev *physdev = get_freetype_dev( dev );
6070 int i;
6071 WORD default_char;
6072 BOOL got_default = FALSE;
6074 if (!physdev->font)
6076 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
6077 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
6080 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
6082 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
6083 got_default = TRUE;
6086 GDI_CheckNotLock();
6087 EnterCriticalSection( &freetype_cs );
6089 for(i = 0; i < count; i++)
6091 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
6092 if (pgi[i] == 0)
6094 if (!got_default)
6096 default_char = get_default_char_index(physdev->font);
6097 got_default = TRUE;
6099 pgi[i] = default_char;
6101 else
6102 pgi[i] = get_GSUB_vert_glyph(physdev->font, pgi[i]);
6104 LeaveCriticalSection( &freetype_cs );
6105 return count;
6108 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
6110 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
6111 return !memcmp(matrix, &identity, sizeof(FMAT2));
6114 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
6116 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
6117 return !memcmp(matrix, &identity, sizeof(MAT2));
6120 static inline BYTE get_max_level( UINT format )
6122 switch( format )
6124 case GGO_GRAY2_BITMAP: return 4;
6125 case GGO_GRAY4_BITMAP: return 16;
6126 case GGO_GRAY8_BITMAP: return 64;
6128 return 255;
6131 static const struct { WCHAR lower; WCHAR upper;} unrotate_ranges[] =
6133 {0x0000, 0x10FF},
6134 /* Hangul Jamo */
6135 {0x1200, 0x17FF},
6136 /* Mongolian */
6137 {0x18B0, 0x1FFF},
6138 /* General Punctuation */
6139 {0x2070, 0x209F},
6140 /* Currency Symbols */
6141 /* Combining Diacritical Marks for Symbols */
6142 /* Letterlike Symbols */
6143 {0x2150, 0x245F},
6144 /* Enclosed Alphanumerics */
6145 {0x2500, 0x259F},
6146 /* Geometric Shapes */
6147 /* Miscellaneous Symbols */
6148 /* Dingbats */
6149 /* Miscellaneous Mathematical Symbols-A */
6150 /* Supplemental Arrows-A */
6151 {0x2800, 0x2E7F},
6152 /* East Asian scripts and symbols */
6153 {0xA000, 0xABFF},
6154 /* Hangul Syllables */
6155 /* Hangul Jamo Extended-B */
6156 {0xD800, 0xF8FF},
6157 /* CJK Compatibility Ideographs */
6158 {0xFB00, 0xFE0F},
6159 /* Vertical Forms */
6160 /* Combining Half Marks */
6161 /* CJK Compatibility Forms */
6162 {0xFE50, 0xFEFF},
6163 /* Halfwidth and Fullwidth Forms */
6164 {0xFFEF, 0xFFFF},
6167 static BOOL check_unicode_tategaki(WCHAR uchar)
6169 int i;
6170 for (i = 0 ;; i++)
6172 if (uchar < unrotate_ranges[i].lower)
6173 return TRUE;
6175 if (uchar >= unrotate_ranges[i].lower && uchar <= unrotate_ranges[i].upper)
6176 return FALSE;
6180 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6182 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
6183 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
6184 const MAT2* lpmat)
6186 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
6187 FT_Face ft_face = incoming_font->ft_face;
6188 GdiFont *font = incoming_font;
6189 FT_Glyph_Metrics metrics;
6190 FT_UInt glyph_index;
6191 DWORD width, height, pitch, needed = 0;
6192 FT_Bitmap ft_bitmap;
6193 FT_Error err;
6194 INT left, right, top = 0, bottom = 0, adv;
6195 INT origin_x = 0, origin_y = 0;
6196 FT_Angle angle = 0;
6197 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
6198 double widthRatio = 1.0;
6199 FT_Matrix transMat = identityMat;
6200 FT_Matrix transMatUnrotated;
6201 FT_Matrix transMatTategaki;
6202 BOOL needsTransform = FALSE;
6203 BOOL tategaki = (font->name[0] == '@');
6204 BOOL vertical_metrics;
6205 UINT original_index;
6206 LONG avgAdvance = 0;
6207 FT_Fixed em_scale;
6209 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
6210 buflen, buf, lpmat);
6212 TRACE("font transform %f %f %f %f\n",
6213 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
6214 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
6216 if(format & GGO_GLYPH_INDEX) {
6217 glyph_index = glyph;
6218 original_index = glyph;
6219 format &= ~GGO_GLYPH_INDEX;
6220 /* TODO: Window also turns off tategaki for glyphs passed in by index
6221 if their unicode code points fall outside of the range that is
6222 rotated. */
6223 } else {
6224 BOOL vert;
6225 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index, &vert);
6226 ft_face = font->ft_face;
6227 original_index = glyph_index;
6228 /* We know what unicode ranges get rotated */
6229 if (!vert && tategaki)
6230 tategaki = check_unicode_tategaki(glyph);
6233 if(format & GGO_UNHINTED) {
6234 load_flags |= FT_LOAD_NO_HINTING;
6235 format &= ~GGO_UNHINTED;
6238 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
6239 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
6240 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
6241 font->gmsize * sizeof(GM*));
6242 } else {
6243 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
6244 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
6246 *lpgm = FONT_GM(font,original_index)->gm;
6247 *abc = FONT_GM(font,original_index)->abc;
6248 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6249 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6250 lpgm->gmCellIncX, lpgm->gmCellIncY);
6251 return 1; /* FIXME */
6255 if (!font->gm[original_index / GM_BLOCK_SIZE])
6256 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
6258 /* Scaling factor */
6259 if (font->aveWidth)
6261 TEXTMETRICW tm;
6263 get_text_metrics(font, &tm);
6265 widthRatio = (double)font->aveWidth;
6266 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6268 else
6269 widthRatio = font->scale_y;
6271 /* Scaling transform */
6272 if (widthRatio != 1.0 || font->scale_y != 1.0)
6274 FT_Matrix scaleMat;
6275 scaleMat.xx = FT_FixedFromFloat(widthRatio);
6276 scaleMat.xy = 0;
6277 scaleMat.yx = 0;
6278 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
6280 pFT_Matrix_Multiply(&scaleMat, &transMat);
6281 needsTransform = TRUE;
6284 /* Slant transform */
6285 if (font->fake_italic) {
6286 FT_Matrix slantMat;
6288 slantMat.xx = (1 << 16);
6289 slantMat.xy = ((1 << 16) >> 2);
6290 slantMat.yx = 0;
6291 slantMat.yy = (1 << 16);
6292 pFT_Matrix_Multiply(&slantMat, &transMat);
6293 needsTransform = TRUE;
6296 /* Rotation transform */
6297 transMatUnrotated = transMat;
6298 transMatTategaki = transMat;
6299 if(font->orientation || tategaki) {
6300 FT_Matrix rotationMat;
6301 FT_Matrix taterotationMat;
6302 FT_Vector vecAngle;
6304 double orient = font->orientation / 10.0;
6305 double tate_orient = 0.f;
6307 if (tategaki)
6308 tate_orient = ((font->orientation+900)%3600)/10.0;
6309 else
6310 tate_orient = font->orientation/10.0;
6312 if (orient)
6314 angle = FT_FixedFromFloat(orient);
6315 pFT_Vector_Unit(&vecAngle, angle);
6316 rotationMat.xx = vecAngle.x;
6317 rotationMat.xy = -vecAngle.y;
6318 rotationMat.yx = -rotationMat.xy;
6319 rotationMat.yy = rotationMat.xx;
6321 pFT_Matrix_Multiply(&rotationMat, &transMat);
6324 if (tate_orient)
6326 angle = FT_FixedFromFloat(tate_orient);
6327 pFT_Vector_Unit(&vecAngle, angle);
6328 taterotationMat.xx = vecAngle.x;
6329 taterotationMat.xy = -vecAngle.y;
6330 taterotationMat.yx = -taterotationMat.xy;
6331 taterotationMat.yy = taterotationMat.xx;
6332 pFT_Matrix_Multiply(&taterotationMat, &transMatTategaki);
6335 needsTransform = TRUE;
6338 /* World transform */
6339 if (!is_identity_FMAT2(&font->font_desc.matrix))
6341 FT_Matrix worldMat;
6342 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
6343 worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21);
6344 worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12);
6345 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
6346 pFT_Matrix_Multiply(&worldMat, &transMat);
6347 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
6348 pFT_Matrix_Multiply(&worldMat, &transMatTategaki);
6349 needsTransform = TRUE;
6352 /* Extra transformation specified by caller */
6353 if (!is_identity_MAT2(lpmat))
6355 FT_Matrix extraMat;
6356 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
6357 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
6358 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
6359 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
6360 pFT_Matrix_Multiply(&extraMat, &transMat);
6361 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
6362 pFT_Matrix_Multiply(&extraMat, &transMatTategaki);
6363 needsTransform = TRUE;
6366 vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face));
6367 /* there is a freetype bug where vertical metrics are only
6368 properly scaled and correct in 2.4.0 or greater */
6369 if ((vertical_metrics) && (FT_Version.major < 2 || (FT_Version.major == 2 && FT_Version.minor < 4)))
6370 vertical_metrics = FALSE;
6372 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
6373 if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
6375 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
6377 if(err) {
6378 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
6379 return GDI_ERROR;
6382 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6383 * by the text metrics. The proper behavior is to clip the glyph metrics to
6384 * fit within the maximums specified in the text metrics. */
6385 metrics = ft_face->glyph->metrics;
6386 if(incoming_font->potm || get_outline_text_metrics(incoming_font) ||
6387 get_bitmap_text_metrics(incoming_font)) {
6388 TEXTMETRICW *ptm = &incoming_font->potm->otmTextMetrics;
6389 top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
6390 bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
6391 metrics.horiBearingY = top;
6392 metrics.height = top - bottom;
6394 /* TODO: Are we supposed to clip the width as well...? */
6395 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6398 if(FT_IS_SCALABLE(incoming_font->ft_face)) {
6399 TEXTMETRICW tm;
6400 if (get_text_metrics(incoming_font, &tm) &&
6401 !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
6402 em_scale = MulDiv(incoming_font->ppem, 1 << 16, incoming_font->ft_face->units_per_EM);
6403 avgAdvance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
6404 if (avgAdvance &&
6405 (metrics.horiAdvance+63) >> 6 == pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale))
6406 TRACE("Fixed-pitch full-width character detected\n");
6407 else
6408 avgAdvance = 0; /* cancel this feature */
6412 if(!needsTransform) {
6413 left = (INT)(metrics.horiBearingX) & -64;
6414 right = (INT)((metrics.horiBearingX + metrics.width) + 63) & -64;
6415 if (!avgAdvance)
6416 adv = (INT)(metrics.horiAdvance + 63) >> 6;
6417 else
6418 adv = (INT)avgAdvance * 2;
6420 top = (metrics.horiBearingY + 63) & -64;
6421 bottom = (metrics.horiBearingY - metrics.height) & -64;
6422 lpgm->gmCellIncX = adv;
6423 lpgm->gmCellIncY = 0;
6424 origin_x = left;
6425 origin_y = top;
6426 } else {
6427 INT xc, yc;
6428 FT_Vector vec;
6430 left = right = 0;
6432 for(xc = 0; xc < 2; xc++) {
6433 for(yc = 0; yc < 2; yc++) {
6434 vec.x = metrics.horiBearingX + xc * metrics.width;
6435 vec.y = metrics.horiBearingY - yc * metrics.height;
6436 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
6437 pFT_Vector_Transform(&vec, &transMatTategaki);
6438 if(xc == 0 && yc == 0) {
6439 left = right = vec.x;
6440 top = bottom = vec.y;
6441 } else {
6442 if(vec.x < left) left = vec.x;
6443 else if(vec.x > right) right = vec.x;
6444 if(vec.y < bottom) bottom = vec.y;
6445 else if(vec.y > top) top = vec.y;
6449 left = left & -64;
6450 right = (right + 63) & -64;
6451 bottom = bottom & -64;
6452 top = (top + 63) & -64;
6454 if (tategaki)
6456 for(xc = 0; xc < 2; xc++)
6458 for(yc = 0; yc < 2; yc++)
6460 if (vertical_metrics)
6462 vec.x = metrics.vertBearingY + xc * metrics.height;
6463 vec.y = metrics.horiBearingX - yc * (metrics.vertBearingX * 2);
6465 else
6467 vec.x = metrics.horiBearingY - xc * metrics.height;
6468 vec.y = metrics.horiBearingX + yc * metrics.width;
6471 TRACE ("Vec %ld,%ld\n", vec.x>>6, vec.y>>6);
6472 pFT_Vector_Transform(&vec, &transMat);
6473 if(xc == 0 && yc == 0) {
6474 origin_x = vec.x;
6475 origin_y = vec.y;
6476 } else {
6477 if(vec.x < origin_x) origin_x = vec.x;
6478 if(vec.y > origin_y) origin_y = vec.y;
6482 origin_x = origin_x & -64;
6483 origin_y = (origin_y + 63) & -64;
6485 else
6487 origin_x = left;
6488 origin_y = top;
6491 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
6492 vec.x = metrics.horiAdvance;
6493 vec.y = 0;
6494 pFT_Vector_Transform(&vec, &transMat);
6495 lpgm->gmCellIncY = -((vec.y+63) >> 6);
6496 if (!avgAdvance || vec.y)
6497 lpgm->gmCellIncX = (vec.x+63) >> 6;
6498 else {
6499 vec.x = incoming_font->ntmAvgWidth;
6500 vec.y = 0;
6501 pFT_Vector_Transform(&vec, &transMat);
6502 lpgm->gmCellIncX = pFT_MulFix(vec.x, em_scale) * 2;
6505 if (vertical_metrics)
6506 vec.x = metrics.vertAdvance;
6507 else
6508 vec.x = metrics.horiAdvance;
6509 vec.y = 0;
6510 pFT_Vector_Transform(&vec, &transMatUnrotated);
6511 if (!avgAdvance || vec.y)
6512 adv = (vec.x+63) >> 6;
6513 else {
6514 vec.x = incoming_font->ntmAvgWidth;
6515 vec.y = 0;
6516 pFT_Vector_Transform(&vec, &transMatUnrotated);
6517 adv = pFT_MulFix(vec.x, em_scale) * 2;
6521 lpgm->gmBlackBoxX = (right - left) >> 6;
6522 lpgm->gmBlackBoxY = (top - bottom) >> 6;
6523 lpgm->gmptGlyphOrigin.x = origin_x >> 6;
6524 lpgm->gmptGlyphOrigin.y = origin_y >> 6;
6525 abc->abcA = left >> 6;
6526 abc->abcB = (right - left) >> 6;
6527 abc->abcC = adv - abc->abcA - abc->abcB;
6529 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6530 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6531 lpgm->gmCellIncX, lpgm->gmCellIncY);
6533 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
6534 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
6536 FONT_GM(font,original_index)->gm = *lpgm;
6537 FONT_GM(font,original_index)->abc = *abc;
6538 FONT_GM(font,original_index)->init = TRUE;
6541 if(format == GGO_METRICS)
6543 return 1; /* FIXME */
6546 if(ft_face->glyph->format != ft_glyph_format_outline &&
6547 (format == GGO_NATIVE || format == GGO_BEZIER))
6549 TRACE("loaded a bitmap\n");
6550 return GDI_ERROR;
6553 switch(format) {
6554 case GGO_BITMAP:
6555 width = lpgm->gmBlackBoxX;
6556 height = lpgm->gmBlackBoxY;
6557 pitch = ((width + 31) >> 5) << 2;
6558 needed = pitch * height;
6560 if(!buf || !buflen) break;
6562 switch(ft_face->glyph->format) {
6563 case ft_glyph_format_bitmap:
6565 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6566 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
6567 INT h = min( height, ft_face->glyph->bitmap.rows );
6568 while(h--) {
6569 memcpy(dst, src, w);
6570 src += ft_face->glyph->bitmap.pitch;
6571 dst += pitch;
6573 break;
6576 case ft_glyph_format_outline:
6577 ft_bitmap.width = width;
6578 ft_bitmap.rows = height;
6579 ft_bitmap.pitch = pitch;
6580 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
6581 ft_bitmap.buffer = buf;
6583 if(needsTransform)
6584 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
6586 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6588 /* Note: FreeType will only set 'black' bits for us. */
6589 memset(buf, 0, needed);
6590 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6591 break;
6593 default:
6594 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6595 return GDI_ERROR;
6597 break;
6599 case GGO_GRAY2_BITMAP:
6600 case GGO_GRAY4_BITMAP:
6601 case GGO_GRAY8_BITMAP:
6602 case WINE_GGO_GRAY16_BITMAP:
6604 unsigned int max_level, row, col;
6605 BYTE *start, *ptr;
6607 width = lpgm->gmBlackBoxX;
6608 height = lpgm->gmBlackBoxY;
6609 pitch = (width + 3) / 4 * 4;
6610 needed = pitch * height;
6612 if(!buf || !buflen) break;
6614 max_level = get_max_level( format );
6616 switch(ft_face->glyph->format) {
6617 case ft_glyph_format_bitmap:
6619 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6620 INT h = min( height, ft_face->glyph->bitmap.rows );
6621 INT x;
6622 memset( buf, 0, needed );
6623 while(h--) {
6624 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
6625 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
6626 src += ft_face->glyph->bitmap.pitch;
6627 dst += pitch;
6629 return needed;
6631 case ft_glyph_format_outline:
6633 ft_bitmap.width = width;
6634 ft_bitmap.rows = height;
6635 ft_bitmap.pitch = pitch;
6636 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6637 ft_bitmap.buffer = buf;
6639 if(needsTransform)
6640 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
6642 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6644 memset(ft_bitmap.buffer, 0, buflen);
6646 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6648 if (max_level != 255)
6650 for (row = 0, start = buf; row < height; row++)
6652 for (col = 0, ptr = start; col < width; col++, ptr++)
6653 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6654 start += pitch;
6657 return needed;
6660 default:
6661 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6662 return GDI_ERROR;
6664 break;
6667 case WINE_GGO_HRGB_BITMAP:
6668 case WINE_GGO_HBGR_BITMAP:
6669 case WINE_GGO_VRGB_BITMAP:
6670 case WINE_GGO_VBGR_BITMAP:
6671 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6673 switch (ft_face->glyph->format)
6675 case FT_GLYPH_FORMAT_BITMAP:
6677 BYTE *src, *dst;
6678 INT src_pitch, x;
6680 width = lpgm->gmBlackBoxX;
6681 height = lpgm->gmBlackBoxY;
6682 pitch = width * 4;
6683 needed = pitch * height;
6685 if (!buf || !buflen) break;
6687 memset(buf, 0, buflen);
6688 dst = buf;
6689 src = ft_face->glyph->bitmap.buffer;
6690 src_pitch = ft_face->glyph->bitmap.pitch;
6692 height = min( height, ft_face->glyph->bitmap.rows );
6693 while ( height-- )
6695 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6697 if ( src[x / 8] & masks[x % 8] )
6698 ((unsigned int *)dst)[x] = ~0u;
6700 src += src_pitch;
6701 dst += pitch;
6704 break;
6707 case FT_GLYPH_FORMAT_OUTLINE:
6709 unsigned int *dst;
6710 BYTE *src;
6711 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6712 INT x_shift, y_shift;
6713 BOOL rgb;
6714 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6715 FT_Render_Mode render_mode =
6716 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6717 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6719 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6721 if ( render_mode == FT_RENDER_MODE_LCD)
6723 lpgm->gmBlackBoxX += 2;
6724 lpgm->gmptGlyphOrigin.x -= 1;
6726 else
6728 lpgm->gmBlackBoxY += 2;
6729 lpgm->gmptGlyphOrigin.y += 1;
6733 width = lpgm->gmBlackBoxX;
6734 height = lpgm->gmBlackBoxY;
6735 pitch = width * 4;
6736 needed = pitch * height;
6738 if (!buf || !buflen) break;
6740 memset(buf, 0, buflen);
6741 dst = buf;
6742 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6744 if ( needsTransform )
6745 pFT_Outline_Transform (&ft_face->glyph->outline, &transMatTategaki);
6747 if ( pFT_Library_SetLcdFilter )
6748 pFT_Library_SetLcdFilter( library, lcdfilter );
6749 pFT_Render_Glyph (ft_face->glyph, render_mode);
6751 src = ft_face->glyph->bitmap.buffer;
6752 src_pitch = ft_face->glyph->bitmap.pitch;
6753 src_width = ft_face->glyph->bitmap.width;
6754 src_height = ft_face->glyph->bitmap.rows;
6756 if ( render_mode == FT_RENDER_MODE_LCD)
6758 rgb_interval = 1;
6759 hmul = 3;
6760 vmul = 1;
6762 else
6764 rgb_interval = src_pitch;
6765 hmul = 1;
6766 vmul = 3;
6769 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6770 if ( x_shift < 0 )
6772 src += hmul * -x_shift;
6773 src_width -= hmul * -x_shift;
6775 else if ( x_shift > 0 )
6777 dst += x_shift;
6778 width -= x_shift;
6781 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6782 if ( y_shift < 0 )
6784 src += src_pitch * vmul * -y_shift;
6785 src_height -= vmul * -y_shift;
6787 else if ( y_shift > 0 )
6789 dst += y_shift * ( pitch / sizeof(*dst) );
6790 height -= y_shift;
6793 width = min( width, src_width / hmul );
6794 height = min( height, src_height / vmul );
6796 while ( height-- )
6798 for ( x = 0; x < width; x++ )
6800 if ( rgb )
6802 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6803 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6804 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6805 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6807 else
6809 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6810 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6811 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6812 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6815 src += src_pitch * vmul;
6816 dst += pitch / sizeof(*dst);
6819 break;
6822 default:
6823 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6824 return GDI_ERROR;
6827 break;
6829 #else
6830 return GDI_ERROR;
6831 #endif
6833 case GGO_NATIVE:
6835 int contour, point = 0, first_pt;
6836 FT_Outline *outline = &ft_face->glyph->outline;
6837 TTPOLYGONHEADER *pph;
6838 TTPOLYCURVE *ppc;
6839 DWORD pph_start, cpfx, type;
6841 if(buflen == 0) buf = NULL;
6843 if (needsTransform && buf) {
6844 pFT_Outline_Transform(outline, &transMatTategaki);
6847 for(contour = 0; contour < outline->n_contours; contour++) {
6848 /* Ignore contours containing one point */
6849 if(point == outline->contours[contour]) {
6850 point++;
6851 continue;
6854 pph_start = needed;
6855 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6856 first_pt = point;
6857 if(buf) {
6858 pph->dwType = TT_POLYGON_TYPE;
6859 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6861 needed += sizeof(*pph);
6862 point++;
6863 while(point <= outline->contours[contour]) {
6864 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6865 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6866 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6867 cpfx = 0;
6868 do {
6869 if(buf)
6870 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6871 cpfx++;
6872 point++;
6873 } while(point <= outline->contours[contour] &&
6874 (outline->tags[point] & FT_Curve_Tag_On) ==
6875 (outline->tags[point-1] & FT_Curve_Tag_On));
6876 /* At the end of a contour Windows adds the start point, but
6877 only for Beziers */
6878 if(point > outline->contours[contour] &&
6879 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6880 if(buf)
6881 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6882 cpfx++;
6883 } else if(point <= outline->contours[contour] &&
6884 outline->tags[point] & FT_Curve_Tag_On) {
6885 /* add closing pt for bezier */
6886 if(buf)
6887 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6888 cpfx++;
6889 point++;
6891 if(buf) {
6892 ppc->wType = type;
6893 ppc->cpfx = cpfx;
6895 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6897 if(buf)
6898 pph->cb = needed - pph_start;
6900 break;
6902 case GGO_BEZIER:
6904 /* Convert the quadratic Beziers to cubic Beziers.
6905 The parametric eqn for a cubic Bezier is, from PLRM:
6906 r(t) = at^3 + bt^2 + ct + r0
6907 with the control points:
6908 r1 = r0 + c/3
6909 r2 = r1 + (c + b)/3
6910 r3 = r0 + c + b + a
6912 A quadratic Bezier has the form:
6913 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6915 So equating powers of t leads to:
6916 r1 = 2/3 p1 + 1/3 p0
6917 r2 = 2/3 p1 + 1/3 p2
6918 and of course r0 = p0, r3 = p2
6921 int contour, point = 0, first_pt;
6922 FT_Outline *outline = &ft_face->glyph->outline;
6923 TTPOLYGONHEADER *pph;
6924 TTPOLYCURVE *ppc;
6925 DWORD pph_start, cpfx, type;
6926 FT_Vector cubic_control[4];
6927 if(buflen == 0) buf = NULL;
6929 if (needsTransform && buf) {
6930 pFT_Outline_Transform(outline, &transMat);
6933 for(contour = 0; contour < outline->n_contours; contour++) {
6934 pph_start = needed;
6935 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6936 first_pt = point;
6937 if(buf) {
6938 pph->dwType = TT_POLYGON_TYPE;
6939 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6941 needed += sizeof(*pph);
6942 point++;
6943 while(point <= outline->contours[contour]) {
6944 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6945 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6946 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6947 cpfx = 0;
6948 do {
6949 if(type == TT_PRIM_LINE) {
6950 if(buf)
6951 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6952 cpfx++;
6953 point++;
6954 } else {
6955 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6956 so cpfx = 3n */
6958 /* FIXME: Possible optimization in endpoint calculation
6959 if there are two consecutive curves */
6960 cubic_control[0] = outline->points[point-1];
6961 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6962 cubic_control[0].x += outline->points[point].x + 1;
6963 cubic_control[0].y += outline->points[point].y + 1;
6964 cubic_control[0].x >>= 1;
6965 cubic_control[0].y >>= 1;
6967 if(point+1 > outline->contours[contour])
6968 cubic_control[3] = outline->points[first_pt];
6969 else {
6970 cubic_control[3] = outline->points[point+1];
6971 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6972 cubic_control[3].x += outline->points[point].x + 1;
6973 cubic_control[3].y += outline->points[point].y + 1;
6974 cubic_control[3].x >>= 1;
6975 cubic_control[3].y >>= 1;
6978 /* r1 = 1/3 p0 + 2/3 p1
6979 r2 = 1/3 p2 + 2/3 p1 */
6980 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6981 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6982 cubic_control[2] = cubic_control[1];
6983 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6984 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6985 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6986 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6987 if(buf) {
6988 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6989 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6990 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6992 cpfx += 3;
6993 point++;
6995 } while(point <= outline->contours[contour] &&
6996 (outline->tags[point] & FT_Curve_Tag_On) ==
6997 (outline->tags[point-1] & FT_Curve_Tag_On));
6998 /* At the end of a contour Windows adds the start point,
6999 but only for Beziers and we've already done that.
7001 if(point <= outline->contours[contour] &&
7002 outline->tags[point] & FT_Curve_Tag_On) {
7003 /* This is the closing pt of a bezier, but we've already
7004 added it, so just inc point and carry on */
7005 point++;
7007 if(buf) {
7008 ppc->wType = type;
7009 ppc->cpfx = cpfx;
7011 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
7013 if(buf)
7014 pph->cb = needed - pph_start;
7016 break;
7019 default:
7020 FIXME("Unsupported format %d\n", format);
7021 return GDI_ERROR;
7023 return needed;
7026 static BOOL get_bitmap_text_metrics(GdiFont *font)
7028 FT_Face ft_face = font->ft_face;
7029 FT_WinFNT_HeaderRec winfnt_header;
7030 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
7031 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
7032 font->potm->otmSize = size;
7034 #define TM font->potm->otmTextMetrics
7035 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
7037 TM.tmHeight = winfnt_header.pixel_height;
7038 TM.tmAscent = winfnt_header.ascent;
7039 TM.tmDescent = TM.tmHeight - TM.tmAscent;
7040 TM.tmInternalLeading = winfnt_header.internal_leading;
7041 TM.tmExternalLeading = winfnt_header.external_leading;
7042 TM.tmAveCharWidth = winfnt_header.avg_width;
7043 TM.tmMaxCharWidth = winfnt_header.max_width;
7044 TM.tmWeight = winfnt_header.weight;
7045 TM.tmOverhang = 0;
7046 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
7047 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
7048 TM.tmFirstChar = winfnt_header.first_char;
7049 TM.tmLastChar = winfnt_header.last_char;
7050 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
7051 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
7052 TM.tmItalic = winfnt_header.italic;
7053 TM.tmUnderlined = font->underline;
7054 TM.tmStruckOut = font->strikeout;
7055 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
7056 TM.tmCharSet = winfnt_header.charset;
7058 else
7060 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
7061 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
7062 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7063 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
7064 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
7065 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
7066 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
7067 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
7068 TM.tmOverhang = 0;
7069 TM.tmDigitizedAspectX = 96; /* FIXME */
7070 TM.tmDigitizedAspectY = 96; /* FIXME */
7071 TM.tmFirstChar = 1;
7072 TM.tmLastChar = 255;
7073 TM.tmDefaultChar = 32;
7074 TM.tmBreakChar = 32;
7075 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
7076 TM.tmUnderlined = font->underline;
7077 TM.tmStruckOut = font->strikeout;
7078 /* NB inverted meaning of TMPF_FIXED_PITCH */
7079 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
7080 TM.tmCharSet = font->charset;
7082 #undef TM
7084 return TRUE;
7088 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
7090 double scale_x, scale_y;
7092 if (font->aveWidth)
7094 scale_x = (double)font->aveWidth;
7095 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7097 else
7098 scale_x = font->scale_y;
7100 scale_x *= fabs(font->font_desc.matrix.eM11);
7101 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7103 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7104 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7106 SCALE_Y(ptm->tmHeight);
7107 SCALE_Y(ptm->tmAscent);
7108 SCALE_Y(ptm->tmDescent);
7109 SCALE_Y(ptm->tmInternalLeading);
7110 SCALE_Y(ptm->tmExternalLeading);
7111 SCALE_Y(ptm->tmOverhang);
7113 SCALE_X(ptm->tmAveCharWidth);
7114 SCALE_X(ptm->tmMaxCharWidth);
7116 #undef SCALE_X
7117 #undef SCALE_Y
7120 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
7122 double scale_x, scale_y;
7124 if (font->aveWidth)
7126 scale_x = (double)font->aveWidth;
7127 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7129 else
7130 scale_x = font->scale_y;
7132 scale_x *= fabs(font->font_desc.matrix.eM11);
7133 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7135 scale_font_metrics(font, &potm->otmTextMetrics);
7137 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7138 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7140 SCALE_Y(potm->otmAscent);
7141 SCALE_Y(potm->otmDescent);
7142 SCALE_Y(potm->otmLineGap);
7143 SCALE_Y(potm->otmsCapEmHeight);
7144 SCALE_Y(potm->otmsXHeight);
7145 SCALE_Y(potm->otmrcFontBox.top);
7146 SCALE_Y(potm->otmrcFontBox.bottom);
7147 SCALE_X(potm->otmrcFontBox.left);
7148 SCALE_X(potm->otmrcFontBox.right);
7149 SCALE_Y(potm->otmMacAscent);
7150 SCALE_Y(potm->otmMacDescent);
7151 SCALE_Y(potm->otmMacLineGap);
7152 SCALE_X(potm->otmptSubscriptSize.x);
7153 SCALE_Y(potm->otmptSubscriptSize.y);
7154 SCALE_X(potm->otmptSubscriptOffset.x);
7155 SCALE_Y(potm->otmptSubscriptOffset.y);
7156 SCALE_X(potm->otmptSuperscriptSize.x);
7157 SCALE_Y(potm->otmptSuperscriptSize.y);
7158 SCALE_X(potm->otmptSuperscriptOffset.x);
7159 SCALE_Y(potm->otmptSuperscriptOffset.y);
7160 SCALE_Y(potm->otmsStrikeoutSize);
7161 SCALE_Y(potm->otmsStrikeoutPosition);
7162 SCALE_Y(potm->otmsUnderscoreSize);
7163 SCALE_Y(potm->otmsUnderscorePosition);
7165 #undef SCALE_X
7166 #undef SCALE_Y
7169 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
7171 if(!font->potm)
7173 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
7175 /* Make sure that the font has sane width/height ratio */
7176 if (font->aveWidth)
7178 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
7180 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
7181 font->aveWidth = 0;
7185 *ptm = font->potm->otmTextMetrics;
7186 scale_font_metrics(font, ptm);
7187 return TRUE;
7190 static BOOL face_has_symbol_charmap(FT_Face ft_face)
7192 int i;
7194 for(i = 0; i < ft_face->num_charmaps; i++)
7196 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
7197 return TRUE;
7199 return FALSE;
7202 static BOOL get_outline_text_metrics(GdiFont *font)
7204 BOOL ret = FALSE;
7205 FT_Face ft_face = font->ft_face;
7206 UINT needed, lenfam, lensty, lenface, lenfull;
7207 TT_OS2 *pOS2;
7208 TT_HoriHeader *pHori;
7209 TT_Postscript *pPost;
7210 FT_Fixed em_scale;
7211 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
7212 char *cp;
7213 INT ascent, descent;
7215 TRACE("font=%p\n", font);
7217 if(!FT_IS_SCALABLE(ft_face))
7218 return FALSE;
7220 needed = sizeof(*font->potm);
7222 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
7223 family_nameW = strdupW(font->name);
7225 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
7226 if (!style_nameW)
7228 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
7229 style_nameW = towstr( CP_ACP, ft_face->style_name );
7231 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
7233 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
7234 if (!face_nameW)
7236 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
7237 face_nameW = strdupW(font->name);
7239 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
7240 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
7242 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
7243 if (!full_nameW)
7245 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
7246 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
7247 full_nameW = strdupW(fake_nameW);
7249 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
7251 /* These names should be read from the TT name table */
7253 /* length of otmpFamilyName */
7254 needed += lenfam;
7256 /* length of otmpFaceName */
7257 needed += lenface;
7259 /* length of otmpStyleName */
7260 needed += lensty;
7262 /* length of otmpFullName */
7263 needed += lenfull;
7266 em_scale = (FT_Fixed)MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
7268 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
7269 if(!pOS2) {
7270 FIXME("Can't find OS/2 table - not TT font?\n");
7271 goto end;
7274 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
7275 if(!pHori) {
7276 FIXME("Can't find HHEA table - not TT font?\n");
7277 goto end;
7280 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
7282 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",
7283 pOS2->usWinAscent, pOS2->usWinDescent,
7284 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
7285 pOS2->xAvgCharWidth,
7286 ft_face->ascender, ft_face->descender, ft_face->height,
7287 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
7288 ft_face->bbox.yMax, ft_face->bbox.yMin);
7290 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
7291 font->potm->otmSize = needed;
7293 #define TM font->potm->otmTextMetrics
7295 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
7296 ascent = pHori->Ascender;
7297 descent = -pHori->Descender;
7298 } else {
7299 ascent = pOS2->usWinAscent;
7300 descent = pOS2->usWinDescent;
7303 font->ntmCellHeight = ascent + descent;
7304 font->ntmAvgWidth = pOS2->xAvgCharWidth;
7306 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7307 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7309 if(font->yMax) {
7310 TM.tmAscent = font->yMax;
7311 TM.tmDescent = -font->yMin;
7312 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
7313 } else {
7314 TM.tmAscent = SCALE_Y(ascent);
7315 TM.tmDescent = SCALE_Y(descent);
7316 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
7319 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7321 /* MSDN says:
7322 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7324 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
7325 ((ascent + descent) -
7326 (pHori->Ascender - pHori->Descender))));
7328 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
7329 if (TM.tmAveCharWidth == 0) {
7330 TM.tmAveCharWidth = 1;
7332 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
7333 TM.tmWeight = FW_REGULAR;
7334 if (font->fake_bold)
7335 TM.tmWeight = FW_BOLD;
7336 else
7338 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
7340 if (pOS2->usWeightClass > FW_MEDIUM)
7341 TM.tmWeight = pOS2->usWeightClass;
7343 else if (pOS2->usWeightClass <= FW_MEDIUM)
7344 TM.tmWeight = pOS2->usWeightClass;
7346 TM.tmOverhang = 0;
7347 TM.tmDigitizedAspectX = 96; /* FIXME */
7348 TM.tmDigitizedAspectY = 96; /* FIXME */
7349 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7350 * symbol range to 0 - f0ff
7353 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
7355 TM.tmFirstChar = 0;
7356 switch(GetACP())
7358 case 1257: /* Baltic */
7359 TM.tmLastChar = 0xf8fd;
7360 break;
7361 default:
7362 TM.tmLastChar = 0xf0ff;
7364 TM.tmBreakChar = 0x20;
7365 TM.tmDefaultChar = 0x1f;
7367 else
7369 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
7370 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
7372 if(pOS2->usFirstCharIndex <= 1)
7373 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
7374 else if (pOS2->usFirstCharIndex > 0xff)
7375 TM.tmBreakChar = 0x20;
7376 else
7377 TM.tmBreakChar = pOS2->usFirstCharIndex;
7378 TM.tmDefaultChar = TM.tmBreakChar - 1;
7380 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
7381 TM.tmUnderlined = font->underline;
7382 TM.tmStruckOut = font->strikeout;
7384 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7385 if(!FT_IS_FIXED_WIDTH(ft_face) &&
7386 (pOS2->version == 0xFFFFU ||
7387 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
7388 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
7389 else
7390 TM.tmPitchAndFamily = 0;
7392 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
7394 case PAN_FAMILY_SCRIPT:
7395 TM.tmPitchAndFamily |= FF_SCRIPT;
7396 break;
7398 case PAN_FAMILY_DECORATIVE:
7399 TM.tmPitchAndFamily |= FF_DECORATIVE;
7400 break;
7402 case PAN_ANY:
7403 case PAN_NO_FIT:
7404 case PAN_FAMILY_TEXT_DISPLAY:
7405 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
7406 /* which is clearly not what the panose spec says. */
7407 default:
7408 if(TM.tmPitchAndFamily == 0 || /* fixed */
7409 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
7410 TM.tmPitchAndFamily = FF_MODERN;
7411 else
7413 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
7415 case PAN_ANY:
7416 case PAN_NO_FIT:
7417 default:
7418 TM.tmPitchAndFamily |= FF_DONTCARE;
7419 break;
7421 case PAN_SERIF_COVE:
7422 case PAN_SERIF_OBTUSE_COVE:
7423 case PAN_SERIF_SQUARE_COVE:
7424 case PAN_SERIF_OBTUSE_SQUARE_COVE:
7425 case PAN_SERIF_SQUARE:
7426 case PAN_SERIF_THIN:
7427 case PAN_SERIF_BONE:
7428 case PAN_SERIF_EXAGGERATED:
7429 case PAN_SERIF_TRIANGLE:
7430 TM.tmPitchAndFamily |= FF_ROMAN;
7431 break;
7433 case PAN_SERIF_NORMAL_SANS:
7434 case PAN_SERIF_OBTUSE_SANS:
7435 case PAN_SERIF_PERP_SANS:
7436 case PAN_SERIF_FLARED:
7437 case PAN_SERIF_ROUNDED:
7438 TM.tmPitchAndFamily |= FF_SWISS;
7439 break;
7442 break;
7445 if(FT_IS_SCALABLE(ft_face))
7446 TM.tmPitchAndFamily |= TMPF_VECTOR;
7448 if(FT_IS_SFNT(ft_face))
7450 if (font->ntmFlags & NTM_PS_OPENTYPE)
7451 TM.tmPitchAndFamily |= TMPF_DEVICE;
7452 else
7453 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
7456 TM.tmCharSet = font->charset;
7458 font->potm->otmFiller = 0;
7459 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
7460 font->potm->otmfsSelection = pOS2->fsSelection;
7461 font->potm->otmfsType = pOS2->fsType;
7462 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
7463 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
7464 font->potm->otmItalicAngle = 0; /* POST table */
7465 font->potm->otmEMSquare = ft_face->units_per_EM;
7466 font->potm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
7467 font->potm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
7468 font->potm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
7469 font->potm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
7470 font->potm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
7471 font->potm->otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
7472 font->potm->otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
7473 font->potm->otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
7474 font->potm->otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
7475 font->potm->otmMacAscent = TM.tmAscent;
7476 font->potm->otmMacDescent = -TM.tmDescent;
7477 font->potm->otmMacLineGap = font->potm->otmLineGap;
7478 font->potm->otmusMinimumPPEM = 0; /* TT Header */
7479 font->potm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
7480 font->potm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
7481 font->potm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
7482 font->potm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
7483 font->potm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
7484 font->potm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
7485 font->potm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
7486 font->potm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
7487 font->potm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
7488 font->potm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
7489 if(!pPost) {
7490 font->potm->otmsUnderscoreSize = 0;
7491 font->potm->otmsUnderscorePosition = 0;
7492 } else {
7493 font->potm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
7494 font->potm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
7496 #undef SCALE_X
7497 #undef SCALE_Y
7498 #undef TM
7500 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7501 cp = (char*)font->potm + sizeof(*font->potm);
7502 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
7503 strcpyW((WCHAR*)cp, family_nameW);
7504 cp += lenfam;
7505 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
7506 strcpyW((WCHAR*)cp, style_nameW);
7507 cp += lensty;
7508 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7509 strcpyW((WCHAR*)cp, face_nameW);
7510 cp += lenface;
7511 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
7512 strcpyW((WCHAR*)cp, full_nameW);
7513 ret = TRUE;
7515 end:
7516 HeapFree(GetProcessHeap(), 0, style_nameW);
7517 HeapFree(GetProcessHeap(), 0, family_nameW);
7518 HeapFree(GetProcessHeap(), 0, face_nameW);
7519 HeapFree(GetProcessHeap(), 0, full_nameW);
7520 return ret;
7523 /*************************************************************
7524 * freetype_GetGlyphOutline
7526 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
7527 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7529 struct freetype_physdev *physdev = get_freetype_dev( dev );
7530 DWORD ret;
7531 ABC abc;
7533 if (!physdev->font)
7535 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
7536 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
7539 GDI_CheckNotLock();
7540 EnterCriticalSection( &freetype_cs );
7541 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
7542 LeaveCriticalSection( &freetype_cs );
7543 return ret;
7546 /*************************************************************
7547 * freetype_GetTextMetrics
7549 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
7551 struct freetype_physdev *physdev = get_freetype_dev( dev );
7552 BOOL ret;
7554 if (!physdev->font)
7556 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
7557 return dev->funcs->pGetTextMetrics( dev, metrics );
7560 GDI_CheckNotLock();
7561 EnterCriticalSection( &freetype_cs );
7562 ret = get_text_metrics( physdev->font, metrics );
7563 LeaveCriticalSection( &freetype_cs );
7564 return ret;
7567 /*************************************************************
7568 * freetype_GetOutlineTextMetrics
7570 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
7572 struct freetype_physdev *physdev = get_freetype_dev( dev );
7573 UINT ret = 0;
7575 if (!physdev->font)
7577 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
7578 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
7581 TRACE("font=%p\n", physdev->font);
7583 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
7585 GDI_CheckNotLock();
7586 EnterCriticalSection( &freetype_cs );
7588 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
7590 if(cbSize >= physdev->font->potm->otmSize)
7592 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
7593 scale_outline_font_metrics(physdev->font, potm);
7595 ret = physdev->font->potm->otmSize;
7597 LeaveCriticalSection( &freetype_cs );
7598 return ret;
7601 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
7603 child->font = alloc_font();
7604 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
7605 if(!child->font->ft_face)
7607 free_font(child->font);
7608 child->font = NULL;
7609 return FALSE;
7612 child->font->font_desc = font->font_desc;
7613 child->font->ntmFlags = child->face->ntmFlags;
7614 child->font->orientation = font->orientation;
7615 child->font->scale_y = font->scale_y;
7616 child->font->name = strdupW(child->face->family->FamilyName);
7617 child->font->base_font = font;
7618 TRACE("created child font %p for base %p\n", child->font, font);
7619 return TRUE;
7622 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL* vert)
7624 FT_UInt g,o;
7625 CHILD_FONT *child_font;
7627 if(font->base_font)
7628 font = font->base_font;
7630 *linked_font = font;
7632 if((*glyph = get_glyph_index(font, c)))
7634 o = *glyph;
7635 *glyph = get_GSUB_vert_glyph(font, *glyph);
7636 *vert = (o != *glyph);
7637 return TRUE;
7640 if (c < 32) goto done; /* don't check linked fonts for control characters */
7642 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7644 if(!child_font->font)
7645 if(!load_child_font(font, child_font))
7646 continue;
7648 if(!child_font->font->ft_face)
7649 continue;
7650 g = get_glyph_index(child_font->font, c);
7651 o = g;
7652 g = get_GSUB_vert_glyph(child_font->font, g);
7653 if(g)
7655 *glyph = g;
7656 *linked_font = child_font->font;
7657 *vert = (o != g);
7658 return TRUE;
7662 done:
7663 *vert = FALSE;
7664 return FALSE;
7667 /*************************************************************
7668 * freetype_GetCharWidth
7670 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7672 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7673 UINT c;
7674 GLYPHMETRICS gm;
7675 ABC abc;
7676 struct freetype_physdev *physdev = get_freetype_dev( dev );
7678 if (!physdev->font)
7680 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7681 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7684 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7686 GDI_CheckNotLock();
7687 EnterCriticalSection( &freetype_cs );
7688 for(c = firstChar; c <= lastChar; c++) {
7689 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7690 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
7692 LeaveCriticalSection( &freetype_cs );
7693 return TRUE;
7696 /*************************************************************
7697 * freetype_GetCharABCWidths
7699 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7701 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7702 UINT c;
7703 GLYPHMETRICS gm;
7704 struct freetype_physdev *physdev = get_freetype_dev( dev );
7706 if (!physdev->font)
7708 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7709 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7712 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7714 GDI_CheckNotLock();
7715 EnterCriticalSection( &freetype_cs );
7717 for(c = firstChar; c <= lastChar; c++, buffer++)
7718 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
7720 LeaveCriticalSection( &freetype_cs );
7721 return TRUE;
7724 /*************************************************************
7725 * freetype_GetCharABCWidthsI
7727 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7729 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7730 UINT c;
7731 GLYPHMETRICS gm;
7732 struct freetype_physdev *physdev = get_freetype_dev( dev );
7734 if (!physdev->font)
7736 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7737 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7740 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7741 return FALSE;
7743 GDI_CheckNotLock();
7744 EnterCriticalSection( &freetype_cs );
7746 for(c = 0; c < count; c++, buffer++)
7747 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
7748 &gm, buffer, 0, NULL, &identity );
7750 LeaveCriticalSection( &freetype_cs );
7751 return TRUE;
7754 /*************************************************************
7755 * freetype_GetTextExtentExPoint
7757 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
7759 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7760 INT idx, pos;
7761 ABC abc;
7762 GLYPHMETRICS gm;
7763 struct freetype_physdev *physdev = get_freetype_dev( dev );
7765 if (!physdev->font)
7767 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7768 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
7771 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
7773 GDI_CheckNotLock();
7774 EnterCriticalSection( &freetype_cs );
7776 for (idx = pos = 0; idx < count; idx++)
7778 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7779 pos += abc.abcA + abc.abcB + abc.abcC;
7780 dxs[idx] = pos;
7783 LeaveCriticalSection( &freetype_cs );
7784 return TRUE;
7787 /*************************************************************
7788 * freetype_GetTextExtentExPointI
7790 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
7792 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7793 INT idx, pos;
7794 ABC abc;
7795 GLYPHMETRICS gm;
7796 struct freetype_physdev *physdev = get_freetype_dev( dev );
7798 if (!physdev->font)
7800 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7801 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
7804 TRACE("%p, %p, %d\n", physdev->font, indices, count);
7806 GDI_CheckNotLock();
7807 EnterCriticalSection( &freetype_cs );
7809 for (idx = pos = 0; idx < count; idx++)
7811 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
7812 &gm, &abc, 0, NULL, &identity );
7813 pos += abc.abcA + abc.abcB + abc.abcC;
7814 dxs[idx] = pos;
7817 LeaveCriticalSection( &freetype_cs );
7818 return TRUE;
7821 /*************************************************************
7822 * freetype_GetFontData
7824 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7826 struct freetype_physdev *physdev = get_freetype_dev( dev );
7828 if (!physdev->font)
7830 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7831 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7834 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7835 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7836 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7838 return get_font_data( physdev->font, table, offset, buf, cbData );
7841 /*************************************************************
7842 * freetype_GetTextFace
7844 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7846 INT n;
7847 struct freetype_physdev *physdev = get_freetype_dev( dev );
7849 if (!physdev->font)
7851 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7852 return dev->funcs->pGetTextFace( dev, count, str );
7855 n = strlenW(physdev->font->name) + 1;
7856 if (str)
7858 lstrcpynW(str, physdev->font->name, count);
7859 n = min(count, n);
7861 return n;
7864 /*************************************************************
7865 * freetype_GetTextCharsetInfo
7867 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7869 struct freetype_physdev *physdev = get_freetype_dev( dev );
7871 if (!physdev->font)
7873 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7874 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7876 if (fs) *fs = physdev->font->fs;
7877 return physdev->font->charset;
7880 /* Retrieve a list of supported Unicode ranges for a given font.
7881 * Can be called with NULL gs to calculate the buffer size. Returns
7882 * the number of ranges found.
7884 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7886 DWORD num_ranges = 0;
7888 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7890 FT_UInt glyph_code;
7891 FT_ULong char_code, char_code_prev;
7893 glyph_code = 0;
7894 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7896 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7897 face->num_glyphs, glyph_code, char_code);
7899 if (!glyph_code) return 0;
7901 if (gs)
7903 gs->ranges[0].wcLow = (USHORT)char_code;
7904 gs->ranges[0].cGlyphs = 0;
7905 gs->cGlyphsSupported = 0;
7908 num_ranges = 1;
7909 while (glyph_code)
7911 if (char_code < char_code_prev)
7913 ERR("expected increasing char code from FT_Get_Next_Char\n");
7914 return 0;
7916 if (char_code - char_code_prev > 1)
7918 num_ranges++;
7919 if (gs)
7921 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7922 gs->ranges[num_ranges - 1].cGlyphs = 1;
7923 gs->cGlyphsSupported++;
7926 else if (gs)
7928 gs->ranges[num_ranges - 1].cGlyphs++;
7929 gs->cGlyphsSupported++;
7931 char_code_prev = char_code;
7932 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7935 else
7936 FIXME("encoding %u not supported\n", face->charmap->encoding);
7938 return num_ranges;
7941 /*************************************************************
7942 * freetype_GetFontUnicodeRanges
7944 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7946 struct freetype_physdev *physdev = get_freetype_dev( dev );
7947 DWORD size, num_ranges;
7949 if (!physdev->font)
7951 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7952 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7955 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7956 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7957 if (glyphset)
7959 glyphset->cbThis = size;
7960 glyphset->cRanges = num_ranges;
7961 glyphset->flAccel = 0;
7963 return size;
7966 /*************************************************************
7967 * freetype_FontIsLinked
7969 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7971 struct freetype_physdev *physdev = get_freetype_dev( dev );
7972 BOOL ret;
7974 if (!physdev->font)
7976 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7977 return dev->funcs->pFontIsLinked( dev );
7980 GDI_CheckNotLock();
7981 EnterCriticalSection( &freetype_cs );
7982 ret = !list_empty(&physdev->font->child_fonts);
7983 LeaveCriticalSection( &freetype_cs );
7984 return ret;
7987 /*************************************************************************
7988 * GetRasterizerCaps (GDI32.@)
7990 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7992 lprs->nSize = sizeof(RASTERIZER_STATUS);
7993 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
7994 lprs->nLanguageID = 0;
7995 return TRUE;
7998 /*************************************************************
7999 * freetype_GdiRealizationInfo
8001 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
8003 struct freetype_physdev *physdev = get_freetype_dev( dev );
8004 realization_info_t *info = ptr;
8006 if (!physdev->font)
8008 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
8009 return dev->funcs->pGdiRealizationInfo( dev, ptr );
8012 FIXME("(%p, %p): stub!\n", physdev->font, info);
8014 info->flags = 1;
8015 if(FT_IS_SCALABLE(physdev->font->ft_face))
8016 info->flags |= 2;
8018 info->cache_num = physdev->font->cache_num;
8019 info->unknown2 = -1;
8020 return TRUE;
8023 /*************************************************************************
8024 * Kerning support for TrueType fonts
8026 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
8028 struct TT_kern_table
8030 USHORT version;
8031 USHORT nTables;
8034 struct TT_kern_subtable
8036 USHORT version;
8037 USHORT length;
8038 union
8040 USHORT word;
8041 struct
8043 USHORT horizontal : 1;
8044 USHORT minimum : 1;
8045 USHORT cross_stream: 1;
8046 USHORT override : 1;
8047 USHORT reserved1 : 4;
8048 USHORT format : 8;
8049 } bits;
8050 } coverage;
8053 struct TT_format0_kern_subtable
8055 USHORT nPairs;
8056 USHORT searchRange;
8057 USHORT entrySelector;
8058 USHORT rangeShift;
8061 struct TT_kern_pair
8063 USHORT left;
8064 USHORT right;
8065 short value;
8068 static DWORD parse_format0_kern_subtable(GdiFont *font,
8069 const struct TT_format0_kern_subtable *tt_f0_ks,
8070 const USHORT *glyph_to_char,
8071 KERNINGPAIR *kern_pair, DWORD cPairs)
8073 USHORT i, nPairs;
8074 const struct TT_kern_pair *tt_kern_pair;
8076 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
8078 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
8080 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8081 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
8082 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
8084 if (!kern_pair || !cPairs)
8085 return nPairs;
8087 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
8089 nPairs = min(nPairs, cPairs);
8091 for (i = 0; i < nPairs; i++)
8093 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
8094 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
8095 /* this algorithm appears to better match what Windows does */
8096 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
8097 if (kern_pair->iKernAmount < 0)
8099 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
8100 kern_pair->iKernAmount -= font->ppem;
8102 else if (kern_pair->iKernAmount > 0)
8104 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
8105 kern_pair->iKernAmount += font->ppem;
8107 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
8109 TRACE("left %u right %u value %d\n",
8110 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
8112 kern_pair++;
8114 TRACE("copied %u entries\n", nPairs);
8115 return nPairs;
8118 /*************************************************************
8119 * freetype_GetKerningPairs
8121 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
8123 DWORD length;
8124 void *buf;
8125 const struct TT_kern_table *tt_kern_table;
8126 const struct TT_kern_subtable *tt_kern_subtable;
8127 USHORT i, nTables;
8128 USHORT *glyph_to_char;
8129 GdiFont *font;
8130 struct freetype_physdev *physdev = get_freetype_dev( dev );
8132 if (!(font = physdev->font))
8134 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
8135 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
8138 GDI_CheckNotLock();
8139 EnterCriticalSection( &freetype_cs );
8140 if (font->total_kern_pairs != (DWORD)-1)
8142 if (cPairs && kern_pair)
8144 cPairs = min(cPairs, font->total_kern_pairs);
8145 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8147 else cPairs = font->total_kern_pairs;
8149 LeaveCriticalSection( &freetype_cs );
8150 return cPairs;
8153 font->total_kern_pairs = 0;
8155 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
8157 if (length == GDI_ERROR)
8159 TRACE("no kerning data in the font\n");
8160 LeaveCriticalSection( &freetype_cs );
8161 return 0;
8164 buf = HeapAlloc(GetProcessHeap(), 0, length);
8165 if (!buf)
8167 WARN("Out of memory\n");
8168 LeaveCriticalSection( &freetype_cs );
8169 return 0;
8172 get_font_data(font, MS_KERN_TAG, 0, buf, length);
8174 /* build a glyph index to char code map */
8175 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
8176 if (!glyph_to_char)
8178 WARN("Out of memory allocating a glyph index to char code map\n");
8179 HeapFree(GetProcessHeap(), 0, buf);
8180 LeaveCriticalSection( &freetype_cs );
8181 return 0;
8184 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
8186 FT_UInt glyph_code;
8187 FT_ULong char_code;
8189 glyph_code = 0;
8190 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
8192 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
8193 font->ft_face->num_glyphs, glyph_code, char_code);
8195 while (glyph_code)
8197 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
8199 /* FIXME: This doesn't match what Windows does: it does some fancy
8200 * things with duplicate glyph index to char code mappings, while
8201 * we just avoid overriding existing entries.
8203 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
8204 glyph_to_char[glyph_code] = (USHORT)char_code;
8206 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
8209 else
8211 ULONG n;
8213 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
8214 for (n = 0; n <= 65535; n++)
8215 glyph_to_char[n] = (USHORT)n;
8218 tt_kern_table = buf;
8219 nTables = GET_BE_WORD(tt_kern_table->nTables);
8220 TRACE("version %u, nTables %u\n",
8221 GET_BE_WORD(tt_kern_table->version), nTables);
8223 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
8225 for (i = 0; i < nTables; i++)
8227 struct TT_kern_subtable tt_kern_subtable_copy;
8229 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
8230 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
8231 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
8233 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8234 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
8235 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
8237 /* According to the TrueType specification this is the only format
8238 * that will be properly interpreted by Windows and OS/2
8240 if (tt_kern_subtable_copy.coverage.bits.format == 0)
8242 DWORD new_chunk, old_total = font->total_kern_pairs;
8244 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8245 glyph_to_char, NULL, 0);
8246 font->total_kern_pairs += new_chunk;
8248 if (!font->kern_pairs)
8249 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
8250 font->total_kern_pairs * sizeof(*font->kern_pairs));
8251 else
8252 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
8253 font->total_kern_pairs * sizeof(*font->kern_pairs));
8255 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8256 glyph_to_char, font->kern_pairs + old_total, new_chunk);
8258 else
8259 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
8261 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
8264 HeapFree(GetProcessHeap(), 0, glyph_to_char);
8265 HeapFree(GetProcessHeap(), 0, buf);
8267 if (cPairs && kern_pair)
8269 cPairs = min(cPairs, font->total_kern_pairs);
8270 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8272 else cPairs = font->total_kern_pairs;
8274 LeaveCriticalSection( &freetype_cs );
8275 return cPairs;
8278 static const struct gdi_dc_funcs freetype_funcs =
8280 NULL, /* pAbortDoc */
8281 NULL, /* pAbortPath */
8282 NULL, /* pAlphaBlend */
8283 NULL, /* pAngleArc */
8284 NULL, /* pArc */
8285 NULL, /* pArcTo */
8286 NULL, /* pBeginPath */
8287 NULL, /* pBlendImage */
8288 NULL, /* pChord */
8289 NULL, /* pCloseFigure */
8290 NULL, /* pCreateCompatibleDC */
8291 freetype_CreateDC, /* pCreateDC */
8292 freetype_DeleteDC, /* pDeleteDC */
8293 NULL, /* pDeleteObject */
8294 NULL, /* pDeviceCapabilities */
8295 NULL, /* pEllipse */
8296 NULL, /* pEndDoc */
8297 NULL, /* pEndPage */
8298 NULL, /* pEndPath */
8299 freetype_EnumFonts, /* pEnumFonts */
8300 NULL, /* pEnumICMProfiles */
8301 NULL, /* pExcludeClipRect */
8302 NULL, /* pExtDeviceMode */
8303 NULL, /* pExtEscape */
8304 NULL, /* pExtFloodFill */
8305 NULL, /* pExtSelectClipRgn */
8306 NULL, /* pExtTextOut */
8307 NULL, /* pFillPath */
8308 NULL, /* pFillRgn */
8309 NULL, /* pFlattenPath */
8310 freetype_FontIsLinked, /* pFontIsLinked */
8311 NULL, /* pFrameRgn */
8312 NULL, /* pGdiComment */
8313 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
8314 NULL, /* pGetBoundsRect */
8315 freetype_GetCharABCWidths, /* pGetCharABCWidths */
8316 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
8317 freetype_GetCharWidth, /* pGetCharWidth */
8318 NULL, /* pGetDeviceCaps */
8319 NULL, /* pGetDeviceGammaRamp */
8320 freetype_GetFontData, /* pGetFontData */
8321 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
8322 freetype_GetGlyphIndices, /* pGetGlyphIndices */
8323 freetype_GetGlyphOutline, /* pGetGlyphOutline */
8324 NULL, /* pGetICMProfile */
8325 NULL, /* pGetImage */
8326 freetype_GetKerningPairs, /* pGetKerningPairs */
8327 NULL, /* pGetNearestColor */
8328 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
8329 NULL, /* pGetPixel */
8330 NULL, /* pGetSystemPaletteEntries */
8331 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
8332 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
8333 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
8334 freetype_GetTextFace, /* pGetTextFace */
8335 freetype_GetTextMetrics, /* pGetTextMetrics */
8336 NULL, /* pGradientFill */
8337 NULL, /* pIntersectClipRect */
8338 NULL, /* pInvertRgn */
8339 NULL, /* pLineTo */
8340 NULL, /* pModifyWorldTransform */
8341 NULL, /* pMoveTo */
8342 NULL, /* pOffsetClipRgn */
8343 NULL, /* pOffsetViewportOrg */
8344 NULL, /* pOffsetWindowOrg */
8345 NULL, /* pPaintRgn */
8346 NULL, /* pPatBlt */
8347 NULL, /* pPie */
8348 NULL, /* pPolyBezier */
8349 NULL, /* pPolyBezierTo */
8350 NULL, /* pPolyDraw */
8351 NULL, /* pPolyPolygon */
8352 NULL, /* pPolyPolyline */
8353 NULL, /* pPolygon */
8354 NULL, /* pPolyline */
8355 NULL, /* pPolylineTo */
8356 NULL, /* pPutImage */
8357 NULL, /* pRealizeDefaultPalette */
8358 NULL, /* pRealizePalette */
8359 NULL, /* pRectangle */
8360 NULL, /* pResetDC */
8361 NULL, /* pRestoreDC */
8362 NULL, /* pRoundRect */
8363 NULL, /* pSaveDC */
8364 NULL, /* pScaleViewportExt */
8365 NULL, /* pScaleWindowExt */
8366 NULL, /* pSelectBitmap */
8367 NULL, /* pSelectBrush */
8368 NULL, /* pSelectClipPath */
8369 freetype_SelectFont, /* pSelectFont */
8370 NULL, /* pSelectPalette */
8371 NULL, /* pSelectPen */
8372 NULL, /* pSetArcDirection */
8373 NULL, /* pSetBkColor */
8374 NULL, /* pSetBkMode */
8375 NULL, /* pSetDCBrushColor */
8376 NULL, /* pSetDCPenColor */
8377 NULL, /* pSetDIBColorTable */
8378 NULL, /* pSetDIBitsToDevice */
8379 NULL, /* pSetDeviceClipping */
8380 NULL, /* pSetDeviceGammaRamp */
8381 NULL, /* pSetLayout */
8382 NULL, /* pSetMapMode */
8383 NULL, /* pSetMapperFlags */
8384 NULL, /* pSetPixel */
8385 NULL, /* pSetPolyFillMode */
8386 NULL, /* pSetROP2 */
8387 NULL, /* pSetRelAbs */
8388 NULL, /* pSetStretchBltMode */
8389 NULL, /* pSetTextAlign */
8390 NULL, /* pSetTextCharacterExtra */
8391 NULL, /* pSetTextColor */
8392 NULL, /* pSetTextJustification */
8393 NULL, /* pSetViewportExt */
8394 NULL, /* pSetViewportOrg */
8395 NULL, /* pSetWindowExt */
8396 NULL, /* pSetWindowOrg */
8397 NULL, /* pSetWorldTransform */
8398 NULL, /* pStartDoc */
8399 NULL, /* pStartPage */
8400 NULL, /* pStretchBlt */
8401 NULL, /* pStretchDIBits */
8402 NULL, /* pStrokeAndFillPath */
8403 NULL, /* pStrokePath */
8404 NULL, /* pUnrealizePalette */
8405 NULL, /* pWidenPath */
8406 NULL, /* wine_get_wgl_driver */
8407 GDI_PRIORITY_FONT_DRV /* priority */
8410 #else /* HAVE_FREETYPE */
8412 /*************************************************************************/
8414 BOOL WineEngInit(void)
8416 return FALSE;
8419 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8421 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8422 return 1;
8425 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8427 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8428 return TRUE;
8431 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
8433 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
8434 return NULL;
8437 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
8438 LPCWSTR font_file, LPCWSTR font_path )
8440 FIXME("stub\n");
8441 return FALSE;
8444 /*************************************************************************
8445 * GetRasterizerCaps (GDI32.@)
8447 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8449 lprs->nSize = sizeof(RASTERIZER_STATUS);
8450 lprs->wFlags = 0;
8451 lprs->nLanguageID = 0;
8452 return TRUE;
8455 #endif /* HAVE_FREETYPE */