gdi32: Don't modify output glyph metrics unless the function succeeds.
[wine.git] / dlls / gdi32 / freetype.c
blobab7b99fbbd040a76100eefa878c2fd37aea11c31
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.bCharSet) continue;
4517 if((ratio.xRatio == 0 &&
4518 ratio.yStartRatio == 0 &&
4519 ratio.yEndRatio == 0) ||
4520 (devXRatio == ratio.xRatio &&
4521 devYRatio >= ratio.yStartRatio &&
4522 devYRatio <= ratio.yEndRatio))
4524 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4525 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4526 offset = GET_BE_WORD(tmp);
4527 break;
4531 if(offset == -1) return 0;
4533 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4534 USHORT recs;
4535 BYTE startsz, endsz;
4536 WORD *vTable;
4538 recs = GET_BE_WORD(group.recs);
4539 startsz = group.startsz;
4540 endsz = group.endsz;
4542 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4544 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4545 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4546 if(result == GDI_ERROR) {
4547 FIXME("Failed to retrieve vTable\n");
4548 goto end;
4551 if(height > 0) {
4552 for(i = 0; i < recs; i++) {
4553 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4554 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4555 ppem = GET_BE_WORD(vTable[i * 3]);
4557 if(yMax + -yMin == height) {
4558 font->yMax = yMax;
4559 font->yMin = yMin;
4560 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4561 break;
4563 if(yMax + -yMin > height) {
4564 if(--i < 0) {
4565 ppem = 0;
4566 goto end; /* failed */
4568 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4569 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4570 ppem = GET_BE_WORD(vTable[i * 3]);
4571 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4572 break;
4575 if(!font->yMax) {
4576 ppem = 0;
4577 TRACE("ppem not found for height %d\n", height);
4579 } else {
4580 ppem = -height;
4581 if(ppem < startsz || ppem > endsz)
4583 ppem = 0;
4584 goto end;
4587 for(i = 0; i < recs; i++) {
4588 USHORT yPelHeight;
4589 yPelHeight = GET_BE_WORD(vTable[i * 3]);
4591 if(yPelHeight > ppem)
4593 ppem = 0;
4594 break; /* failed */
4597 if(yPelHeight == ppem) {
4598 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4599 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4600 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
4601 break;
4605 end:
4606 HeapFree(GetProcessHeap(), 0, vTable);
4609 return ppem;
4612 static void dump_gdi_font_list(void)
4614 GdiFont *font;
4616 TRACE("---------- Font Cache ----------\n");
4617 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct tagGdiFont, entry )
4618 TRACE("font=%p ref=%u %s %d\n", font, font->refcount,
4619 debugstr_w(font->font_desc.lf.lfFaceName), font->font_desc.lf.lfHeight);
4622 static void grab_font( GdiFont *font )
4624 if (!font->refcount++)
4626 list_remove( &font->unused_entry );
4627 unused_font_count--;
4631 static void release_font( GdiFont *font )
4633 if (!font) return;
4634 if (!--font->refcount)
4636 TRACE( "font %p\n", font );
4638 /* add it to the unused list */
4639 list_add_head( &unused_gdi_font_list, &font->unused_entry );
4640 if (unused_font_count > UNUSED_CACHE_SIZE)
4642 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct tagGdiFont, unused_entry );
4643 TRACE( "freeing %p\n", font );
4644 list_remove( &font->entry );
4645 list_remove( &font->unused_entry );
4646 free_font( font );
4648 else unused_font_count++;
4650 if (TRACE_ON(font)) dump_gdi_font_list();
4654 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4656 if(font->font_desc.hash != fd->hash) return TRUE;
4657 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4658 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4659 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4660 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4663 static void calc_hash(FONT_DESC *pfd)
4665 DWORD hash = 0, *ptr, two_chars;
4666 WORD *pwc;
4667 unsigned int i;
4669 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4670 hash ^= *ptr;
4671 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4672 hash ^= *ptr;
4673 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4674 two_chars = *ptr;
4675 pwc = (WCHAR *)&two_chars;
4676 if(!*pwc) break;
4677 *pwc = toupperW(*pwc);
4678 pwc++;
4679 *pwc = toupperW(*pwc);
4680 hash ^= two_chars;
4681 if(!*pwc) break;
4683 hash ^= !pfd->can_use_bitmap;
4684 pfd->hash = hash;
4685 return;
4688 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4690 GdiFont *ret;
4691 FONT_DESC fd;
4693 fd.lf = *plf;
4694 fd.matrix = *pmat;
4695 fd.can_use_bitmap = can_use_bitmap;
4696 calc_hash(&fd);
4698 /* try the in-use list */
4699 LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
4701 if(fontcmp(ret, &fd)) continue;
4702 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4703 list_remove( &ret->entry );
4704 list_add_head( &gdi_font_list, &ret->entry );
4705 grab_font( ret );
4706 return ret;
4708 return NULL;
4711 static void add_to_cache(GdiFont *font)
4713 static DWORD cache_num = 1;
4715 font->cache_num = cache_num++;
4716 list_add_head(&gdi_font_list, &font->entry);
4717 TRACE( "font %p\n", font );
4720 /*************************************************************
4721 * create_child_font_list
4723 static BOOL create_child_font_list(GdiFont *font)
4725 BOOL ret = FALSE;
4726 SYSTEM_LINKS *font_link;
4727 CHILD_FONT *font_link_entry, *new_child;
4728 FontSubst *psub;
4729 WCHAR* font_name;
4731 psub = get_font_subst(&font_subst_list, font->name, -1);
4732 font_name = psub ? psub->to.name : font->name;
4733 font_link = find_font_link(font_name);
4734 if (font_link != NULL)
4736 TRACE("found entry in system list\n");
4737 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4739 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4740 new_child->face = font_link_entry->face;
4741 new_child->font = NULL;
4742 new_child->face->refcount++;
4743 list_add_tail(&font->child_fonts, &new_child->entry);
4744 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4746 ret = TRUE;
4749 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4750 * Sans Serif. This is how asian windows get default fallbacks for fonts
4752 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4753 font->charset != OEM_CHARSET &&
4754 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4756 font_link = find_font_link(szDefaultFallbackLink);
4757 if (font_link != NULL)
4759 TRACE("found entry in default fallback list\n");
4760 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4762 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4763 new_child->face = font_link_entry->face;
4764 new_child->font = NULL;
4765 new_child->face->refcount++;
4766 list_add_tail(&font->child_fonts, &new_child->entry);
4767 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4769 ret = TRUE;
4773 return ret;
4776 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4778 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4780 if (pFT_Set_Charmap)
4782 FT_Int i;
4783 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4785 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4787 for (i = 0; i < ft_face->num_charmaps; i++)
4789 if (ft_face->charmaps[i]->encoding == encoding)
4791 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4792 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4794 switch (ft_face->charmaps[i]->platform_id)
4796 default:
4797 cmap_def = ft_face->charmaps[i];
4798 break;
4799 case 0: /* Apple Unicode */
4800 cmap0 = ft_face->charmaps[i];
4801 break;
4802 case 1: /* Macintosh */
4803 cmap1 = ft_face->charmaps[i];
4804 break;
4805 case 2: /* ISO */
4806 cmap2 = ft_face->charmaps[i];
4807 break;
4808 case 3: /* Microsoft */
4809 cmap3 = ft_face->charmaps[i];
4810 break;
4814 if (cmap3) /* prefer Microsoft cmap table */
4815 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4816 else if (cmap1)
4817 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4818 else if (cmap2)
4819 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4820 else if (cmap0)
4821 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4822 else if (cmap_def)
4823 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4825 return ft_err == FT_Err_Ok;
4828 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4832 /*************************************************************
4833 * freetype_CreateDC
4835 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4836 LPCWSTR output, const DEVMODEW *devmode )
4838 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4840 if (!physdev) return FALSE;
4841 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4842 return TRUE;
4846 /*************************************************************
4847 * freetype_DeleteDC
4849 static BOOL freetype_DeleteDC( PHYSDEV dev )
4851 struct freetype_physdev *physdev = get_freetype_dev( dev );
4852 release_font( physdev->font );
4853 HeapFree( GetProcessHeap(), 0, physdev );
4854 return TRUE;
4857 static FT_Encoding pick_charmap( FT_Face face, int charset )
4859 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
4860 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
4861 const FT_Encoding *encs = regular_order;
4863 if (charset == SYMBOL_CHARSET) encs = symbol_order;
4865 while (*encs != 0)
4867 if (select_charmap( face, *encs )) break;
4868 encs++;
4870 return *encs;
4873 #define GASP_GRIDFIT 0x01
4874 #define GASP_DOGRAY 0x02
4875 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4877 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
4879 DWORD size;
4880 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
4881 WORD *alloced = NULL, *ptr = buf;
4882 WORD num_recs, version;
4883 BOOL ret = FALSE;
4885 *flags = 0;
4886 size = get_font_data( font, GASP_TAG, 0, NULL, 0 );
4887 if (size == GDI_ERROR) return FALSE;
4888 if (size < 4 * sizeof(WORD)) return FALSE;
4889 if (size > sizeof(buf))
4891 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
4892 if (!ptr) return FALSE;
4895 get_font_data( font, GASP_TAG, 0, ptr, size );
4897 version = GET_BE_WORD( *ptr++ );
4898 num_recs = GET_BE_WORD( *ptr++ );
4900 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
4902 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
4903 goto done;
4906 while (num_recs--)
4908 *flags = GET_BE_WORD( *(ptr + 1) );
4909 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
4910 ptr += 2;
4912 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
4913 ret = TRUE;
4915 done:
4916 HeapFree( GetProcessHeap(), 0, alloced );
4917 return ret;
4920 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4922 const GSUB_ScriptList *script;
4923 const GSUB_Script *deflt = NULL;
4924 int i;
4925 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4927 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4928 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4930 const GSUB_Script *scr;
4931 int offset;
4933 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4934 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4936 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4937 return scr;
4938 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4939 deflt = scr;
4941 return deflt;
4944 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4946 int i;
4947 int offset;
4948 const GSUB_LangSys *Lang;
4950 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4952 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4954 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4955 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4957 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4958 return Lang;
4960 offset = GET_BE_WORD(script->DefaultLangSys);
4961 if (offset)
4963 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4964 return Lang;
4966 return NULL;
4969 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4971 int i;
4972 const GSUB_FeatureList *feature;
4973 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4975 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4976 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4978 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4979 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4981 const GSUB_Feature *feat;
4982 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4983 return feat;
4986 return NULL;
4989 static const char* get_opentype_script(const GdiFont *font)
4992 * I am not sure if this is the correct way to generate our script tag
4995 switch (font->charset)
4997 case ANSI_CHARSET: return "latn";
4998 case BALTIC_CHARSET: return "latn"; /* ?? */
4999 case CHINESEBIG5_CHARSET: return "hani";
5000 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5001 case GB2312_CHARSET: return "hani";
5002 case GREEK_CHARSET: return "grek";
5003 case HANGUL_CHARSET: return "hang";
5004 case RUSSIAN_CHARSET: return "cyrl";
5005 case SHIFTJIS_CHARSET: return "kana";
5006 case TURKISH_CHARSET: return "latn"; /* ?? */
5007 case VIETNAMESE_CHARSET: return "latn";
5008 case JOHAB_CHARSET: return "latn"; /* ?? */
5009 case ARABIC_CHARSET: return "arab";
5010 case HEBREW_CHARSET: return "hebr";
5011 case THAI_CHARSET: return "thai";
5012 default: return "latn";
5016 static const VOID * get_GSUB_vert_feature(const GdiFont *font)
5018 const GSUB_Header *header;
5019 const GSUB_Script *script;
5020 const GSUB_LangSys *language;
5021 const GSUB_Feature *feature;
5023 if (!font->GSUB_Table)
5024 return NULL;
5026 header = font->GSUB_Table;
5028 script = GSUB_get_script_table(header, get_opentype_script(font));
5029 if (!script)
5031 TRACE("Script not found\n");
5032 return NULL;
5034 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5035 if (!language)
5037 TRACE("Language not found\n");
5038 return NULL;
5040 feature = GSUB_get_feature(header, language, "vrt2");
5041 if (!feature)
5042 feature = GSUB_get_feature(header, language, "vert");
5043 if (!feature)
5045 TRACE("vrt2/vert feature not found\n");
5046 return NULL;
5048 return feature;
5051 /*************************************************************
5052 * freetype_SelectFont
5054 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
5056 struct freetype_physdev *physdev = get_freetype_dev( dev );
5057 GdiFont *ret;
5058 Face *face, *best, *best_bitmap;
5059 Family *family, *last_resort_family;
5060 const struct list *face_list;
5061 INT height, width = 0;
5062 unsigned int score = 0, new_score;
5063 signed int diff = 0, newdiff;
5064 BOOL bd, it, can_use_bitmap, want_vertical;
5065 LOGFONTW lf;
5066 CHARSETINFO csi;
5067 FMAT2 dcmat;
5068 FontSubst *psub = NULL;
5069 DC *dc = get_dc_ptr( dev->hdc );
5070 const SYSTEM_LINKS *font_link;
5072 if (!hfont) /* notification that the font has been changed by another driver */
5074 release_font( physdev->font );
5075 physdev->font = NULL;
5076 release_dc_ptr( dc );
5077 return 0;
5080 GetObjectW( hfont, sizeof(lf), &lf );
5081 lf.lfWidth = abs(lf.lfWidth);
5083 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
5085 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
5086 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
5087 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
5088 lf.lfEscapement);
5090 if(dc->GraphicsMode == GM_ADVANCED)
5092 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
5093 /* Try to avoid not necessary glyph transformations */
5094 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
5096 lf.lfHeight *= fabs(dcmat.eM11);
5097 lf.lfWidth *= fabs(dcmat.eM11);
5098 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
5101 else
5103 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
5104 font scaling abilities. */
5105 dcmat.eM11 = dcmat.eM22 = 1.0;
5106 dcmat.eM21 = dcmat.eM12 = 0;
5107 lf.lfOrientation = lf.lfEscapement;
5108 if (dc->vport2WorldValid)
5110 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
5111 lf.lfOrientation = -lf.lfOrientation;
5112 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
5113 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
5117 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
5118 dcmat.eM21, dcmat.eM22);
5120 GDI_CheckNotLock();
5121 EnterCriticalSection( &freetype_cs );
5123 /* check the cache first */
5124 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5125 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
5126 goto done;
5129 TRACE("not in cache\n");
5130 ret = alloc_font();
5132 ret->font_desc.matrix = dcmat;
5133 ret->font_desc.lf = lf;
5134 ret->font_desc.can_use_bitmap = can_use_bitmap;
5135 calc_hash(&ret->font_desc);
5137 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
5138 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
5139 original value lfCharSet. Note this is a special case for
5140 Symbol and doesn't happen at least for "Wingdings*" */
5142 if(!strcmpiW(lf.lfFaceName, SymbolW))
5143 lf.lfCharSet = SYMBOL_CHARSET;
5145 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
5146 switch(lf.lfCharSet) {
5147 case DEFAULT_CHARSET:
5148 csi.fs.fsCsb[0] = 0;
5149 break;
5150 default:
5151 FIXME("Untranslated charset %d\n", lf.lfCharSet);
5152 csi.fs.fsCsb[0] = 0;
5153 break;
5157 family = NULL;
5158 if(lf.lfFaceName[0] != '\0') {
5159 CHILD_FONT *font_link_entry;
5160 LPWSTR FaceName = lf.lfFaceName;
5162 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
5164 if(psub) {
5165 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
5166 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
5167 if (psub->to.charset != -1)
5168 lf.lfCharSet = psub->to.charset;
5171 /* We want a match on name and charset or just name if
5172 charset was DEFAULT_CHARSET. If the latter then
5173 we fixup the returned charset later in get_nearest_charset
5174 where we'll either use the charset of the current ansi codepage
5175 or if that's unavailable the first charset that the font supports.
5177 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5178 if (!strcmpiW(family->FamilyName, FaceName) ||
5179 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
5181 font_link = find_font_link(family->FamilyName);
5182 face_list = get_face_list_from_family(family);
5183 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5184 if (!(face->scalable || can_use_bitmap))
5185 continue;
5186 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5187 goto found;
5188 if (font_link != NULL &&
5189 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5190 goto found;
5191 if (!csi.fs.fsCsb[0])
5192 goto found;
5197 /* Search by full face name. */
5198 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5199 face_list = get_face_list_from_family(family);
5200 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5201 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
5202 (face->scalable || can_use_bitmap))
5204 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5205 goto found_face;
5206 font_link = find_font_link(family->FamilyName);
5207 if (font_link != NULL &&
5208 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5209 goto found_face;
5215 * Try check the SystemLink list first for a replacement font.
5216 * We may find good replacements there.
5218 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
5220 if(!strcmpiW(font_link->font_name, FaceName) ||
5221 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
5223 TRACE("found entry in system list\n");
5224 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5226 const SYSTEM_LINKS *links;
5228 face = font_link_entry->face;
5229 if (!(face->scalable || can_use_bitmap))
5230 continue;
5231 family = face->family;
5232 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5233 goto found;
5234 links = find_font_link(family->FamilyName);
5235 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
5236 goto found;
5242 psub = NULL; /* substitution is no more relevant */
5244 /* If requested charset was DEFAULT_CHARSET then try using charset
5245 corresponding to the current ansi codepage */
5246 if (!csi.fs.fsCsb[0])
5248 INT acp = GetACP();
5249 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
5250 FIXME("TCI failed on codepage %d\n", acp);
5251 csi.fs.fsCsb[0] = 0;
5252 } else
5253 lf.lfCharSet = csi.ciCharset;
5256 want_vertical = (lf.lfFaceName[0] == '@');
5258 /* Face families are in the top 4 bits of lfPitchAndFamily,
5259 so mask with 0xF0 before testing */
5261 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
5262 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
5263 strcpyW(lf.lfFaceName, defFixed);
5264 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
5265 strcpyW(lf.lfFaceName, defSerif);
5266 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
5267 strcpyW(lf.lfFaceName, defSans);
5268 else
5269 strcpyW(lf.lfFaceName, defSans);
5270 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5271 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
5272 font_link = find_font_link(family->FamilyName);
5273 face_list = get_face_list_from_family(family);
5274 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5275 if (!(face->scalable || can_use_bitmap))
5276 continue;
5277 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5278 goto found;
5279 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5280 goto found;
5285 last_resort_family = NULL;
5286 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5287 font_link = find_font_link(family->FamilyName);
5288 face_list = get_face_list_from_family(family);
5289 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5290 if(!(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical &&
5291 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5292 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
5293 if(face->scalable)
5294 goto found;
5295 if(can_use_bitmap && !last_resort_family)
5296 last_resort_family = family;
5301 if(last_resort_family) {
5302 family = last_resort_family;
5303 csi.fs.fsCsb[0] = 0;
5304 goto found;
5307 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5308 face_list = get_face_list_from_family(family);
5309 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5310 if(face->scalable && !(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical) {
5311 csi.fs.fsCsb[0] = 0;
5312 WARN("just using first face for now\n");
5313 goto found;
5315 if(can_use_bitmap && !last_resort_family)
5316 last_resort_family = family;
5319 if(!last_resort_family) {
5320 FIXME("can't find a single appropriate font - bailing\n");
5321 free_font(ret);
5322 ret = NULL;
5323 goto done;
5326 WARN("could only find a bitmap font - this will probably look awful!\n");
5327 family = last_resort_family;
5328 csi.fs.fsCsb[0] = 0;
5330 found:
5331 it = lf.lfItalic ? 1 : 0;
5332 bd = lf.lfWeight > 550 ? 1 : 0;
5334 height = lf.lfHeight;
5336 face = best = best_bitmap = NULL;
5337 font_link = find_font_link(family->FamilyName);
5338 face_list = get_face_list_from_family(family);
5339 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5341 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5342 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
5343 !csi.fs.fsCsb[0])
5345 BOOL italic, bold;
5347 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
5348 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
5349 new_score = (italic ^ it) + (bold ^ bd);
5350 if(!best || new_score <= score)
5352 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5353 italic, bold, it, bd);
5354 score = new_score;
5355 best = face;
5356 if(best->scalable && score == 0) break;
5357 if(!best->scalable)
5359 if(height > 0)
5360 newdiff = height - (signed int)(best->size.height);
5361 else
5362 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
5363 if(!best_bitmap || new_score < score ||
5364 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
5366 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
5367 diff = newdiff;
5368 best_bitmap = best;
5369 if(score == 0 && diff == 0) break;
5375 if(best)
5376 face = best->scalable ? best : best_bitmap;
5377 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
5378 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
5380 found_face:
5381 height = lf.lfHeight;
5383 ret->fs = face->fs;
5385 if(csi.fs.fsCsb[0]) {
5386 ret->charset = lf.lfCharSet;
5387 ret->codepage = csi.ciACP;
5389 else
5390 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
5392 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
5393 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
5395 ret->aveWidth = height ? lf.lfWidth : 0;
5397 if(!face->scalable) {
5398 /* Windows uses integer scaling factors for bitmap fonts */
5399 INT scale, scaled_height;
5400 GdiFont *cachedfont;
5402 /* FIXME: rotation of bitmap fonts is ignored */
5403 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
5404 if (ret->aveWidth)
5405 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
5406 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
5407 dcmat.eM11 = dcmat.eM22 = 1.0;
5408 /* As we changed the matrix, we need to search the cache for the font again,
5409 * otherwise we might explode the cache. */
5410 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5411 TRACE("Found cached font after non-scalable matrix rescale!\n");
5412 free_font( ret );
5413 ret = cachedfont;
5414 goto done;
5416 calc_hash(&ret->font_desc);
5418 if (height != 0) height = diff;
5419 height += face->size.height;
5421 scale = (height + face->size.height - 1) / face->size.height;
5422 scaled_height = scale * face->size.height;
5423 /* Only jump to the next height if the difference <= 25% original height */
5424 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
5425 /* The jump between unscaled and doubled is delayed by 1 */
5426 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
5427 ret->scale_y = scale;
5429 width = face->size.x_ppem >> 6;
5430 height = face->size.y_ppem >> 6;
5432 else
5433 ret->scale_y = 1.0;
5434 TRACE("font scale y: %f\n", ret->scale_y);
5436 ret->ft_face = OpenFontFace(ret, face, width, height);
5438 if (!ret->ft_face)
5440 free_font( ret );
5441 ret = NULL;
5442 goto done;
5445 ret->ntmFlags = face->ntmFlags;
5447 pick_charmap( ret->ft_face, ret->charset );
5449 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
5450 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
5451 ret->underline = lf.lfUnderline ? 0xff : 0;
5452 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
5453 create_child_font_list(ret);
5455 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
5457 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
5458 if (length != GDI_ERROR)
5460 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
5461 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
5462 TRACE("Loaded GSUB table of %i bytes\n",length);
5463 ret->vert_feature = get_GSUB_vert_feature(ret);
5464 if (!ret->vert_feature)
5466 TRACE("Vertical feature not found\n");
5467 HeapFree(GetProcessHeap(), 0, ret->GSUB_Table);
5468 ret->GSUB_Table = NULL;
5472 ret->aa_flags = HIWORD( face->flags );
5474 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
5476 add_to_cache(ret);
5477 done:
5478 if (ret)
5480 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
5482 switch (lf.lfQuality)
5484 case NONANTIALIASED_QUALITY:
5485 case ANTIALIASED_QUALITY:
5486 next->funcs->pSelectFont( dev, hfont, aa_flags );
5487 break;
5488 case CLEARTYPE_QUALITY:
5489 case CLEARTYPE_NATURAL_QUALITY:
5490 default:
5491 if (!*aa_flags) *aa_flags = ret->aa_flags;
5492 next->funcs->pSelectFont( dev, hfont, aa_flags );
5494 /* fixup the antialiasing flags for that font */
5495 switch (*aa_flags)
5497 case WINE_GGO_HRGB_BITMAP:
5498 case WINE_GGO_HBGR_BITMAP:
5499 case WINE_GGO_VRGB_BITMAP:
5500 case WINE_GGO_VBGR_BITMAP:
5501 if (is_subpixel_rendering_enabled()) break;
5502 *aa_flags = GGO_GRAY4_BITMAP;
5503 /* fall through */
5504 case GGO_GRAY2_BITMAP:
5505 case GGO_GRAY4_BITMAP:
5506 case GGO_GRAY8_BITMAP:
5507 case WINE_GGO_GRAY16_BITMAP:
5508 if (is_hinting_enabled())
5510 WORD gasp_flags;
5511 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
5513 TRACE( "font %s %d aa disabled by GASP\n",
5514 debugstr_w(lf.lfFaceName), lf.lfHeight );
5515 *aa_flags = GGO_BITMAP;
5520 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5521 release_font( physdev->font );
5522 physdev->font = ret;
5524 LeaveCriticalSection( &freetype_cs );
5525 release_dc_ptr( dc );
5526 return ret ? hfont : 0;
5529 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5531 HRSRC rsrc;
5532 HGLOBAL hMem;
5533 WCHAR *p;
5534 int i;
5536 id += IDS_FIRST_SCRIPT;
5537 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5538 if (!rsrc) return 0;
5539 hMem = LoadResource( gdi32_module, rsrc );
5540 if (!hMem) return 0;
5542 p = LockResource( hMem );
5543 id &= 0x000f;
5544 while (id--) p += *p + 1;
5546 i = min(LF_FACESIZE - 1, *p);
5547 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5548 buffer[i] = 0;
5549 return i;
5553 /***************************************************
5554 * create_enum_charset_list
5556 * This function creates charset enumeration list because in DEFAULT_CHARSET
5557 * case, the ANSI codepage's charset takes precedence over other charsets.
5558 * This function works as a filter other than DEFAULT_CHARSET case.
5560 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5562 CHARSETINFO csi;
5563 DWORD n = 0;
5565 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5566 csi.fs.fsCsb[0] != 0) {
5567 list->element[n].mask = csi.fs.fsCsb[0];
5568 list->element[n].charset = csi.ciCharset;
5569 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5570 n++;
5572 else { /* charset is DEFAULT_CHARSET or invalid. */
5573 INT acp, i;
5574 DWORD mask = 0;
5576 /* Set the current codepage's charset as the first element. */
5577 acp = GetACP();
5578 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5579 csi.fs.fsCsb[0] != 0) {
5580 list->element[n].mask = csi.fs.fsCsb[0];
5581 list->element[n].charset = csi.ciCharset;
5582 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5583 mask |= csi.fs.fsCsb[0];
5584 n++;
5587 /* Fill out left elements. */
5588 for (i = 0; i < 32; i++) {
5589 FONTSIGNATURE fs;
5590 fs.fsCsb[0] = 1L << i;
5591 fs.fsCsb[1] = 0;
5592 if (fs.fsCsb[0] & mask)
5593 continue; /* skip, already added. */
5594 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5595 continue; /* skip, this is an invalid fsCsb bit. */
5597 list->element[n].mask = fs.fsCsb[0];
5598 list->element[n].charset = csi.ciCharset;
5599 load_script_name( i, list->element[n].name );
5600 mask |= fs.fsCsb[0];
5601 n++;
5604 /* add catch all mask for remaining bits */
5605 if (~mask)
5607 list->element[n].mask = ~mask;
5608 list->element[n].charset = DEFAULT_CHARSET;
5609 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5610 n++;
5613 list->total = n;
5615 return n;
5618 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
5619 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5621 GdiFont *font;
5622 LONG width, height;
5624 if (face->cached_enum_data)
5626 TRACE("Cached\n");
5627 *pelf = face->cached_enum_data->elf;
5628 *pntm = face->cached_enum_data->ntm;
5629 *ptype = face->cached_enum_data->type;
5630 return;
5633 font = alloc_font();
5635 if(face->scalable) {
5636 height = 100;
5637 width = 0;
5638 } else {
5639 height = face->size.y_ppem >> 6;
5640 width = face->size.x_ppem >> 6;
5642 font->scale_y = 1.0;
5644 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5646 free_font(font);
5647 return;
5650 font->name = strdupW( family_name );
5651 font->ntmFlags = face->ntmFlags;
5653 if (get_outline_text_metrics(font))
5655 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5657 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5658 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5659 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5661 lstrcpynW(pelf->elfLogFont.lfFaceName,
5662 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5663 LF_FACESIZE);
5664 lstrcpynW(pelf->elfFullName,
5665 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5666 LF_FULLFACESIZE);
5667 lstrcpynW(pelf->elfStyle,
5668 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5669 LF_FACESIZE);
5671 else
5673 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5675 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5676 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5677 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5679 lstrcpynW(pelf->elfLogFont.lfFaceName, family_name, LF_FACESIZE);
5680 if (face->FullName)
5681 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5682 else
5683 lstrcpynW(pelf->elfFullName, family_name, LF_FULLFACESIZE);
5684 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5687 pntm->ntmTm.ntmFlags = face->ntmFlags;
5688 pntm->ntmFontSig = face->fs;
5690 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5692 pelf->elfLogFont.lfEscapement = 0;
5693 pelf->elfLogFont.lfOrientation = 0;
5694 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5695 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5696 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5697 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5698 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5699 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5700 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5701 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5702 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5703 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5704 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5706 *ptype = 0;
5707 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5708 *ptype |= TRUETYPE_FONTTYPE;
5709 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5710 *ptype |= DEVICE_FONTTYPE;
5711 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5712 *ptype |= RASTER_FONTTYPE;
5714 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5715 if (face->cached_enum_data)
5717 face->cached_enum_data->elf = *pelf;
5718 face->cached_enum_data->ntm = *pntm;
5719 face->cached_enum_data->type = *ptype;
5722 free_font(font);
5725 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5727 Face *face;
5728 const struct list *face_list;
5730 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5732 face_list = get_face_list_from_family(family);
5733 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5734 if (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName)) return TRUE;
5736 return FALSE;
5739 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5741 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5743 return (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName));
5746 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5747 FONTENUMPROCW proc, LPARAM lparam)
5749 ENUMLOGFONTEXW elf;
5750 NEWTEXTMETRICEXW ntm;
5751 DWORD type = 0;
5752 DWORD i;
5754 GetEnumStructs(face, face->family->FamilyName, &elf, &ntm, &type);
5755 for(i = 0; i < list->total; i++) {
5756 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5757 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5758 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
5759 i = list->total; /* break out of loop after enumeration */
5761 else
5763 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
5764 /* use the DEFAULT_CHARSET case only if no other charset is present */
5765 if (list->element[i].charset == DEFAULT_CHARSET &&
5766 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
5767 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5768 strcpyW(elf.elfScript, list->element[i].name);
5769 if (!elf.elfScript[0])
5770 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5772 /* Font Replacement */
5773 if (family != face->family)
5775 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5776 if (face->FullName)
5777 strcpyW(elf.elfFullName, face->FullName);
5778 else
5779 strcpyW(elf.elfFullName, family->FamilyName);
5781 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5782 debugstr_w(elf.elfLogFont.lfFaceName),
5783 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5784 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5785 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5786 ntm.ntmTm.ntmFlags);
5787 /* release section before callback (FIXME) */
5788 LeaveCriticalSection( &freetype_cs );
5789 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5790 EnterCriticalSection( &freetype_cs );
5792 return TRUE;
5795 /*************************************************************
5796 * freetype_EnumFonts
5798 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5800 Family *family;
5801 Face *face;
5802 const struct list *face_list;
5803 LOGFONTW lf;
5804 struct enum_charset_list enum_charsets;
5806 if (!plf)
5808 lf.lfCharSet = DEFAULT_CHARSET;
5809 lf.lfPitchAndFamily = 0;
5810 lf.lfFaceName[0] = 0;
5811 plf = &lf;
5814 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5816 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5818 GDI_CheckNotLock();
5819 EnterCriticalSection( &freetype_cs );
5820 if(plf->lfFaceName[0]) {
5821 FontSubst *psub;
5822 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5824 if(psub) {
5825 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5826 debugstr_w(psub->to.name));
5827 lf = *plf;
5828 strcpyW(lf.lfFaceName, psub->to.name);
5829 plf = &lf;
5832 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5833 if (!family_matches(family, plf)) continue;
5834 face_list = get_face_list_from_family(family);
5835 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5836 if (!face_matches(family->FamilyName, face, plf)) continue;
5837 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5840 } else {
5841 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5842 face_list = get_face_list_from_family(family);
5843 face = LIST_ENTRY(list_head(face_list), Face, entry);
5844 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5847 LeaveCriticalSection( &freetype_cs );
5848 return TRUE;
5851 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5853 pt->x.value = vec->x >> 6;
5854 pt->x.fract = (vec->x & 0x3f) << 10;
5855 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5856 pt->y.value = vec->y >> 6;
5857 pt->y.fract = (vec->y & 0x3f) << 10;
5858 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5859 return;
5862 /***************************************************
5863 * According to the MSDN documentation on WideCharToMultiByte,
5864 * certain codepages cannot set the default_used parameter.
5865 * This returns TRUE if the codepage can set that parameter, false else
5866 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5868 static BOOL codepage_sets_default_used(UINT codepage)
5870 switch (codepage)
5872 case CP_UTF7:
5873 case CP_UTF8:
5874 case CP_SYMBOL:
5875 return FALSE;
5876 default:
5877 return TRUE;
5882 * GSUB Table handling functions
5885 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5887 const GSUB_CoverageFormat1* cf1;
5889 cf1 = table;
5891 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5893 int count = GET_BE_WORD(cf1->GlyphCount);
5894 int i;
5895 TRACE("Coverage Format 1, %i glyphs\n",count);
5896 for (i = 0; i < count; i++)
5897 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5898 return i;
5899 return -1;
5901 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5903 const GSUB_CoverageFormat2* cf2;
5904 int i;
5905 int count;
5906 cf2 = (const GSUB_CoverageFormat2*)cf1;
5908 count = GET_BE_WORD(cf2->RangeCount);
5909 TRACE("Coverage Format 2, %i ranges\n",count);
5910 for (i = 0; i < count; i++)
5912 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5913 return -1;
5914 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5915 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5917 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5918 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5921 return -1;
5923 else
5924 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5926 return -1;
5929 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5931 int i;
5932 int offset;
5933 const GSUB_LookupList *lookup;
5934 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5936 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5937 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5939 const GSUB_LookupTable *look;
5940 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5941 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5942 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5943 if (GET_BE_WORD(look->LookupType) != 1)
5944 FIXME("We only handle SubType 1\n");
5945 else
5947 int j;
5949 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5951 const GSUB_SingleSubstFormat1 *ssf1;
5952 offset = GET_BE_WORD(look->SubTable[j]);
5953 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5954 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5956 int offset = GET_BE_WORD(ssf1->Coverage);
5957 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5958 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5960 TRACE(" Glyph 0x%x ->",glyph);
5961 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5962 TRACE(" 0x%x\n",glyph);
5965 else
5967 const GSUB_SingleSubstFormat2 *ssf2;
5968 INT index;
5969 INT offset;
5971 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5972 offset = GET_BE_WORD(ssf1->Coverage);
5973 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5974 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5975 TRACE(" Coverage index %i\n",index);
5976 if (index != -1)
5978 TRACE(" Glyph is 0x%x ->",glyph);
5979 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5980 TRACE("0x%x\n",glyph);
5986 return glyph;
5990 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5992 const GSUB_Header *header;
5993 const GSUB_Feature *feature;
5995 if (!font->GSUB_Table)
5996 return glyph;
5998 header = font->GSUB_Table;
5999 feature = font->vert_feature;
6001 return GSUB_apply_feature(header, feature, glyph);
6004 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
6006 FT_UInt glyphId;
6008 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
6009 WCHAR wc = (WCHAR)glyph;
6010 BOOL default_used;
6011 BOOL *default_used_pointer;
6012 FT_UInt ret;
6013 char buf;
6014 default_used_pointer = NULL;
6015 default_used = FALSE;
6016 if (codepage_sets_default_used(font->codepage))
6017 default_used_pointer = &default_used;
6018 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
6020 if (font->codepage == CP_SYMBOL && wc < 0x100)
6021 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
6022 else
6023 ret = 0;
6025 else
6026 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
6027 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
6028 return ret;
6031 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
6033 if (glyph < 0x100) glyph += 0xf000;
6034 /* there is a number of old pre-Unicode "broken" TTFs, which
6035 do have symbols at U+00XX instead of U+f0XX */
6036 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
6037 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
6039 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
6041 return glyphId;
6044 static FT_UInt get_default_char_index(GdiFont *font)
6046 FT_UInt default_char;
6048 if (FT_IS_SFNT(font->ft_face))
6050 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
6051 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
6053 else
6055 TEXTMETRICW textm;
6056 get_text_metrics(font, &textm);
6057 default_char = textm.tmDefaultChar;
6060 return default_char;
6063 /*************************************************************
6064 * freetype_GetGlyphIndices
6066 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
6068 struct freetype_physdev *physdev = get_freetype_dev( dev );
6069 int i;
6070 WORD default_char;
6071 BOOL got_default = FALSE;
6073 if (!physdev->font)
6075 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
6076 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
6079 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
6081 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
6082 got_default = TRUE;
6085 GDI_CheckNotLock();
6086 EnterCriticalSection( &freetype_cs );
6088 for(i = 0; i < count; i++)
6090 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
6091 if (pgi[i] == 0)
6093 if (!got_default)
6095 default_char = get_default_char_index(physdev->font);
6096 got_default = TRUE;
6098 pgi[i] = default_char;
6100 else
6101 pgi[i] = get_GSUB_vert_glyph(physdev->font, pgi[i]);
6103 LeaveCriticalSection( &freetype_cs );
6104 return count;
6107 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
6109 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
6110 return !memcmp(matrix, &identity, sizeof(FMAT2));
6113 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
6115 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
6116 return !memcmp(matrix, &identity, sizeof(MAT2));
6119 static inline BYTE get_max_level( UINT format )
6121 switch( format )
6123 case GGO_GRAY2_BITMAP: return 4;
6124 case GGO_GRAY4_BITMAP: return 16;
6125 case GGO_GRAY8_BITMAP: return 64;
6127 return 255;
6130 static const struct { WCHAR lower; WCHAR upper;} unrotate_ranges[] =
6132 {0x0000, 0x10FF},
6133 /* Hangul Jamo */
6134 {0x1200, 0x17FF},
6135 /* Mongolian */
6136 {0x18B0, 0x1FFF},
6137 /* General Punctuation */
6138 {0x2070, 0x209F},
6139 /* Currency Symbols */
6140 /* Combining Diacritical Marks for Symbols */
6141 /* Letterlike Symbols */
6142 {0x2150, 0x245F},
6143 /* Enclosed Alphanumerics */
6144 {0x2500, 0x259F},
6145 /* Geometric Shapes */
6146 /* Miscellaneous Symbols */
6147 /* Dingbats */
6148 /* Miscellaneous Mathematical Symbols-A */
6149 /* Supplemental Arrows-A */
6150 {0x2800, 0x2E7F},
6151 /* East Asian scripts and symbols */
6152 {0xA000, 0xABFF},
6153 /* Hangul Syllables */
6154 /* Hangul Jamo Extended-B */
6155 {0xD800, 0xDFFF},
6156 /* Private Use Area */
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 GLYPHMETRICS gm;
6188 FT_Face ft_face = incoming_font->ft_face;
6189 GdiFont *font = incoming_font;
6190 FT_Glyph_Metrics metrics;
6191 FT_UInt glyph_index;
6192 DWORD width, height, pitch, needed = 0;
6193 FT_Bitmap ft_bitmap;
6194 FT_Error err;
6195 INT left, right, top = 0, bottom = 0, adv;
6196 INT origin_x = 0, origin_y = 0;
6197 FT_Angle angle = 0;
6198 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
6199 double widthRatio = 1.0;
6200 FT_Matrix transMat = identityMat;
6201 FT_Matrix transMatUnrotated;
6202 FT_Matrix transMatTategaki;
6203 BOOL needsTransform = FALSE;
6204 BOOL tategaki = (font->name[0] == '@');
6205 BOOL vertical_metrics;
6206 UINT original_index;
6207 LONG avgAdvance = 0;
6208 FT_Fixed em_scale;
6210 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
6211 buflen, buf, lpmat);
6213 TRACE("font transform %f %f %f %f\n",
6214 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
6215 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
6217 if(format & GGO_GLYPH_INDEX) {
6218 glyph_index = glyph;
6219 original_index = glyph;
6220 format &= ~GGO_GLYPH_INDEX;
6221 /* TODO: Window also turns off tategaki for glyphs passed in by index
6222 if their unicode code points fall outside of the range that is
6223 rotated. */
6224 } else {
6225 BOOL vert;
6226 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index, &vert);
6227 ft_face = font->ft_face;
6228 original_index = glyph_index;
6229 /* We know what unicode ranges get rotated */
6230 if (!vert && tategaki)
6231 tategaki = check_unicode_tategaki(glyph);
6234 if(format & GGO_UNHINTED) {
6235 load_flags |= FT_LOAD_NO_HINTING;
6236 format &= ~GGO_UNHINTED;
6239 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
6240 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
6241 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
6242 font->gmsize * sizeof(GM*));
6243 } else {
6244 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
6245 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
6247 *lpgm = FONT_GM(font,original_index)->gm;
6248 *abc = FONT_GM(font,original_index)->abc;
6249 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6250 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6251 lpgm->gmCellIncX, lpgm->gmCellIncY);
6252 return 1; /* FIXME */
6256 if (!font->gm[original_index / GM_BLOCK_SIZE])
6257 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
6259 /* Scaling factor */
6260 if (font->aveWidth)
6262 TEXTMETRICW tm;
6264 get_text_metrics(font, &tm);
6266 widthRatio = (double)font->aveWidth;
6267 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6269 else
6270 widthRatio = font->scale_y;
6272 /* Scaling transform */
6273 if (widthRatio != 1.0 || font->scale_y != 1.0)
6275 FT_Matrix scaleMat;
6276 scaleMat.xx = FT_FixedFromFloat(widthRatio);
6277 scaleMat.xy = 0;
6278 scaleMat.yx = 0;
6279 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
6281 pFT_Matrix_Multiply(&scaleMat, &transMat);
6282 needsTransform = TRUE;
6285 /* Slant transform */
6286 if (font->fake_italic) {
6287 FT_Matrix slantMat;
6289 slantMat.xx = (1 << 16);
6290 slantMat.xy = ((1 << 16) >> 2);
6291 slantMat.yx = 0;
6292 slantMat.yy = (1 << 16);
6293 pFT_Matrix_Multiply(&slantMat, &transMat);
6294 needsTransform = TRUE;
6297 /* Rotation transform */
6298 transMatUnrotated = transMat;
6299 transMatTategaki = transMat;
6300 if(font->orientation || tategaki) {
6301 FT_Matrix rotationMat;
6302 FT_Matrix taterotationMat;
6303 FT_Vector vecAngle;
6305 double orient = font->orientation / 10.0;
6306 double tate_orient = 0.f;
6308 if (tategaki)
6309 tate_orient = ((font->orientation+900)%3600)/10.0;
6310 else
6311 tate_orient = font->orientation/10.0;
6313 if (orient)
6315 angle = FT_FixedFromFloat(orient);
6316 pFT_Vector_Unit(&vecAngle, angle);
6317 rotationMat.xx = vecAngle.x;
6318 rotationMat.xy = -vecAngle.y;
6319 rotationMat.yx = -rotationMat.xy;
6320 rotationMat.yy = rotationMat.xx;
6322 pFT_Matrix_Multiply(&rotationMat, &transMat);
6325 if (tate_orient)
6327 angle = FT_FixedFromFloat(tate_orient);
6328 pFT_Vector_Unit(&vecAngle, angle);
6329 taterotationMat.xx = vecAngle.x;
6330 taterotationMat.xy = -vecAngle.y;
6331 taterotationMat.yx = -taterotationMat.xy;
6332 taterotationMat.yy = taterotationMat.xx;
6333 pFT_Matrix_Multiply(&taterotationMat, &transMatTategaki);
6336 needsTransform = TRUE;
6339 /* World transform */
6340 if (!is_identity_FMAT2(&font->font_desc.matrix))
6342 FT_Matrix worldMat;
6343 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
6344 worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21);
6345 worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12);
6346 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
6347 pFT_Matrix_Multiply(&worldMat, &transMat);
6348 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
6349 pFT_Matrix_Multiply(&worldMat, &transMatTategaki);
6350 needsTransform = TRUE;
6353 /* Extra transformation specified by caller */
6354 if (!is_identity_MAT2(lpmat))
6356 FT_Matrix extraMat;
6357 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
6358 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
6359 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
6360 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
6361 pFT_Matrix_Multiply(&extraMat, &transMat);
6362 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
6363 pFT_Matrix_Multiply(&extraMat, &transMatTategaki);
6364 needsTransform = TRUE;
6367 vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face));
6368 /* there is a freetype bug where vertical metrics are only
6369 properly scaled and correct in 2.4.0 or greater */
6370 if ((vertical_metrics) && (FT_Version.major < 2 || (FT_Version.major == 2 && FT_Version.minor < 4)))
6371 vertical_metrics = FALSE;
6373 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
6374 if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
6376 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
6378 if(err) {
6379 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
6380 return GDI_ERROR;
6383 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6384 * by the text metrics. The proper behavior is to clip the glyph metrics to
6385 * fit within the maximums specified in the text metrics. */
6386 metrics = ft_face->glyph->metrics;
6387 if(incoming_font->potm || get_outline_text_metrics(incoming_font) ||
6388 get_bitmap_text_metrics(incoming_font)) {
6389 TEXTMETRICW *ptm = &incoming_font->potm->otmTextMetrics;
6390 top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
6391 bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
6392 metrics.horiBearingY = top;
6393 metrics.height = top - bottom;
6395 /* TODO: Are we supposed to clip the width as well...? */
6396 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6399 if(FT_IS_SCALABLE(incoming_font->ft_face)) {
6400 TEXTMETRICW tm;
6401 if (get_text_metrics(incoming_font, &tm) &&
6402 !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
6403 em_scale = MulDiv(incoming_font->ppem, 1 << 16, incoming_font->ft_face->units_per_EM);
6404 avgAdvance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
6405 if (avgAdvance &&
6406 (metrics.horiAdvance+63) >> 6 == pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale))
6407 TRACE("Fixed-pitch full-width character detected\n");
6408 else
6409 avgAdvance = 0; /* cancel this feature */
6413 if(!needsTransform) {
6414 left = (INT)(metrics.horiBearingX) & -64;
6415 right = (INT)((metrics.horiBearingX + metrics.width) + 63) & -64;
6416 if (!avgAdvance)
6417 adv = (INT)(metrics.horiAdvance + 63) >> 6;
6418 else
6419 adv = (INT)avgAdvance * 2;
6421 top = (metrics.horiBearingY + 63) & -64;
6422 bottom = (metrics.horiBearingY - metrics.height) & -64;
6423 gm.gmCellIncX = adv;
6424 gm.gmCellIncY = 0;
6425 origin_x = left;
6426 origin_y = top;
6427 } else {
6428 INT xc, yc;
6429 FT_Vector vec;
6431 left = right = 0;
6433 for(xc = 0; xc < 2; xc++) {
6434 for(yc = 0; yc < 2; yc++) {
6435 vec.x = metrics.horiBearingX + xc * metrics.width;
6436 vec.y = metrics.horiBearingY - yc * metrics.height;
6437 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
6438 pFT_Vector_Transform(&vec, &transMatTategaki);
6439 if(xc == 0 && yc == 0) {
6440 left = right = vec.x;
6441 top = bottom = vec.y;
6442 } else {
6443 if(vec.x < left) left = vec.x;
6444 else if(vec.x > right) right = vec.x;
6445 if(vec.y < bottom) bottom = vec.y;
6446 else if(vec.y > top) top = vec.y;
6450 left = left & -64;
6451 right = (right + 63) & -64;
6452 bottom = bottom & -64;
6453 top = (top + 63) & -64;
6455 if (tategaki)
6457 for(xc = 0; xc < 2; xc++)
6459 for(yc = 0; yc < 2; yc++)
6461 if (vertical_metrics)
6463 vec.x = metrics.vertBearingY + xc * metrics.height;
6464 vec.y = metrics.horiBearingX - yc * (metrics.vertBearingX * 2);
6466 else
6468 vec.x = metrics.horiBearingY - xc * metrics.height;
6469 vec.y = metrics.horiBearingX + yc * metrics.width;
6472 TRACE ("Vec %ld,%ld\n", vec.x>>6, vec.y>>6);
6473 pFT_Vector_Transform(&vec, &transMat);
6474 if(xc == 0 && yc == 0) {
6475 origin_x = vec.x;
6476 origin_y = vec.y;
6477 } else {
6478 if(vec.x < origin_x) origin_x = vec.x;
6479 if(vec.y > origin_y) origin_y = vec.y;
6483 origin_x = origin_x & -64;
6484 origin_y = (origin_y + 63) & -64;
6486 else
6488 origin_x = left;
6489 origin_y = top;
6492 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
6493 vec.x = metrics.horiAdvance;
6494 vec.y = 0;
6495 pFT_Vector_Transform(&vec, &transMat);
6496 gm.gmCellIncY = -((vec.y+63) >> 6);
6497 if (!avgAdvance || vec.y)
6498 gm.gmCellIncX = (vec.x+63) >> 6;
6499 else {
6500 vec.x = incoming_font->ntmAvgWidth;
6501 vec.y = 0;
6502 pFT_Vector_Transform(&vec, &transMat);
6503 gm.gmCellIncX = pFT_MulFix(vec.x, em_scale) * 2;
6506 if (vertical_metrics)
6507 vec.x = metrics.vertAdvance;
6508 else
6509 vec.x = metrics.horiAdvance;
6510 vec.y = 0;
6511 pFT_Vector_Transform(&vec, &transMatUnrotated);
6512 if (!avgAdvance || vec.y)
6513 adv = (vec.x+63) >> 6;
6514 else {
6515 vec.x = incoming_font->ntmAvgWidth;
6516 vec.y = 0;
6517 pFT_Vector_Transform(&vec, &transMatUnrotated);
6518 adv = pFT_MulFix(vec.x, em_scale) * 2;
6522 width = (right - left) >> 6;
6523 height = (top - bottom) >> 6;
6524 gm.gmBlackBoxX = width ? width : 1;
6525 gm.gmBlackBoxY = height ? height : 1;
6526 gm.gmptGlyphOrigin.x = origin_x >> 6;
6527 gm.gmptGlyphOrigin.y = origin_y >> 6;
6528 abc->abcA = left >> 6;
6529 abc->abcB = gm.gmBlackBoxX;
6530 abc->abcC = adv - abc->abcA - abc->abcB;
6532 TRACE("%u,%u,%s,%d,%d\n", gm.gmBlackBoxX, gm.gmBlackBoxY,
6533 wine_dbgstr_point(&gm.gmptGlyphOrigin),
6534 gm.gmCellIncX, gm.gmCellIncY);
6536 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
6537 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
6539 FONT_GM(font,original_index)->gm = gm;
6540 FONT_GM(font,original_index)->abc = *abc;
6541 FONT_GM(font,original_index)->init = TRUE;
6544 if(format == GGO_METRICS)
6546 *lpgm = gm;
6547 return 1; /* FIXME */
6550 if(ft_face->glyph->format != ft_glyph_format_outline &&
6551 (format == GGO_NATIVE || format == GGO_BEZIER))
6553 TRACE("loaded a bitmap\n");
6554 return GDI_ERROR;
6557 switch(format) {
6558 case GGO_BITMAP:
6559 pitch = ((width + 31) >> 5) << 2;
6560 needed = pitch * height;
6562 if(!buf || !buflen) break;
6563 if (!needed) return GDI_ERROR; /* empty glyph */
6565 switch(ft_face->glyph->format) {
6566 case ft_glyph_format_bitmap:
6568 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6569 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
6570 INT h = min( height, ft_face->glyph->bitmap.rows );
6571 while(h--) {
6572 memcpy(dst, src, w);
6573 src += ft_face->glyph->bitmap.pitch;
6574 dst += pitch;
6576 break;
6579 case ft_glyph_format_outline:
6580 ft_bitmap.width = width;
6581 ft_bitmap.rows = height;
6582 ft_bitmap.pitch = pitch;
6583 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
6584 ft_bitmap.buffer = buf;
6586 if(needsTransform)
6587 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
6589 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6591 /* Note: FreeType will only set 'black' bits for us. */
6592 memset(buf, 0, needed);
6593 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6594 break;
6596 default:
6597 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6598 return GDI_ERROR;
6600 break;
6602 case GGO_GRAY2_BITMAP:
6603 case GGO_GRAY4_BITMAP:
6604 case GGO_GRAY8_BITMAP:
6605 case WINE_GGO_GRAY16_BITMAP:
6607 unsigned int max_level, row, col;
6608 BYTE *start, *ptr;
6610 pitch = (width + 3) / 4 * 4;
6611 needed = pitch * height;
6613 if(!buf || !buflen) break;
6614 if (!needed) return GDI_ERROR; /* empty glyph */
6616 max_level = get_max_level( format );
6618 switch(ft_face->glyph->format) {
6619 case ft_glyph_format_bitmap:
6621 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6622 INT h = min( height, ft_face->glyph->bitmap.rows );
6623 INT x;
6624 memset( buf, 0, needed );
6625 while(h--) {
6626 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
6627 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
6628 src += ft_face->glyph->bitmap.pitch;
6629 dst += pitch;
6631 break;
6633 case ft_glyph_format_outline:
6635 ft_bitmap.width = width;
6636 ft_bitmap.rows = height;
6637 ft_bitmap.pitch = pitch;
6638 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6639 ft_bitmap.buffer = buf;
6641 if(needsTransform)
6642 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
6644 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6646 memset(ft_bitmap.buffer, 0, buflen);
6648 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6650 if (max_level != 255)
6652 for (row = 0, start = buf; row < height; row++)
6654 for (col = 0, ptr = start; col < width; col++, ptr++)
6655 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6656 start += pitch;
6659 break;
6662 default:
6663 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6664 return GDI_ERROR;
6666 break;
6669 case WINE_GGO_HRGB_BITMAP:
6670 case WINE_GGO_HBGR_BITMAP:
6671 case WINE_GGO_VRGB_BITMAP:
6672 case WINE_GGO_VBGR_BITMAP:
6673 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6675 switch (ft_face->glyph->format)
6677 case FT_GLYPH_FORMAT_BITMAP:
6679 BYTE *src, *dst;
6680 INT src_pitch, x;
6682 pitch = width * 4;
6683 needed = pitch * height;
6685 if (!buf || !buflen) break;
6686 if (!needed) return GDI_ERROR; /* empty glyph */
6688 memset(buf, 0, buflen);
6689 dst = buf;
6690 src = ft_face->glyph->bitmap.buffer;
6691 src_pitch = ft_face->glyph->bitmap.pitch;
6693 height = min( height, ft_face->glyph->bitmap.rows );
6694 while ( height-- )
6696 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6698 if ( src[x / 8] & masks[x % 8] )
6699 ((unsigned int *)dst)[x] = ~0u;
6701 src += src_pitch;
6702 dst += pitch;
6705 break;
6708 case FT_GLYPH_FORMAT_OUTLINE:
6710 unsigned int *dst;
6711 BYTE *src;
6712 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6713 INT x_shift, y_shift;
6714 BOOL rgb;
6715 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6716 FT_Render_Mode render_mode =
6717 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6718 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6720 if (!width || !height)
6722 if (!buf || !buflen) break;
6723 return GDI_ERROR;
6726 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6728 if ( render_mode == FT_RENDER_MODE_LCD)
6730 gm.gmBlackBoxX += 2;
6731 gm.gmptGlyphOrigin.x -= 1;
6733 else
6735 gm.gmBlackBoxY += 2;
6736 gm.gmptGlyphOrigin.y += 1;
6740 width = gm.gmBlackBoxX;
6741 height = gm.gmBlackBoxY;
6742 pitch = width * 4;
6743 needed = pitch * height;
6745 if (!buf || !buflen) break;
6747 memset(buf, 0, buflen);
6748 dst = buf;
6749 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6751 if ( needsTransform )
6752 pFT_Outline_Transform (&ft_face->glyph->outline, &transMatTategaki);
6754 if ( pFT_Library_SetLcdFilter )
6755 pFT_Library_SetLcdFilter( library, lcdfilter );
6756 pFT_Render_Glyph (ft_face->glyph, render_mode);
6758 src = ft_face->glyph->bitmap.buffer;
6759 src_pitch = ft_face->glyph->bitmap.pitch;
6760 src_width = ft_face->glyph->bitmap.width;
6761 src_height = ft_face->glyph->bitmap.rows;
6763 if ( render_mode == FT_RENDER_MODE_LCD)
6765 rgb_interval = 1;
6766 hmul = 3;
6767 vmul = 1;
6769 else
6771 rgb_interval = src_pitch;
6772 hmul = 1;
6773 vmul = 3;
6776 x_shift = ft_face->glyph->bitmap_left - gm.gmptGlyphOrigin.x;
6777 if ( x_shift < 0 )
6779 src += hmul * -x_shift;
6780 src_width -= hmul * -x_shift;
6782 else if ( x_shift > 0 )
6784 dst += x_shift;
6785 width -= x_shift;
6788 y_shift = gm.gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6789 if ( y_shift < 0 )
6791 src += src_pitch * vmul * -y_shift;
6792 src_height -= vmul * -y_shift;
6794 else if ( y_shift > 0 )
6796 dst += y_shift * ( pitch / sizeof(*dst) );
6797 height -= y_shift;
6800 width = min( width, src_width / hmul );
6801 height = min( height, src_height / vmul );
6803 while ( height-- )
6805 for ( x = 0; x < width; x++ )
6807 if ( rgb )
6809 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6810 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6811 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6812 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6814 else
6816 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6817 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6818 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6819 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6822 src += src_pitch * vmul;
6823 dst += pitch / sizeof(*dst);
6826 break;
6829 default:
6830 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6831 return GDI_ERROR;
6834 break;
6836 #else
6837 return GDI_ERROR;
6838 #endif
6840 case GGO_NATIVE:
6842 int contour, point = 0, first_pt;
6843 FT_Outline *outline = &ft_face->glyph->outline;
6844 TTPOLYGONHEADER *pph;
6845 TTPOLYCURVE *ppc;
6846 DWORD pph_start, cpfx, type;
6848 if(buflen == 0) buf = NULL;
6850 if (needsTransform && buf) {
6851 pFT_Outline_Transform(outline, &transMatTategaki);
6854 for(contour = 0; contour < outline->n_contours; contour++) {
6855 /* Ignore contours containing one point */
6856 if(point == outline->contours[contour]) {
6857 point++;
6858 continue;
6861 pph_start = needed;
6862 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6863 first_pt = point;
6864 if(buf) {
6865 pph->dwType = TT_POLYGON_TYPE;
6866 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6868 needed += sizeof(*pph);
6869 point++;
6870 while(point <= outline->contours[contour]) {
6871 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6872 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6873 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6874 cpfx = 0;
6875 do {
6876 if(buf)
6877 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6878 cpfx++;
6879 point++;
6880 } while(point <= outline->contours[contour] &&
6881 (outline->tags[point] & FT_Curve_Tag_On) ==
6882 (outline->tags[point-1] & FT_Curve_Tag_On));
6883 /* At the end of a contour Windows adds the start point, but
6884 only for Beziers */
6885 if(point > outline->contours[contour] &&
6886 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6887 if(buf)
6888 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6889 cpfx++;
6890 } else if(point <= outline->contours[contour] &&
6891 outline->tags[point] & FT_Curve_Tag_On) {
6892 /* add closing pt for bezier */
6893 if(buf)
6894 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6895 cpfx++;
6896 point++;
6898 if(buf) {
6899 ppc->wType = type;
6900 ppc->cpfx = cpfx;
6902 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6904 if(buf)
6905 pph->cb = needed - pph_start;
6907 break;
6909 case GGO_BEZIER:
6911 /* Convert the quadratic Beziers to cubic Beziers.
6912 The parametric eqn for a cubic Bezier is, from PLRM:
6913 r(t) = at^3 + bt^2 + ct + r0
6914 with the control points:
6915 r1 = r0 + c/3
6916 r2 = r1 + (c + b)/3
6917 r3 = r0 + c + b + a
6919 A quadratic Bezier has the form:
6920 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6922 So equating powers of t leads to:
6923 r1 = 2/3 p1 + 1/3 p0
6924 r2 = 2/3 p1 + 1/3 p2
6925 and of course r0 = p0, r3 = p2
6928 int contour, point = 0, first_pt;
6929 FT_Outline *outline = &ft_face->glyph->outline;
6930 TTPOLYGONHEADER *pph;
6931 TTPOLYCURVE *ppc;
6932 DWORD pph_start, cpfx, type;
6933 FT_Vector cubic_control[4];
6934 if(buflen == 0) buf = NULL;
6936 if (needsTransform && buf) {
6937 pFT_Outline_Transform(outline, &transMat);
6940 for(contour = 0; contour < outline->n_contours; contour++) {
6941 pph_start = needed;
6942 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6943 first_pt = point;
6944 if(buf) {
6945 pph->dwType = TT_POLYGON_TYPE;
6946 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6948 needed += sizeof(*pph);
6949 point++;
6950 while(point <= outline->contours[contour]) {
6951 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6952 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6953 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6954 cpfx = 0;
6955 do {
6956 if(type == TT_PRIM_LINE) {
6957 if(buf)
6958 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6959 cpfx++;
6960 point++;
6961 } else {
6962 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6963 so cpfx = 3n */
6965 /* FIXME: Possible optimization in endpoint calculation
6966 if there are two consecutive curves */
6967 cubic_control[0] = outline->points[point-1];
6968 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6969 cubic_control[0].x += outline->points[point].x + 1;
6970 cubic_control[0].y += outline->points[point].y + 1;
6971 cubic_control[0].x >>= 1;
6972 cubic_control[0].y >>= 1;
6974 if(point+1 > outline->contours[contour])
6975 cubic_control[3] = outline->points[first_pt];
6976 else {
6977 cubic_control[3] = outline->points[point+1];
6978 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6979 cubic_control[3].x += outline->points[point].x + 1;
6980 cubic_control[3].y += outline->points[point].y + 1;
6981 cubic_control[3].x >>= 1;
6982 cubic_control[3].y >>= 1;
6985 /* r1 = 1/3 p0 + 2/3 p1
6986 r2 = 1/3 p2 + 2/3 p1 */
6987 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6988 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6989 cubic_control[2] = cubic_control[1];
6990 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6991 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6992 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6993 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6994 if(buf) {
6995 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6996 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6997 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6999 cpfx += 3;
7000 point++;
7002 } while(point <= outline->contours[contour] &&
7003 (outline->tags[point] & FT_Curve_Tag_On) ==
7004 (outline->tags[point-1] & FT_Curve_Tag_On));
7005 /* At the end of a contour Windows adds the start point,
7006 but only for Beziers and we've already done that.
7008 if(point <= outline->contours[contour] &&
7009 outline->tags[point] & FT_Curve_Tag_On) {
7010 /* This is the closing pt of a bezier, but we've already
7011 added it, so just inc point and carry on */
7012 point++;
7014 if(buf) {
7015 ppc->wType = type;
7016 ppc->cpfx = cpfx;
7018 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
7020 if(buf)
7021 pph->cb = needed - pph_start;
7023 break;
7026 default:
7027 FIXME("Unsupported format %d\n", format);
7028 return GDI_ERROR;
7030 *lpgm = gm;
7031 return needed;
7034 static BOOL get_bitmap_text_metrics(GdiFont *font)
7036 FT_Face ft_face = font->ft_face;
7037 FT_WinFNT_HeaderRec winfnt_header;
7038 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
7039 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
7040 font->potm->otmSize = size;
7042 #define TM font->potm->otmTextMetrics
7043 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
7045 TM.tmHeight = winfnt_header.pixel_height;
7046 TM.tmAscent = winfnt_header.ascent;
7047 TM.tmDescent = TM.tmHeight - TM.tmAscent;
7048 TM.tmInternalLeading = winfnt_header.internal_leading;
7049 TM.tmExternalLeading = winfnt_header.external_leading;
7050 TM.tmAveCharWidth = winfnt_header.avg_width;
7051 TM.tmMaxCharWidth = winfnt_header.max_width;
7052 TM.tmWeight = winfnt_header.weight;
7053 TM.tmOverhang = 0;
7054 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
7055 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
7056 TM.tmFirstChar = winfnt_header.first_char;
7057 TM.tmLastChar = winfnt_header.last_char;
7058 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
7059 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
7060 TM.tmItalic = winfnt_header.italic;
7061 TM.tmUnderlined = font->underline;
7062 TM.tmStruckOut = font->strikeout;
7063 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
7064 TM.tmCharSet = winfnt_header.charset;
7066 else
7068 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
7069 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
7070 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7071 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
7072 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
7073 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
7074 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
7075 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
7076 TM.tmOverhang = 0;
7077 TM.tmDigitizedAspectX = 96; /* FIXME */
7078 TM.tmDigitizedAspectY = 96; /* FIXME */
7079 TM.tmFirstChar = 1;
7080 TM.tmLastChar = 255;
7081 TM.tmDefaultChar = 32;
7082 TM.tmBreakChar = 32;
7083 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
7084 TM.tmUnderlined = font->underline;
7085 TM.tmStruckOut = font->strikeout;
7086 /* NB inverted meaning of TMPF_FIXED_PITCH */
7087 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
7088 TM.tmCharSet = font->charset;
7090 #undef TM
7092 return TRUE;
7096 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
7098 double scale_x, scale_y;
7100 if (font->aveWidth)
7102 scale_x = (double)font->aveWidth;
7103 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7105 else
7106 scale_x = font->scale_y;
7108 scale_x *= fabs(font->font_desc.matrix.eM11);
7109 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7111 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7112 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7114 SCALE_Y(ptm->tmHeight);
7115 SCALE_Y(ptm->tmAscent);
7116 SCALE_Y(ptm->tmDescent);
7117 SCALE_Y(ptm->tmInternalLeading);
7118 SCALE_Y(ptm->tmExternalLeading);
7119 SCALE_Y(ptm->tmOverhang);
7121 SCALE_X(ptm->tmAveCharWidth);
7122 SCALE_X(ptm->tmMaxCharWidth);
7124 #undef SCALE_X
7125 #undef SCALE_Y
7128 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
7130 double scale_x, scale_y;
7132 if (font->aveWidth)
7134 scale_x = (double)font->aveWidth;
7135 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7137 else
7138 scale_x = font->scale_y;
7140 scale_x *= fabs(font->font_desc.matrix.eM11);
7141 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7143 scale_font_metrics(font, &potm->otmTextMetrics);
7145 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7146 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7148 SCALE_Y(potm->otmAscent);
7149 SCALE_Y(potm->otmDescent);
7150 SCALE_Y(potm->otmLineGap);
7151 SCALE_Y(potm->otmsCapEmHeight);
7152 SCALE_Y(potm->otmsXHeight);
7153 SCALE_Y(potm->otmrcFontBox.top);
7154 SCALE_Y(potm->otmrcFontBox.bottom);
7155 SCALE_X(potm->otmrcFontBox.left);
7156 SCALE_X(potm->otmrcFontBox.right);
7157 SCALE_Y(potm->otmMacAscent);
7158 SCALE_Y(potm->otmMacDescent);
7159 SCALE_Y(potm->otmMacLineGap);
7160 SCALE_X(potm->otmptSubscriptSize.x);
7161 SCALE_Y(potm->otmptSubscriptSize.y);
7162 SCALE_X(potm->otmptSubscriptOffset.x);
7163 SCALE_Y(potm->otmptSubscriptOffset.y);
7164 SCALE_X(potm->otmptSuperscriptSize.x);
7165 SCALE_Y(potm->otmptSuperscriptSize.y);
7166 SCALE_X(potm->otmptSuperscriptOffset.x);
7167 SCALE_Y(potm->otmptSuperscriptOffset.y);
7168 SCALE_Y(potm->otmsStrikeoutSize);
7169 SCALE_Y(potm->otmsStrikeoutPosition);
7170 SCALE_Y(potm->otmsUnderscoreSize);
7171 SCALE_Y(potm->otmsUnderscorePosition);
7173 #undef SCALE_X
7174 #undef SCALE_Y
7177 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
7179 if(!font->potm)
7181 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
7183 /* Make sure that the font has sane width/height ratio */
7184 if (font->aveWidth)
7186 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
7188 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
7189 font->aveWidth = 0;
7193 *ptm = font->potm->otmTextMetrics;
7194 scale_font_metrics(font, ptm);
7195 return TRUE;
7198 static BOOL face_has_symbol_charmap(FT_Face ft_face)
7200 int i;
7202 for(i = 0; i < ft_face->num_charmaps; i++)
7204 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
7205 return TRUE;
7207 return FALSE;
7210 static BOOL get_outline_text_metrics(GdiFont *font)
7212 BOOL ret = FALSE;
7213 FT_Face ft_face = font->ft_face;
7214 UINT needed, lenfam, lensty, lenface, lenfull;
7215 TT_OS2 *pOS2;
7216 TT_HoriHeader *pHori;
7217 TT_Postscript *pPost;
7218 FT_Fixed em_scale;
7219 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
7220 char *cp;
7221 INT ascent, descent;
7223 TRACE("font=%p\n", font);
7225 if(!FT_IS_SCALABLE(ft_face))
7226 return FALSE;
7228 needed = sizeof(*font->potm);
7230 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
7231 family_nameW = strdupW(font->name);
7233 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
7234 if (!style_nameW)
7236 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
7237 style_nameW = towstr( CP_ACP, ft_face->style_name );
7239 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
7241 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
7242 if (!face_nameW)
7244 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
7245 face_nameW = strdupW(font->name);
7247 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
7248 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
7250 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
7251 if (!full_nameW)
7253 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
7254 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
7255 full_nameW = strdupW(fake_nameW);
7257 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
7259 /* These names should be read from the TT name table */
7261 /* length of otmpFamilyName */
7262 needed += lenfam;
7264 /* length of otmpFaceName */
7265 needed += lenface;
7267 /* length of otmpStyleName */
7268 needed += lensty;
7270 /* length of otmpFullName */
7271 needed += lenfull;
7274 em_scale = (FT_Fixed)MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
7276 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
7277 if(!pOS2) {
7278 FIXME("Can't find OS/2 table - not TT font?\n");
7279 goto end;
7282 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
7283 if(!pHori) {
7284 FIXME("Can't find HHEA table - not TT font?\n");
7285 goto end;
7288 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
7290 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",
7291 pOS2->usWinAscent, pOS2->usWinDescent,
7292 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
7293 pOS2->xAvgCharWidth,
7294 ft_face->ascender, ft_face->descender, ft_face->height,
7295 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
7296 ft_face->bbox.yMax, ft_face->bbox.yMin);
7298 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
7299 font->potm->otmSize = needed;
7301 #define TM font->potm->otmTextMetrics
7303 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
7304 ascent = pHori->Ascender;
7305 descent = -pHori->Descender;
7306 } else {
7307 ascent = pOS2->usWinAscent;
7308 descent = pOS2->usWinDescent;
7311 font->ntmCellHeight = ascent + descent;
7312 font->ntmAvgWidth = pOS2->xAvgCharWidth;
7314 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7315 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7317 if(font->yMax) {
7318 TM.tmAscent = font->yMax;
7319 TM.tmDescent = -font->yMin;
7320 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
7321 } else {
7322 TM.tmAscent = SCALE_Y(ascent);
7323 TM.tmDescent = SCALE_Y(descent);
7324 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
7327 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7329 /* MSDN says:
7330 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7332 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
7333 ((ascent + descent) -
7334 (pHori->Ascender - pHori->Descender))));
7336 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
7337 if (TM.tmAveCharWidth == 0) {
7338 TM.tmAveCharWidth = 1;
7340 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
7341 TM.tmWeight = FW_REGULAR;
7342 if (font->fake_bold)
7343 TM.tmWeight = FW_BOLD;
7344 else
7346 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
7348 if (pOS2->usWeightClass > FW_MEDIUM)
7349 TM.tmWeight = pOS2->usWeightClass;
7351 else if (pOS2->usWeightClass <= FW_MEDIUM)
7352 TM.tmWeight = pOS2->usWeightClass;
7354 TM.tmOverhang = 0;
7355 TM.tmDigitizedAspectX = 96; /* FIXME */
7356 TM.tmDigitizedAspectY = 96; /* FIXME */
7357 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7358 * symbol range to 0 - f0ff
7361 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
7363 TM.tmFirstChar = 0;
7364 switch(GetACP())
7366 case 1257: /* Baltic */
7367 TM.tmLastChar = 0xf8fd;
7368 break;
7369 default:
7370 TM.tmLastChar = 0xf0ff;
7372 TM.tmBreakChar = 0x20;
7373 TM.tmDefaultChar = 0x1f;
7375 else
7377 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
7378 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
7380 if(pOS2->usFirstCharIndex <= 1)
7381 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
7382 else if (pOS2->usFirstCharIndex > 0xff)
7383 TM.tmBreakChar = 0x20;
7384 else
7385 TM.tmBreakChar = pOS2->usFirstCharIndex;
7386 TM.tmDefaultChar = TM.tmBreakChar - 1;
7388 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
7389 TM.tmUnderlined = font->underline;
7390 TM.tmStruckOut = font->strikeout;
7392 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7393 if(!FT_IS_FIXED_WIDTH(ft_face) &&
7394 (pOS2->version == 0xFFFFU ||
7395 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
7396 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
7397 else
7398 TM.tmPitchAndFamily = 0;
7400 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
7402 case PAN_FAMILY_SCRIPT:
7403 TM.tmPitchAndFamily |= FF_SCRIPT;
7404 break;
7406 case PAN_FAMILY_DECORATIVE:
7407 TM.tmPitchAndFamily |= FF_DECORATIVE;
7408 break;
7410 case PAN_ANY:
7411 case PAN_NO_FIT:
7412 case PAN_FAMILY_TEXT_DISPLAY:
7413 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
7414 /* which is clearly not what the panose spec says. */
7415 default:
7416 if(TM.tmPitchAndFamily == 0 || /* fixed */
7417 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
7418 TM.tmPitchAndFamily = FF_MODERN;
7419 else
7421 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
7423 case PAN_ANY:
7424 case PAN_NO_FIT:
7425 default:
7426 TM.tmPitchAndFamily |= FF_DONTCARE;
7427 break;
7429 case PAN_SERIF_COVE:
7430 case PAN_SERIF_OBTUSE_COVE:
7431 case PAN_SERIF_SQUARE_COVE:
7432 case PAN_SERIF_OBTUSE_SQUARE_COVE:
7433 case PAN_SERIF_SQUARE:
7434 case PAN_SERIF_THIN:
7435 case PAN_SERIF_BONE:
7436 case PAN_SERIF_EXAGGERATED:
7437 case PAN_SERIF_TRIANGLE:
7438 TM.tmPitchAndFamily |= FF_ROMAN;
7439 break;
7441 case PAN_SERIF_NORMAL_SANS:
7442 case PAN_SERIF_OBTUSE_SANS:
7443 case PAN_SERIF_PERP_SANS:
7444 case PAN_SERIF_FLARED:
7445 case PAN_SERIF_ROUNDED:
7446 TM.tmPitchAndFamily |= FF_SWISS;
7447 break;
7450 break;
7453 if(FT_IS_SCALABLE(ft_face))
7454 TM.tmPitchAndFamily |= TMPF_VECTOR;
7456 if(FT_IS_SFNT(ft_face))
7458 if (font->ntmFlags & NTM_PS_OPENTYPE)
7459 TM.tmPitchAndFamily |= TMPF_DEVICE;
7460 else
7461 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
7464 TM.tmCharSet = font->charset;
7466 font->potm->otmFiller = 0;
7467 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
7468 font->potm->otmfsSelection = pOS2->fsSelection;
7469 font->potm->otmfsType = pOS2->fsType;
7470 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
7471 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
7472 font->potm->otmItalicAngle = 0; /* POST table */
7473 font->potm->otmEMSquare = ft_face->units_per_EM;
7474 font->potm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
7475 font->potm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
7476 font->potm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
7477 font->potm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
7478 font->potm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
7479 font->potm->otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
7480 font->potm->otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
7481 font->potm->otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
7482 font->potm->otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
7483 font->potm->otmMacAscent = TM.tmAscent;
7484 font->potm->otmMacDescent = -TM.tmDescent;
7485 font->potm->otmMacLineGap = font->potm->otmLineGap;
7486 font->potm->otmusMinimumPPEM = 0; /* TT Header */
7487 font->potm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
7488 font->potm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
7489 font->potm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
7490 font->potm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
7491 font->potm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
7492 font->potm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
7493 font->potm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
7494 font->potm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
7495 font->potm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
7496 font->potm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
7497 if(!pPost) {
7498 font->potm->otmsUnderscoreSize = 0;
7499 font->potm->otmsUnderscorePosition = 0;
7500 } else {
7501 font->potm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
7502 font->potm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
7504 #undef SCALE_X
7505 #undef SCALE_Y
7506 #undef TM
7508 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7509 cp = (char*)font->potm + sizeof(*font->potm);
7510 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
7511 strcpyW((WCHAR*)cp, family_nameW);
7512 cp += lenfam;
7513 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
7514 strcpyW((WCHAR*)cp, style_nameW);
7515 cp += lensty;
7516 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7517 strcpyW((WCHAR*)cp, face_nameW);
7518 cp += lenface;
7519 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
7520 strcpyW((WCHAR*)cp, full_nameW);
7521 ret = TRUE;
7523 end:
7524 HeapFree(GetProcessHeap(), 0, style_nameW);
7525 HeapFree(GetProcessHeap(), 0, family_nameW);
7526 HeapFree(GetProcessHeap(), 0, face_nameW);
7527 HeapFree(GetProcessHeap(), 0, full_nameW);
7528 return ret;
7531 /*************************************************************
7532 * freetype_GetGlyphOutline
7534 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
7535 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7537 struct freetype_physdev *physdev = get_freetype_dev( dev );
7538 DWORD ret;
7539 ABC abc;
7541 if (!physdev->font)
7543 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
7544 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
7547 GDI_CheckNotLock();
7548 EnterCriticalSection( &freetype_cs );
7549 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
7550 LeaveCriticalSection( &freetype_cs );
7551 return ret;
7554 /*************************************************************
7555 * freetype_GetTextMetrics
7557 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
7559 struct freetype_physdev *physdev = get_freetype_dev( dev );
7560 BOOL ret;
7562 if (!physdev->font)
7564 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
7565 return dev->funcs->pGetTextMetrics( dev, metrics );
7568 GDI_CheckNotLock();
7569 EnterCriticalSection( &freetype_cs );
7570 ret = get_text_metrics( physdev->font, metrics );
7571 LeaveCriticalSection( &freetype_cs );
7572 return ret;
7575 /*************************************************************
7576 * freetype_GetOutlineTextMetrics
7578 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
7580 struct freetype_physdev *physdev = get_freetype_dev( dev );
7581 UINT ret = 0;
7583 if (!physdev->font)
7585 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
7586 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
7589 TRACE("font=%p\n", physdev->font);
7591 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
7593 GDI_CheckNotLock();
7594 EnterCriticalSection( &freetype_cs );
7596 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
7598 if(cbSize >= physdev->font->potm->otmSize)
7600 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
7601 scale_outline_font_metrics(physdev->font, potm);
7603 ret = physdev->font->potm->otmSize;
7605 LeaveCriticalSection( &freetype_cs );
7606 return ret;
7609 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
7611 child->font = alloc_font();
7612 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
7613 if(!child->font->ft_face)
7615 free_font(child->font);
7616 child->font = NULL;
7617 return FALSE;
7620 child->font->font_desc = font->font_desc;
7621 child->font->ntmFlags = child->face->ntmFlags;
7622 child->font->orientation = font->orientation;
7623 child->font->scale_y = font->scale_y;
7624 child->font->name = strdupW(child->face->family->FamilyName);
7625 child->font->base_font = font;
7626 TRACE("created child font %p for base %p\n", child->font, font);
7627 return TRUE;
7630 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL* vert)
7632 FT_UInt g,o;
7633 CHILD_FONT *child_font;
7635 if(font->base_font)
7636 font = font->base_font;
7638 *linked_font = font;
7640 if((*glyph = get_glyph_index(font, c)))
7642 o = *glyph;
7643 *glyph = get_GSUB_vert_glyph(font, *glyph);
7644 *vert = (o != *glyph);
7645 return TRUE;
7648 if (c < 32) goto done; /* don't check linked fonts for control characters */
7650 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7652 if(!child_font->font)
7653 if(!load_child_font(font, child_font))
7654 continue;
7656 if(!child_font->font->ft_face)
7657 continue;
7658 g = get_glyph_index(child_font->font, c);
7659 o = g;
7660 g = get_GSUB_vert_glyph(child_font->font, g);
7661 if(g)
7663 *glyph = g;
7664 *linked_font = child_font->font;
7665 *vert = (o != g);
7666 return TRUE;
7670 done:
7671 *vert = FALSE;
7672 return FALSE;
7675 /*************************************************************
7676 * freetype_GetCharWidth
7678 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7680 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7681 UINT c;
7682 GLYPHMETRICS gm;
7683 ABC abc;
7684 struct freetype_physdev *physdev = get_freetype_dev( dev );
7686 if (!physdev->font)
7688 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7689 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7692 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7694 GDI_CheckNotLock();
7695 EnterCriticalSection( &freetype_cs );
7696 for(c = firstChar; c <= lastChar; c++) {
7697 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7698 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
7700 LeaveCriticalSection( &freetype_cs );
7701 return TRUE;
7704 /*************************************************************
7705 * freetype_GetCharABCWidths
7707 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7709 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7710 UINT c;
7711 GLYPHMETRICS gm;
7712 struct freetype_physdev *physdev = get_freetype_dev( dev );
7714 if (!physdev->font)
7716 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7717 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7720 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7722 GDI_CheckNotLock();
7723 EnterCriticalSection( &freetype_cs );
7725 for(c = firstChar; c <= lastChar; c++, buffer++)
7726 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
7728 LeaveCriticalSection( &freetype_cs );
7729 return TRUE;
7732 /*************************************************************
7733 * freetype_GetCharABCWidthsI
7735 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7737 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7738 UINT c;
7739 GLYPHMETRICS gm;
7740 struct freetype_physdev *physdev = get_freetype_dev( dev );
7742 if (!physdev->font)
7744 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7745 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7748 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7749 return FALSE;
7751 GDI_CheckNotLock();
7752 EnterCriticalSection( &freetype_cs );
7754 for(c = 0; c < count; c++, buffer++)
7755 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
7756 &gm, buffer, 0, NULL, &identity );
7758 LeaveCriticalSection( &freetype_cs );
7759 return TRUE;
7762 /*************************************************************
7763 * freetype_GetTextExtentExPoint
7765 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
7767 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7768 INT idx, pos;
7769 ABC abc;
7770 GLYPHMETRICS gm;
7771 struct freetype_physdev *physdev = get_freetype_dev( dev );
7773 if (!physdev->font)
7775 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7776 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
7779 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
7781 GDI_CheckNotLock();
7782 EnterCriticalSection( &freetype_cs );
7784 for (idx = pos = 0; idx < count; idx++)
7786 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7787 pos += abc.abcA + abc.abcB + abc.abcC;
7788 dxs[idx] = pos;
7791 LeaveCriticalSection( &freetype_cs );
7792 return TRUE;
7795 /*************************************************************
7796 * freetype_GetTextExtentExPointI
7798 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
7800 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7801 INT idx, pos;
7802 ABC abc;
7803 GLYPHMETRICS gm;
7804 struct freetype_physdev *physdev = get_freetype_dev( dev );
7806 if (!physdev->font)
7808 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7809 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
7812 TRACE("%p, %p, %d\n", physdev->font, indices, count);
7814 GDI_CheckNotLock();
7815 EnterCriticalSection( &freetype_cs );
7817 for (idx = pos = 0; idx < count; idx++)
7819 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
7820 &gm, &abc, 0, NULL, &identity );
7821 pos += abc.abcA + abc.abcB + abc.abcC;
7822 dxs[idx] = pos;
7825 LeaveCriticalSection( &freetype_cs );
7826 return TRUE;
7829 /*************************************************************
7830 * freetype_GetFontData
7832 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7834 struct freetype_physdev *physdev = get_freetype_dev( dev );
7836 if (!physdev->font)
7838 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7839 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7842 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7843 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7844 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7846 return get_font_data( physdev->font, table, offset, buf, cbData );
7849 /*************************************************************
7850 * freetype_GetTextFace
7852 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7854 INT n;
7855 struct freetype_physdev *physdev = get_freetype_dev( dev );
7857 if (!physdev->font)
7859 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7860 return dev->funcs->pGetTextFace( dev, count, str );
7863 n = strlenW(physdev->font->name) + 1;
7864 if (str)
7866 lstrcpynW(str, physdev->font->name, count);
7867 n = min(count, n);
7869 return n;
7872 /*************************************************************
7873 * freetype_GetTextCharsetInfo
7875 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7877 struct freetype_physdev *physdev = get_freetype_dev( dev );
7879 if (!physdev->font)
7881 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7882 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7884 if (fs) *fs = physdev->font->fs;
7885 return physdev->font->charset;
7888 /* Retrieve a list of supported Unicode ranges for a given font.
7889 * Can be called with NULL gs to calculate the buffer size. Returns
7890 * the number of ranges found.
7892 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7894 DWORD num_ranges = 0;
7896 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7898 FT_UInt glyph_code;
7899 FT_ULong char_code, char_code_prev;
7901 glyph_code = 0;
7902 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7904 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7905 face->num_glyphs, glyph_code, char_code);
7907 if (!glyph_code) return 0;
7909 if (gs)
7911 gs->ranges[0].wcLow = (USHORT)char_code;
7912 gs->ranges[0].cGlyphs = 0;
7913 gs->cGlyphsSupported = 0;
7916 num_ranges = 1;
7917 while (glyph_code)
7919 if (char_code < char_code_prev)
7921 ERR("expected increasing char code from FT_Get_Next_Char\n");
7922 return 0;
7924 if (char_code - char_code_prev > 1)
7926 num_ranges++;
7927 if (gs)
7929 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7930 gs->ranges[num_ranges - 1].cGlyphs = 1;
7931 gs->cGlyphsSupported++;
7934 else if (gs)
7936 gs->ranges[num_ranges - 1].cGlyphs++;
7937 gs->cGlyphsSupported++;
7939 char_code_prev = char_code;
7940 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7943 else
7944 FIXME("encoding %u not supported\n", face->charmap->encoding);
7946 return num_ranges;
7949 /*************************************************************
7950 * freetype_GetFontUnicodeRanges
7952 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7954 struct freetype_physdev *physdev = get_freetype_dev( dev );
7955 DWORD size, num_ranges;
7957 if (!physdev->font)
7959 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7960 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7963 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7964 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7965 if (glyphset)
7967 glyphset->cbThis = size;
7968 glyphset->cRanges = num_ranges;
7969 glyphset->flAccel = 0;
7971 return size;
7974 /*************************************************************
7975 * freetype_FontIsLinked
7977 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7979 struct freetype_physdev *physdev = get_freetype_dev( dev );
7980 BOOL ret;
7982 if (!physdev->font)
7984 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7985 return dev->funcs->pFontIsLinked( dev );
7988 GDI_CheckNotLock();
7989 EnterCriticalSection( &freetype_cs );
7990 ret = !list_empty(&physdev->font->child_fonts);
7991 LeaveCriticalSection( &freetype_cs );
7992 return ret;
7995 /*************************************************************************
7996 * GetRasterizerCaps (GDI32.@)
7998 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8000 lprs->nSize = sizeof(RASTERIZER_STATUS);
8001 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
8002 lprs->nLanguageID = 0;
8003 return TRUE;
8006 /*************************************************************
8007 * freetype_GdiRealizationInfo
8009 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
8011 struct freetype_physdev *physdev = get_freetype_dev( dev );
8012 realization_info_t *info = ptr;
8014 if (!physdev->font)
8016 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
8017 return dev->funcs->pGdiRealizationInfo( dev, ptr );
8020 FIXME("(%p, %p): stub!\n", physdev->font, info);
8022 info->flags = 1;
8023 if(FT_IS_SCALABLE(physdev->font->ft_face))
8024 info->flags |= 2;
8026 info->cache_num = physdev->font->cache_num;
8027 info->unknown2 = -1;
8028 return TRUE;
8031 /*************************************************************************
8032 * Kerning support for TrueType fonts
8034 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
8036 struct TT_kern_table
8038 USHORT version;
8039 USHORT nTables;
8042 struct TT_kern_subtable
8044 USHORT version;
8045 USHORT length;
8046 union
8048 USHORT word;
8049 struct
8051 USHORT horizontal : 1;
8052 USHORT minimum : 1;
8053 USHORT cross_stream: 1;
8054 USHORT override : 1;
8055 USHORT reserved1 : 4;
8056 USHORT format : 8;
8057 } bits;
8058 } coverage;
8061 struct TT_format0_kern_subtable
8063 USHORT nPairs;
8064 USHORT searchRange;
8065 USHORT entrySelector;
8066 USHORT rangeShift;
8069 struct TT_kern_pair
8071 USHORT left;
8072 USHORT right;
8073 short value;
8076 static DWORD parse_format0_kern_subtable(GdiFont *font,
8077 const struct TT_format0_kern_subtable *tt_f0_ks,
8078 const USHORT *glyph_to_char,
8079 KERNINGPAIR *kern_pair, DWORD cPairs)
8081 USHORT i, nPairs;
8082 const struct TT_kern_pair *tt_kern_pair;
8084 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
8086 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
8088 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8089 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
8090 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
8092 if (!kern_pair || !cPairs)
8093 return nPairs;
8095 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
8097 nPairs = min(nPairs, cPairs);
8099 for (i = 0; i < nPairs; i++)
8101 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
8102 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
8103 /* this algorithm appears to better match what Windows does */
8104 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
8105 if (kern_pair->iKernAmount < 0)
8107 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
8108 kern_pair->iKernAmount -= font->ppem;
8110 else if (kern_pair->iKernAmount > 0)
8112 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
8113 kern_pair->iKernAmount += font->ppem;
8115 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
8117 TRACE("left %u right %u value %d\n",
8118 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
8120 kern_pair++;
8122 TRACE("copied %u entries\n", nPairs);
8123 return nPairs;
8126 /*************************************************************
8127 * freetype_GetKerningPairs
8129 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
8131 DWORD length;
8132 void *buf;
8133 const struct TT_kern_table *tt_kern_table;
8134 const struct TT_kern_subtable *tt_kern_subtable;
8135 USHORT i, nTables;
8136 USHORT *glyph_to_char;
8137 GdiFont *font;
8138 struct freetype_physdev *physdev = get_freetype_dev( dev );
8140 if (!(font = physdev->font))
8142 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
8143 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
8146 GDI_CheckNotLock();
8147 EnterCriticalSection( &freetype_cs );
8148 if (font->total_kern_pairs != (DWORD)-1)
8150 if (cPairs && kern_pair)
8152 cPairs = min(cPairs, font->total_kern_pairs);
8153 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8155 else cPairs = font->total_kern_pairs;
8157 LeaveCriticalSection( &freetype_cs );
8158 return cPairs;
8161 font->total_kern_pairs = 0;
8163 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
8165 if (length == GDI_ERROR)
8167 TRACE("no kerning data in the font\n");
8168 LeaveCriticalSection( &freetype_cs );
8169 return 0;
8172 buf = HeapAlloc(GetProcessHeap(), 0, length);
8173 if (!buf)
8175 WARN("Out of memory\n");
8176 LeaveCriticalSection( &freetype_cs );
8177 return 0;
8180 get_font_data(font, MS_KERN_TAG, 0, buf, length);
8182 /* build a glyph index to char code map */
8183 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
8184 if (!glyph_to_char)
8186 WARN("Out of memory allocating a glyph index to char code map\n");
8187 HeapFree(GetProcessHeap(), 0, buf);
8188 LeaveCriticalSection( &freetype_cs );
8189 return 0;
8192 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
8194 FT_UInt glyph_code;
8195 FT_ULong char_code;
8197 glyph_code = 0;
8198 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
8200 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
8201 font->ft_face->num_glyphs, glyph_code, char_code);
8203 while (glyph_code)
8205 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
8207 /* FIXME: This doesn't match what Windows does: it does some fancy
8208 * things with duplicate glyph index to char code mappings, while
8209 * we just avoid overriding existing entries.
8211 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
8212 glyph_to_char[glyph_code] = (USHORT)char_code;
8214 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
8217 else
8219 ULONG n;
8221 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
8222 for (n = 0; n <= 65535; n++)
8223 glyph_to_char[n] = (USHORT)n;
8226 tt_kern_table = buf;
8227 nTables = GET_BE_WORD(tt_kern_table->nTables);
8228 TRACE("version %u, nTables %u\n",
8229 GET_BE_WORD(tt_kern_table->version), nTables);
8231 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
8233 for (i = 0; i < nTables; i++)
8235 struct TT_kern_subtable tt_kern_subtable_copy;
8237 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
8238 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
8239 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
8241 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8242 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
8243 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
8245 /* According to the TrueType specification this is the only format
8246 * that will be properly interpreted by Windows and OS/2
8248 if (tt_kern_subtable_copy.coverage.bits.format == 0)
8250 DWORD new_chunk, old_total = font->total_kern_pairs;
8252 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8253 glyph_to_char, NULL, 0);
8254 font->total_kern_pairs += new_chunk;
8256 if (!font->kern_pairs)
8257 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
8258 font->total_kern_pairs * sizeof(*font->kern_pairs));
8259 else
8260 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
8261 font->total_kern_pairs * sizeof(*font->kern_pairs));
8263 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8264 glyph_to_char, font->kern_pairs + old_total, new_chunk);
8266 else
8267 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
8269 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
8272 HeapFree(GetProcessHeap(), 0, glyph_to_char);
8273 HeapFree(GetProcessHeap(), 0, buf);
8275 if (cPairs && kern_pair)
8277 cPairs = min(cPairs, font->total_kern_pairs);
8278 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8280 else cPairs = font->total_kern_pairs;
8282 LeaveCriticalSection( &freetype_cs );
8283 return cPairs;
8286 static const struct gdi_dc_funcs freetype_funcs =
8288 NULL, /* pAbortDoc */
8289 NULL, /* pAbortPath */
8290 NULL, /* pAlphaBlend */
8291 NULL, /* pAngleArc */
8292 NULL, /* pArc */
8293 NULL, /* pArcTo */
8294 NULL, /* pBeginPath */
8295 NULL, /* pBlendImage */
8296 NULL, /* pChord */
8297 NULL, /* pCloseFigure */
8298 NULL, /* pCreateCompatibleDC */
8299 freetype_CreateDC, /* pCreateDC */
8300 freetype_DeleteDC, /* pDeleteDC */
8301 NULL, /* pDeleteObject */
8302 NULL, /* pDeviceCapabilities */
8303 NULL, /* pEllipse */
8304 NULL, /* pEndDoc */
8305 NULL, /* pEndPage */
8306 NULL, /* pEndPath */
8307 freetype_EnumFonts, /* pEnumFonts */
8308 NULL, /* pEnumICMProfiles */
8309 NULL, /* pExcludeClipRect */
8310 NULL, /* pExtDeviceMode */
8311 NULL, /* pExtEscape */
8312 NULL, /* pExtFloodFill */
8313 NULL, /* pExtSelectClipRgn */
8314 NULL, /* pExtTextOut */
8315 NULL, /* pFillPath */
8316 NULL, /* pFillRgn */
8317 NULL, /* pFlattenPath */
8318 freetype_FontIsLinked, /* pFontIsLinked */
8319 NULL, /* pFrameRgn */
8320 NULL, /* pGdiComment */
8321 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
8322 NULL, /* pGetBoundsRect */
8323 freetype_GetCharABCWidths, /* pGetCharABCWidths */
8324 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
8325 freetype_GetCharWidth, /* pGetCharWidth */
8326 NULL, /* pGetDeviceCaps */
8327 NULL, /* pGetDeviceGammaRamp */
8328 freetype_GetFontData, /* pGetFontData */
8329 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
8330 freetype_GetGlyphIndices, /* pGetGlyphIndices */
8331 freetype_GetGlyphOutline, /* pGetGlyphOutline */
8332 NULL, /* pGetICMProfile */
8333 NULL, /* pGetImage */
8334 freetype_GetKerningPairs, /* pGetKerningPairs */
8335 NULL, /* pGetNearestColor */
8336 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
8337 NULL, /* pGetPixel */
8338 NULL, /* pGetSystemPaletteEntries */
8339 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
8340 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
8341 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
8342 freetype_GetTextFace, /* pGetTextFace */
8343 freetype_GetTextMetrics, /* pGetTextMetrics */
8344 NULL, /* pGradientFill */
8345 NULL, /* pIntersectClipRect */
8346 NULL, /* pInvertRgn */
8347 NULL, /* pLineTo */
8348 NULL, /* pModifyWorldTransform */
8349 NULL, /* pMoveTo */
8350 NULL, /* pOffsetClipRgn */
8351 NULL, /* pOffsetViewportOrg */
8352 NULL, /* pOffsetWindowOrg */
8353 NULL, /* pPaintRgn */
8354 NULL, /* pPatBlt */
8355 NULL, /* pPie */
8356 NULL, /* pPolyBezier */
8357 NULL, /* pPolyBezierTo */
8358 NULL, /* pPolyDraw */
8359 NULL, /* pPolyPolygon */
8360 NULL, /* pPolyPolyline */
8361 NULL, /* pPolygon */
8362 NULL, /* pPolyline */
8363 NULL, /* pPolylineTo */
8364 NULL, /* pPutImage */
8365 NULL, /* pRealizeDefaultPalette */
8366 NULL, /* pRealizePalette */
8367 NULL, /* pRectangle */
8368 NULL, /* pResetDC */
8369 NULL, /* pRestoreDC */
8370 NULL, /* pRoundRect */
8371 NULL, /* pSaveDC */
8372 NULL, /* pScaleViewportExt */
8373 NULL, /* pScaleWindowExt */
8374 NULL, /* pSelectBitmap */
8375 NULL, /* pSelectBrush */
8376 NULL, /* pSelectClipPath */
8377 freetype_SelectFont, /* pSelectFont */
8378 NULL, /* pSelectPalette */
8379 NULL, /* pSelectPen */
8380 NULL, /* pSetArcDirection */
8381 NULL, /* pSetBkColor */
8382 NULL, /* pSetBkMode */
8383 NULL, /* pSetDCBrushColor */
8384 NULL, /* pSetDCPenColor */
8385 NULL, /* pSetDIBColorTable */
8386 NULL, /* pSetDIBitsToDevice */
8387 NULL, /* pSetDeviceClipping */
8388 NULL, /* pSetDeviceGammaRamp */
8389 NULL, /* pSetLayout */
8390 NULL, /* pSetMapMode */
8391 NULL, /* pSetMapperFlags */
8392 NULL, /* pSetPixel */
8393 NULL, /* pSetPolyFillMode */
8394 NULL, /* pSetROP2 */
8395 NULL, /* pSetRelAbs */
8396 NULL, /* pSetStretchBltMode */
8397 NULL, /* pSetTextAlign */
8398 NULL, /* pSetTextCharacterExtra */
8399 NULL, /* pSetTextColor */
8400 NULL, /* pSetTextJustification */
8401 NULL, /* pSetViewportExt */
8402 NULL, /* pSetViewportOrg */
8403 NULL, /* pSetWindowExt */
8404 NULL, /* pSetWindowOrg */
8405 NULL, /* pSetWorldTransform */
8406 NULL, /* pStartDoc */
8407 NULL, /* pStartPage */
8408 NULL, /* pStretchBlt */
8409 NULL, /* pStretchDIBits */
8410 NULL, /* pStrokeAndFillPath */
8411 NULL, /* pStrokePath */
8412 NULL, /* pUnrealizePalette */
8413 NULL, /* pWidenPath */
8414 NULL, /* wine_get_wgl_driver */
8415 GDI_PRIORITY_FONT_DRV /* priority */
8418 #else /* HAVE_FREETYPE */
8420 /*************************************************************************/
8422 BOOL WineEngInit(void)
8424 return FALSE;
8427 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8429 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8430 return 1;
8433 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8435 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8436 return TRUE;
8439 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
8441 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
8442 return NULL;
8445 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
8446 LPCWSTR font_file, LPCWSTR font_path )
8448 FIXME("stub\n");
8449 return FALSE;
8452 /*************************************************************************
8453 * GetRasterizerCaps (GDI32.@)
8455 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8457 lprs->nSize = sizeof(RASTERIZER_STATUS);
8458 lprs->wFlags = 0;
8459 lprs->nLanguageID = 0;
8460 return TRUE;
8463 #endif /* HAVE_FREETYPE */