usp10: Free default_language items when freeing script cache.
[wine.git] / dlls / gdi32 / freetype.c
blobb977b0d1fa20da60059958af8852d430f01430e7
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 void *font_data_ptr;
267 DWORD font_data_size;
268 FT_Long face_index;
269 FONTSIGNATURE fs;
270 DWORD ntmFlags;
271 FT_Fixed font_version;
272 BOOL scalable;
273 Bitmap_Size size; /* set if face is a bitmap */
274 DWORD flags; /* ADDFONT flags */
275 struct tagFamily *family;
276 /* Cached data for Enum */
277 struct enum_data *cached_enum_data;
278 } Face;
280 #define ADDFONT_EXTERNAL_FONT 0x01
281 #define ADDFONT_ALLOW_BITMAP 0x02
282 #define ADDFONT_ADD_TO_CACHE 0x04
283 #define ADDFONT_ADD_RESOURCE 0x08 /* added through AddFontResource */
284 #define ADDFONT_VERTICAL_FONT 0x10
285 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
287 typedef struct tagFamily {
288 struct list entry;
289 unsigned int refcount;
290 WCHAR *FamilyName;
291 WCHAR *EnglishName;
292 struct list faces;
293 struct list *replacement;
294 } Family;
296 typedef struct {
297 GLYPHMETRICS gm;
298 ABC abc; /* metrics of the unrotated char */
299 BOOL init;
300 } GM;
302 typedef struct {
303 FLOAT eM11, eM12;
304 FLOAT eM21, eM22;
305 } FMAT2;
307 typedef struct {
308 DWORD hash;
309 LOGFONTW lf;
310 FMAT2 matrix;
311 BOOL can_use_bitmap;
312 } FONT_DESC;
314 typedef struct tagGdiFont GdiFont;
316 typedef struct {
317 struct list entry;
318 Face *face;
319 GdiFont *font;
320 } CHILD_FONT;
322 struct tagGdiFont {
323 struct list entry;
324 struct list unused_entry;
325 unsigned int refcount;
326 GM **gm;
327 DWORD gmsize;
328 OUTLINETEXTMETRICW *potm;
329 DWORD total_kern_pairs;
330 KERNINGPAIR *kern_pairs;
331 struct list child_fonts;
333 /* the following members can be accessed without locking, they are never modified after creation */
334 FT_Face ft_face;
335 struct font_mapping *mapping;
336 LPWSTR name;
337 int charset;
338 int codepage;
339 BOOL fake_italic;
340 BOOL fake_bold;
341 BYTE underline;
342 BYTE strikeout;
343 INT orientation;
344 FONT_DESC font_desc;
345 LONG aveWidth, ppem;
346 double scale_y;
347 SHORT yMax;
348 SHORT yMin;
349 DWORD ntmFlags;
350 DWORD aa_flags;
351 UINT ntmCellHeight, ntmAvgWidth;
352 FONTSIGNATURE fs;
353 GdiFont *base_font;
354 VOID *GSUB_Table;
355 DWORD cache_num;
358 typedef struct {
359 struct list entry;
360 const WCHAR *font_name;
361 FONTSIGNATURE fs;
362 struct list links;
363 } SYSTEM_LINKS;
365 struct enum_charset_element {
366 DWORD mask;
367 DWORD charset;
368 WCHAR name[LF_FACESIZE];
371 struct enum_charset_list {
372 DWORD total;
373 struct enum_charset_element element[32];
376 #define GM_BLOCK_SIZE 128
377 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
379 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
380 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
381 static unsigned int unused_font_count;
382 #define UNUSED_CACHE_SIZE 10
383 static struct list system_links = LIST_INIT(system_links);
385 static struct list font_subst_list = LIST_INIT(font_subst_list);
387 static struct list font_list = LIST_INIT(font_list);
389 struct freetype_physdev
391 struct gdi_physdev dev;
392 GdiFont *font;
395 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
397 return (struct freetype_physdev *)dev;
400 static const struct gdi_dc_funcs freetype_funcs;
402 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
403 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
404 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
406 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
407 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
408 'W','i','n','d','o','w','s','\\',
409 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
410 'F','o','n','t','s','\0'};
412 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
413 'W','i','n','d','o','w','s',' ','N','T','\\',
414 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
415 'F','o','n','t','s','\0'};
417 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
418 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
419 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
420 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
422 static const WCHAR * const SystemFontValues[] = {
423 System_Value,
424 OEMFont_Value,
425 FixedSys_Value,
426 NULL
429 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
430 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
432 /* Interesting and well-known (frequently-assumed!) font names */
433 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
434 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 };
435 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
436 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
437 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
438 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
439 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
440 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
442 static const WCHAR arial[] = {'A','r','i','a','l',0};
443 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
444 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};
445 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};
446 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
447 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
448 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
449 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
450 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
451 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
453 static const WCHAR *default_serif_list[] =
455 times_new_roman,
456 liberation_serif,
457 bitstream_vera_serif,
458 NULL
461 static const WCHAR *default_fixed_list[] =
463 courier_new,
464 liberation_mono,
465 bitstream_vera_sans_mono,
466 NULL
469 static const WCHAR *default_sans_list[] =
471 arial,
472 liberation_sans,
473 bitstream_vera_sans,
474 NULL
477 typedef struct {
478 WCHAR *name;
479 INT charset;
480 } NameCs;
482 typedef struct tagFontSubst {
483 struct list entry;
484 NameCs from;
485 NameCs to;
486 } FontSubst;
488 /* Registry font cache key and value names */
489 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
490 'F','o','n','t','s',0};
491 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
492 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
493 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
494 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
495 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
496 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
497 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
498 static const WCHAR face_size_value[] = {'S','i','z','e',0};
499 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
500 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
501 static const WCHAR face_flags_value[] = {'F','l','a','g','s',0};
502 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
503 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
504 static const WCHAR face_file_name_value[] = {'F','i','l','e',' ','N','a','m','e','\0'};
505 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
508 struct font_mapping
510 struct list entry;
511 int refcount;
512 dev_t dev;
513 ino_t ino;
514 void *data;
515 size_t size;
518 static struct list mappings_list = LIST_INIT( mappings_list );
520 static UINT default_aa_flags;
521 static HKEY hkey_font_cache;
523 static CRITICAL_SECTION freetype_cs;
524 static CRITICAL_SECTION_DEBUG critsect_debug =
526 0, 0, &freetype_cs,
527 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
528 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
530 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
532 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
534 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
535 static BOOL use_default_fallback = FALSE;
537 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
538 static BOOL get_outline_text_metrics(GdiFont *font);
539 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
540 static void remove_face_from_cache( Face *face );
542 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
543 'W','i','n','d','o','w','s',' ','N','T','\\',
544 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
545 'S','y','s','t','e','m','L','i','n','k',0};
547 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
548 'F','o','n','t','L','i','n','k','\\',
549 'S','y','s','t','e','m','L','i','n','k',0};
551 /****************************************
552 * Notes on .fon files
554 * The fonts System, FixedSys and Terminal are special. There are typically multiple
555 * versions installed for different resolutions and codepages. Windows stores which one to use
556 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
557 * Key Meaning
558 * FIXEDFON.FON FixedSys
559 * FONTS.FON System
560 * OEMFONT.FON Terminal
561 * LogPixels Current dpi set by the display control panel applet
562 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
563 * also has a LogPixels value that appears to mirror this)
565 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
566 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
567 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
568 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
569 * so that makes sense.
571 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
572 * to be mapped into the registry on Windows 2000 at least).
573 * I have
574 * woafont=app850.fon
575 * ega80woa.fon=ega80850.fon
576 * ega40woa.fon=ega40850.fon
577 * cga80woa.fon=cga80850.fon
578 * cga40woa.fon=cga40850.fon
581 /* These are all structures needed for the GSUB table */
583 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
584 #define TATEGAKI_LOWER_BOUND 0x02F1
586 typedef struct {
587 DWORD version;
588 WORD ScriptList;
589 WORD FeatureList;
590 WORD LookupList;
591 } GSUB_Header;
593 typedef struct {
594 CHAR ScriptTag[4];
595 WORD Script;
596 } GSUB_ScriptRecord;
598 typedef struct {
599 WORD ScriptCount;
600 GSUB_ScriptRecord ScriptRecord[1];
601 } GSUB_ScriptList;
603 typedef struct {
604 CHAR LangSysTag[4];
605 WORD LangSys;
606 } GSUB_LangSysRecord;
608 typedef struct {
609 WORD DefaultLangSys;
610 WORD LangSysCount;
611 GSUB_LangSysRecord LangSysRecord[1];
612 } GSUB_Script;
614 typedef struct {
615 WORD LookupOrder; /* Reserved */
616 WORD ReqFeatureIndex;
617 WORD FeatureCount;
618 WORD FeatureIndex[1];
619 } GSUB_LangSys;
621 typedef struct {
622 CHAR FeatureTag[4];
623 WORD Feature;
624 } GSUB_FeatureRecord;
626 typedef struct {
627 WORD FeatureCount;
628 GSUB_FeatureRecord FeatureRecord[1];
629 } GSUB_FeatureList;
631 typedef struct {
632 WORD FeatureParams; /* Reserved */
633 WORD LookupCount;
634 WORD LookupListIndex[1];
635 } GSUB_Feature;
637 typedef struct {
638 WORD LookupCount;
639 WORD Lookup[1];
640 } GSUB_LookupList;
642 typedef struct {
643 WORD LookupType;
644 WORD LookupFlag;
645 WORD SubTableCount;
646 WORD SubTable[1];
647 } GSUB_LookupTable;
649 typedef struct {
650 WORD CoverageFormat;
651 WORD GlyphCount;
652 WORD GlyphArray[1];
653 } GSUB_CoverageFormat1;
655 typedef struct {
656 WORD Start;
657 WORD End;
658 WORD StartCoverageIndex;
659 } GSUB_RangeRecord;
661 typedef struct {
662 WORD CoverageFormat;
663 WORD RangeCount;
664 GSUB_RangeRecord RangeRecord[1];
665 } GSUB_CoverageFormat2;
667 typedef struct {
668 WORD SubstFormat; /* = 1 */
669 WORD Coverage;
670 WORD DeltaGlyphID;
671 } GSUB_SingleSubstFormat1;
673 typedef struct {
674 WORD SubstFormat; /* = 2 */
675 WORD Coverage;
676 WORD GlyphCount;
677 WORD Substitute[1];
678 }GSUB_SingleSubstFormat2;
680 #ifdef HAVE_CARBON_CARBON_H
681 static char *find_cache_dir(void)
683 FSRef ref;
684 OSErr err;
685 static char cached_path[MAX_PATH];
686 static const char *wine = "/Wine", *fonts = "/Fonts";
688 if(*cached_path) return cached_path;
690 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
691 if(err != noErr)
693 WARN("can't create cached data folder\n");
694 return NULL;
696 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
697 if(err != noErr)
699 WARN("can't create cached data path\n");
700 *cached_path = '\0';
701 return NULL;
703 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
705 ERR("Could not create full path\n");
706 *cached_path = '\0';
707 return NULL;
709 strcat(cached_path, wine);
711 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
713 WARN("Couldn't mkdir %s\n", cached_path);
714 *cached_path = '\0';
715 return NULL;
717 strcat(cached_path, fonts);
718 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
720 WARN("Couldn't mkdir %s\n", cached_path);
721 *cached_path = '\0';
722 return NULL;
724 return cached_path;
727 /******************************************************************
728 * expand_mac_font
730 * Extracts individual TrueType font files from a Mac suitcase font
731 * and saves them into the user's caches directory (see
732 * find_cache_dir()).
733 * Returns a NULL terminated array of filenames.
735 * We do this because they are apps that try to read ttf files
736 * themselves and they don't like Mac suitcase files.
738 static char **expand_mac_font(const char *path)
740 FSRef ref;
741 SInt16 res_ref;
742 OSStatus s;
743 unsigned int idx;
744 const char *out_dir;
745 const char *filename;
746 int output_len;
747 struct {
748 char **array;
749 unsigned int size, max_size;
750 } ret;
752 TRACE("path %s\n", path);
754 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
755 if(s != noErr)
757 WARN("failed to get ref\n");
758 return NULL;
761 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
762 if(s != noErr)
764 TRACE("no data fork, so trying resource fork\n");
765 res_ref = FSOpenResFile(&ref, fsRdPerm);
766 if(res_ref == -1)
768 TRACE("unable to open resource fork\n");
769 return NULL;
773 ret.size = 0;
774 ret.max_size = 10;
775 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
776 if(!ret.array)
778 CloseResFile(res_ref);
779 return NULL;
782 out_dir = find_cache_dir();
784 filename = strrchr(path, '/');
785 if(!filename) filename = path;
786 else filename++;
788 /* output filename has the form out_dir/filename_%04x.ttf */
789 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
791 UseResFile(res_ref);
792 idx = 1;
793 while(1)
795 FamRec *fam_rec;
796 unsigned short *num_faces_ptr, num_faces, face;
797 AsscEntry *assoc;
798 Handle fond;
799 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
801 fond = Get1IndResource(fond_res, idx);
802 if(!fond) break;
803 TRACE("got fond resource %d\n", idx);
804 HLock(fond);
806 fam_rec = *(FamRec**)fond;
807 num_faces_ptr = (unsigned short *)(fam_rec + 1);
808 num_faces = GET_BE_WORD(*num_faces_ptr);
809 num_faces++;
810 assoc = (AsscEntry*)(num_faces_ptr + 1);
811 TRACE("num faces %04x\n", num_faces);
812 for(face = 0; face < num_faces; face++, assoc++)
814 Handle sfnt;
815 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
816 unsigned short size, font_id;
817 char *output;
819 size = GET_BE_WORD(assoc->fontSize);
820 font_id = GET_BE_WORD(assoc->fontID);
821 if(size != 0)
823 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
824 continue;
827 TRACE("trying to load sfnt id %04x\n", font_id);
828 sfnt = GetResource(sfnt_res, font_id);
829 if(!sfnt)
831 TRACE("can't get sfnt resource %04x\n", font_id);
832 continue;
835 output = HeapAlloc(GetProcessHeap(), 0, output_len);
836 if(output)
838 int fd;
840 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
842 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
843 if(fd != -1 || errno == EEXIST)
845 if(fd != -1)
847 unsigned char *sfnt_data;
849 HLock(sfnt);
850 sfnt_data = *(unsigned char**)sfnt;
851 write(fd, sfnt_data, GetHandleSize(sfnt));
852 HUnlock(sfnt);
853 close(fd);
855 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
857 ret.max_size *= 2;
858 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
860 ret.array[ret.size++] = output;
862 else
864 WARN("unable to create %s\n", output);
865 HeapFree(GetProcessHeap(), 0, output);
868 ReleaseResource(sfnt);
870 HUnlock(fond);
871 ReleaseResource(fond);
872 idx++;
874 CloseResFile(res_ref);
876 return ret.array;
879 #endif /* HAVE_CARBON_CARBON_H */
881 static inline BOOL is_win9x(void)
883 return GetVersion() & 0x80000000;
886 This function builds an FT_Fixed from a double. It fails if the absolute
887 value of the float number is greater than 32768.
889 static inline FT_Fixed FT_FixedFromFloat(double f)
891 return f * 0x10000;
895 This function builds an FT_Fixed from a FIXED. It simply put f.value
896 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
898 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
900 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
903 static BOOL is_hinting_enabled(void)
905 static int enabled = -1;
907 if (enabled == -1)
909 /* Use the >= 2.2.0 function if available */
910 if (pFT_Get_TrueType_Engine_Type)
912 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
913 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
915 #ifdef FT_DRIVER_HAS_HINTER
916 else
918 /* otherwise if we've been compiled with < 2.2.0 headers use the internal macro */
919 FT_Module mod = pFT_Get_Module(library, "truetype");
920 enabled = (mod && FT_DRIVER_HAS_HINTER(mod));
922 #endif
923 else enabled = FALSE;
924 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
926 return enabled;
929 static BOOL is_subpixel_rendering_enabled( void )
931 #ifdef HAVE_FREETYPE_FTLCDFIL_H
932 static int enabled = -1;
933 if (enabled == -1)
935 enabled = (pFT_Library_SetLcdFilter &&
936 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature);
937 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
939 return enabled;
940 #else
941 return FALSE;
942 #endif
946 static const struct list *get_face_list_from_family(const Family *family)
948 if (!list_empty(&family->faces))
949 return &family->faces;
950 else
951 return family->replacement;
954 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
956 Family *family;
957 Face *face;
958 const WCHAR *file;
960 TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
962 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
964 const struct list *face_list;
965 if(face_name && strcmpiW(face_name, family->FamilyName))
966 continue;
967 face_list = get_face_list_from_family(family);
968 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
970 if (!face->file)
971 continue;
972 file = strrchrW(face->file, '/');
973 if(!file)
974 file = face->file;
975 else
976 file++;
977 if(strcmpiW(file, file_name)) continue;
978 face->refcount++;
979 return face;
982 return NULL;
985 static Family *find_family_from_name(const WCHAR *name)
987 Family *family;
989 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
991 if(!strcmpiW(family->FamilyName, name))
992 return family;
995 return NULL;
998 static Family *find_family_from_any_name(const WCHAR *name)
1000 Family *family;
1002 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1004 if(!strcmpiW(family->FamilyName, name))
1005 return family;
1006 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
1007 return family;
1010 return NULL;
1013 static void DumpSubstList(void)
1015 FontSubst *psub;
1017 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
1019 if(psub->from.charset != -1 || psub->to.charset != -1)
1020 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
1021 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
1022 else
1023 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
1024 debugstr_w(psub->to.name));
1026 return;
1029 static LPWSTR strdupW(LPCWSTR p)
1031 LPWSTR ret;
1032 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
1033 ret = HeapAlloc(GetProcessHeap(), 0, len);
1034 memcpy(ret, p, len);
1035 return ret;
1038 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1039 INT from_charset)
1041 FontSubst *element;
1043 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1045 if(!strcmpiW(element->from.name, from_name) &&
1046 (element->from.charset == from_charset ||
1047 element->from.charset == -1))
1048 return element;
1051 return NULL;
1054 #define ADD_FONT_SUBST_FORCE 1
1056 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1058 FontSubst *from_exist, *to_exist;
1060 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1062 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1064 list_remove(&from_exist->entry);
1065 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
1066 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
1067 HeapFree(GetProcessHeap(), 0, from_exist);
1068 from_exist = NULL;
1071 if(!from_exist)
1073 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1075 if(to_exist)
1077 HeapFree(GetProcessHeap(), 0, subst->to.name);
1078 subst->to.name = strdupW(to_exist->to.name);
1081 list_add_tail(subst_list, &subst->entry);
1083 return TRUE;
1086 HeapFree(GetProcessHeap(), 0, subst->from.name);
1087 HeapFree(GetProcessHeap(), 0, subst->to.name);
1088 HeapFree(GetProcessHeap(), 0, subst);
1089 return FALSE;
1092 static WCHAR *towstr(UINT cp, const char *str)
1094 int len;
1095 WCHAR *wstr;
1097 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1098 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1099 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1100 return wstr;
1103 static char *strWtoA(UINT cp, const WCHAR *str)
1105 int len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL );
1106 char *ret = HeapAlloc( GetProcessHeap(), 0, len );
1107 WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL );
1108 return ret;
1111 static void split_subst_info(NameCs *nc, LPSTR str)
1113 CHAR *p = strrchr(str, ',');
1115 nc->charset = -1;
1116 if(p && *(p+1)) {
1117 nc->charset = strtol(p+1, NULL, 10);
1118 *p = '\0';
1120 nc->name = towstr(CP_ACP, str);
1123 static void LoadSubstList(void)
1125 FontSubst *psub;
1126 HKEY hkey;
1127 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1128 LPSTR value;
1129 LPVOID data;
1131 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1132 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1133 &hkey) == ERROR_SUCCESS) {
1135 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1136 &valuelen, &datalen, NULL, NULL);
1138 valuelen++; /* returned value doesn't include room for '\0' */
1139 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1140 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1142 dlen = datalen;
1143 vlen = valuelen;
1144 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1145 &dlen) == ERROR_SUCCESS) {
1146 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1148 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1149 split_subst_info(&psub->from, value);
1150 split_subst_info(&psub->to, data);
1152 /* Win 2000 doesn't allow mapping between different charsets
1153 or mapping of DEFAULT_CHARSET */
1154 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1155 psub->to.charset == DEFAULT_CHARSET) {
1156 HeapFree(GetProcessHeap(), 0, psub->to.name);
1157 HeapFree(GetProcessHeap(), 0, psub->from.name);
1158 HeapFree(GetProcessHeap(), 0, psub);
1159 } else {
1160 add_font_subst(&font_subst_list, psub, 0);
1162 /* reset dlen and vlen */
1163 dlen = datalen;
1164 vlen = valuelen;
1166 HeapFree(GetProcessHeap(), 0, data);
1167 HeapFree(GetProcessHeap(), 0, value);
1168 RegCloseKey(hkey);
1173 /*****************************************************************
1174 * get_name_table_entry
1176 * Supply the platform, encoding, language and name ids in req
1177 * and if the name exists the function will fill in the string
1178 * and string_len members. The string is owned by FreeType so
1179 * don't free it. Returns TRUE if the name is found else FALSE.
1181 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1183 FT_SfntName name;
1184 FT_UInt num_names, name_index;
1186 if(FT_IS_SFNT(ft_face))
1188 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1190 for(name_index = 0; name_index < num_names; name_index++)
1192 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1194 if((name.platform_id == req->platform_id) &&
1195 ((name.encoding_id == TT_MS_ID_UNICODE_CS) || (name.encoding_id == TT_MS_ID_SYMBOL_CS)) &&
1196 (name.language_id == req->language_id) &&
1197 (name.name_id == req->name_id))
1199 req->string = name.string;
1200 req->string_len = name.string_len;
1201 return TRUE;
1206 req->string = NULL;
1207 req->string_len = 0;
1208 return FALSE;
1211 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1213 WCHAR *ret = NULL;
1214 FT_SfntName name;
1216 name.platform_id = TT_PLATFORM_MICROSOFT;
1217 name.language_id = language_id;
1218 name.name_id = name_id;
1220 if(get_name_table_entry(ft_face, &name))
1222 FT_UInt i;
1224 /* String is not nul terminated and string_len is a byte length. */
1225 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1226 for(i = 0; i < name.string_len / 2; i++)
1228 WORD *tmp = (WORD *)&name.string[i * 2];
1229 ret[i] = GET_BE_WORD(*tmp);
1231 ret[i] = 0;
1232 TRACE("Got localised name %s\n", debugstr_w(ret));
1235 return ret;
1238 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1240 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1241 if (f1->scalable) return TRUE;
1242 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1243 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1246 static void release_family( Family *family )
1248 if (--family->refcount) return;
1249 assert( list_empty( &family->faces ));
1250 list_remove( &family->entry );
1251 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1252 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1253 HeapFree( GetProcessHeap(), 0, family );
1256 static void release_face( Face *face )
1258 if (--face->refcount) return;
1259 if (face->family)
1261 if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
1262 list_remove( &face->entry );
1263 release_family( face->family );
1265 HeapFree( GetProcessHeap(), 0, face->file );
1266 HeapFree( GetProcessHeap(), 0, face->StyleName );
1267 HeapFree( GetProcessHeap(), 0, face->FullName );
1268 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1269 HeapFree( GetProcessHeap(), 0, face );
1272 static inline int style_order(const Face *face)
1274 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1276 case NTM_REGULAR:
1277 return 0;
1278 case NTM_BOLD:
1279 return 1;
1280 case NTM_ITALIC:
1281 return 2;
1282 case NTM_BOLD | NTM_ITALIC:
1283 return 3;
1284 default:
1285 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1286 debugstr_w(face->family->FamilyName),
1287 debugstr_w(face->StyleName),
1288 face->ntmFlags);
1289 return 9999;
1293 static BOOL insert_face_in_family_list( Face *face, Family *family )
1295 Face *cursor;
1297 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1299 if (faces_equal( face, cursor ))
1301 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1302 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1303 cursor->font_version, face->font_version);
1305 if (face->font_version <= cursor->font_version)
1307 TRACE("Original font %s is newer so skipping %s\n",
1308 debugstr_w(cursor->file), debugstr_w(face->file));
1309 return FALSE;
1311 else
1313 TRACE("Replacing original %s with %s\n",
1314 debugstr_w(cursor->file), debugstr_w(face->file));
1315 list_add_before( &cursor->entry, &face->entry );
1316 face->family = family;
1317 family->refcount++;
1318 face->refcount++;
1319 release_face( cursor );
1320 return TRUE;
1323 else
1324 TRACE("Adding new %s\n", debugstr_w(face->file));
1326 if (style_order( face ) < style_order( cursor )) break;
1329 list_add_before( &cursor->entry, &face->entry );
1330 face->family = family;
1331 family->refcount++;
1332 face->refcount++;
1333 return TRUE;
1336 /****************************************************************
1337 * NB This function stores the ptrs to the strings to save copying.
1338 * Don't free them after calling.
1340 static Family *create_family( WCHAR *name, WCHAR *english_name )
1342 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1343 family->refcount = 1;
1344 family->FamilyName = name;
1345 family->EnglishName = english_name;
1346 list_init( &family->faces );
1347 family->replacement = &family->faces;
1348 list_add_tail( &font_list, &family->entry );
1350 return family;
1353 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1355 DWORD type, size = sizeof(DWORD);
1357 if (RegQueryValueExW(hkey, value, NULL, &type, (BYTE *)data, &size) ||
1358 type != REG_DWORD || size != sizeof(DWORD))
1360 *data = 0;
1361 return ERROR_BAD_CONFIGURATION;
1363 return ERROR_SUCCESS;
1366 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1368 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1371 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1373 DWORD needed, strike_index = 0;
1374 HKEY hkey_strike;
1376 /* If we have a File Name key then this is a real font, not just the parent
1377 key of a bunch of non-scalable strikes */
1378 needed = buffer_size;
1379 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1381 Face *face;
1382 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1383 face->cached_enum_data = NULL;
1384 face->family = NULL;
1386 face->refcount = 1;
1387 face->file = strdupW( buffer );
1388 face->StyleName = strdupW(face_name);
1390 needed = buffer_size;
1391 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1392 face->FullName = strdupW( buffer );
1393 else
1394 face->FullName = NULL;
1396 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1397 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1398 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1399 reg_load_dword(hkey_face, face_flags_value, (DWORD*)&face->flags);
1401 needed = sizeof(face->fs);
1402 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1404 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1406 face->scalable = TRUE;
1407 memset(&face->size, 0, sizeof(face->size));
1409 else
1411 face->scalable = FALSE;
1412 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1413 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1414 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1415 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1416 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1418 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1419 face->size.height, face->size.width, face->size.size >> 6,
1420 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1423 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1424 face->fs.fsCsb[0], face->fs.fsCsb[1],
1425 face->fs.fsUsb[0], face->fs.fsUsb[1],
1426 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1428 if (insert_face_in_family_list(face, family))
1429 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1431 release_face( face );
1434 /* load bitmap strikes */
1436 needed = buffer_size;
1437 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1439 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1441 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1442 RegCloseKey(hkey_strike);
1444 needed = buffer_size;
1448 static void load_font_list_from_cache(HKEY hkey_font_cache)
1450 DWORD size, family_index = 0;
1451 Family *family;
1452 HKEY hkey_family;
1453 WCHAR buffer[4096];
1455 size = sizeof(buffer);
1456 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1458 WCHAR *english_family = NULL;
1459 WCHAR *family_name = strdupW( buffer );
1460 DWORD face_index = 0;
1462 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1463 TRACE("opened family key %s\n", debugstr_w(family_name));
1464 size = sizeof(buffer);
1465 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1466 english_family = strdupW( buffer );
1468 family = create_family(family_name, english_family);
1470 if(english_family)
1472 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1473 subst->from.name = strdupW(english_family);
1474 subst->from.charset = -1;
1475 subst->to.name = strdupW(family_name);
1476 subst->to.charset = -1;
1477 add_font_subst(&font_subst_list, subst, 0);
1480 size = sizeof(buffer);
1481 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1483 WCHAR *face_name = strdupW( buffer );
1484 HKEY hkey_face;
1486 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1488 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1489 RegCloseKey(hkey_face);
1491 HeapFree( GetProcessHeap(), 0, face_name );
1492 size = sizeof(buffer);
1494 RegCloseKey(hkey_family);
1495 release_family( family );
1496 size = sizeof(buffer);
1500 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1502 LONG ret;
1503 HKEY hkey_wine_fonts;
1505 /* We don't want to create the fonts key as volatile, so open this first */
1506 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1507 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1508 if(ret != ERROR_SUCCESS)
1510 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1511 return ret;
1514 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1515 KEY_ALL_ACCESS, NULL, hkey, disposition);
1516 RegCloseKey(hkey_wine_fonts);
1517 return ret;
1520 static void add_face_to_cache(Face *face)
1522 HKEY hkey_family, hkey_face;
1523 WCHAR *face_key_name;
1525 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1526 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1527 if(face->family->EnglishName)
1528 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1529 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1531 if(face->scalable)
1532 face_key_name = face->StyleName;
1533 else
1535 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1536 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1537 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1539 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1540 &hkey_face, NULL);
1541 if(!face->scalable)
1542 HeapFree(GetProcessHeap(), 0, face_key_name);
1544 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1545 (strlenW(face->file) + 1) * sizeof(WCHAR));
1546 if (face->FullName)
1547 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1548 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1550 reg_save_dword(hkey_face, face_index_value, face->face_index);
1551 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1552 reg_save_dword(hkey_face, face_version_value, face->font_version);
1553 if (face->flags) reg_save_dword(hkey_face, face_flags_value, face->flags);
1555 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1557 if(!face->scalable)
1559 reg_save_dword(hkey_face, face_height_value, face->size.height);
1560 reg_save_dword(hkey_face, face_width_value, face->size.width);
1561 reg_save_dword(hkey_face, face_size_value, face->size.size);
1562 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1563 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1564 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1566 RegCloseKey(hkey_face);
1567 RegCloseKey(hkey_family);
1570 static void remove_face_from_cache( Face *face )
1572 HKEY hkey_family;
1574 RegOpenKeyExW( hkey_font_cache, face->family->FamilyName, 0, KEY_ALL_ACCESS, &hkey_family );
1576 if (face->scalable)
1578 RegDeleteKeyW( hkey_family, face->StyleName );
1580 else
1582 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1583 WCHAR *face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1584 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1585 RegDeleteKeyW( hkey_family, face_key_name );
1586 HeapFree(GetProcessHeap(), 0, face_key_name);
1588 RegCloseKey(hkey_family);
1591 static WCHAR *prepend_at(WCHAR *family)
1593 WCHAR *str;
1595 if (!family)
1596 return NULL;
1598 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1599 str[0] = '@';
1600 strcpyW(str + 1, family);
1601 HeapFree(GetProcessHeap(), 0, family);
1602 return str;
1605 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1607 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1608 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1610 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1611 if (!*name)
1613 *name = *english;
1614 *english = NULL;
1616 else if (!strcmpiW( *name, *english ))
1618 HeapFree( GetProcessHeap(), 0, *english );
1619 *english = NULL;
1622 if (vertical)
1624 *name = prepend_at( *name );
1625 *english = prepend_at( *english );
1629 static Family *get_family( FT_Face ft_face, BOOL vertical )
1631 Family *family;
1632 WCHAR *name, *english_name;
1634 get_family_names( ft_face, &name, &english_name, vertical );
1636 family = find_family_from_name( name );
1638 if (!family)
1640 family = create_family( name, english_name );
1641 if (english_name)
1643 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1644 subst->from.name = strdupW( english_name );
1645 subst->from.charset = -1;
1646 subst->to.name = strdupW( name );
1647 subst->to.charset = -1;
1648 add_font_subst( &font_subst_list, subst, 0 );
1651 else
1653 HeapFree( GetProcessHeap(), 0, name );
1654 HeapFree( GetProcessHeap(), 0, english_name );
1655 family->refcount++;
1658 return family;
1661 static inline FT_Fixed get_font_version( FT_Face ft_face )
1663 FT_Fixed version = 0;
1664 TT_Header *header;
1666 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1667 if (header) version = header->Font_Revision;
1669 return version;
1672 static inline DWORD get_ntm_flags( FT_Face ft_face )
1674 DWORD flags = 0;
1675 FT_ULong table_size = 0;
1677 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1678 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1679 if (flags == 0) flags = NTM_REGULAR;
1681 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1682 flags |= NTM_PS_OPENTYPE;
1684 return flags;
1687 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1689 int internal_leading = 0;
1690 FT_WinFNT_HeaderRec winfnt_header;
1692 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1693 internal_leading = winfnt_header.internal_leading;
1695 return internal_leading;
1698 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1700 TT_OS2 *os2;
1701 FT_UInt dummy;
1702 CHARSETINFO csi;
1703 FT_WinFNT_HeaderRec winfnt_header;
1704 int i;
1706 memset( fs, 0, sizeof(*fs) );
1708 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1709 if (os2)
1711 fs->fsUsb[0] = os2->ulUnicodeRange1;
1712 fs->fsUsb[1] = os2->ulUnicodeRange2;
1713 fs->fsUsb[2] = os2->ulUnicodeRange3;
1714 fs->fsUsb[3] = os2->ulUnicodeRange4;
1716 if (os2->version == 0)
1718 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1719 fs->fsCsb[0] = FS_LATIN1;
1720 else
1721 fs->fsCsb[0] = FS_SYMBOL;
1723 else
1725 fs->fsCsb[0] = os2->ulCodePageRange1;
1726 fs->fsCsb[1] = os2->ulCodePageRange2;
1729 else
1731 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1733 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1734 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1735 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1736 *fs = csi.fs;
1740 if (fs->fsCsb[0] == 0)
1742 /* let's see if we can find any interesting cmaps */
1743 for (i = 0; i < ft_face->num_charmaps; i++)
1745 switch (ft_face->charmaps[i]->encoding)
1747 case FT_ENCODING_UNICODE:
1748 case FT_ENCODING_APPLE_ROMAN:
1749 fs->fsCsb[0] |= FS_LATIN1;
1750 break;
1751 case FT_ENCODING_MS_SYMBOL:
1752 fs->fsCsb[0] |= FS_SYMBOL;
1753 break;
1754 default:
1755 break;
1761 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1762 DWORD flags )
1764 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1765 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1767 face->refcount = 1;
1768 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
1769 if (!face->StyleName)
1770 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1771 if (!face->StyleName)
1773 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1776 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
1777 if (!face->FullName)
1778 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1779 if (flags & ADDFONT_VERTICAL_FONT)
1780 face->FullName = prepend_at( face->FullName );
1782 if (file)
1784 face->file = towstr( CP_UNIXCP, file );
1785 face->font_data_ptr = NULL;
1786 face->font_data_size = 0;
1788 else
1790 face->file = NULL;
1791 face->font_data_ptr = font_data_ptr;
1792 face->font_data_size = font_data_size;
1795 face->face_index = face_index;
1796 get_fontsig( ft_face, &face->fs );
1797 face->ntmFlags = get_ntm_flags( ft_face );
1798 face->font_version = get_font_version( ft_face );
1800 if (FT_IS_SCALABLE( ft_face ))
1802 memset( &face->size, 0, sizeof(face->size) );
1803 face->scalable = TRUE;
1805 else
1807 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1808 size->height, size->width, size->size >> 6,
1809 size->x_ppem >> 6, size->y_ppem >> 6);
1810 face->size.height = size->height;
1811 face->size.width = size->width;
1812 face->size.size = size->size;
1813 face->size.x_ppem = size->x_ppem;
1814 face->size.y_ppem = size->y_ppem;
1815 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1816 face->scalable = FALSE;
1819 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
1820 face->flags = flags;
1821 face->family = NULL;
1822 face->cached_enum_data = NULL;
1824 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1825 face->fs.fsCsb[0], face->fs.fsCsb[1],
1826 face->fs.fsUsb[0], face->fs.fsUsb[1],
1827 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1829 return face;
1832 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1833 FT_Long face_index, DWORD flags )
1835 Face *face;
1836 Family *family;
1838 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags );
1839 family = get_family( ft_face, flags & ADDFONT_VERTICAL_FONT );
1840 if (insert_face_in_family_list( face, family ))
1842 if (flags & ADDFONT_ADD_TO_CACHE)
1843 add_face_to_cache( face );
1845 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1846 debugstr_w(face->StyleName));
1848 release_face( face );
1849 release_family( family );
1852 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1853 FT_Long face_index, BOOL allow_bitmap )
1855 FT_Error err;
1856 TT_OS2 *pOS2;
1857 FT_Face ft_face;
1859 if (file)
1861 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1862 err = pFT_New_Face(library, file, face_index, &ft_face);
1864 else
1866 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1867 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1870 if (err != 0)
1872 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1873 return NULL;
1876 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1877 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1879 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1880 goto fail;
1883 if (!FT_IS_SFNT( ft_face ))
1885 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1887 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1888 goto fail;
1891 else
1893 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1894 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1895 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1897 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1898 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1899 goto fail;
1902 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1903 we don't want to load these. */
1904 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1906 FT_ULong len = 0;
1908 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1910 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1911 goto fail;
1916 if (!ft_face->family_name || !ft_face->style_name)
1918 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1919 goto fail;
1922 return ft_face;
1923 fail:
1924 pFT_Done_Face( ft_face );
1925 return NULL;
1928 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1930 FT_Face ft_face;
1931 FT_Long face_index = 0, num_faces;
1932 INT ret = 0;
1934 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1935 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1937 #ifdef HAVE_CARBON_CARBON_H
1938 if(file)
1940 char **mac_list = expand_mac_font(file);
1941 if(mac_list)
1943 BOOL had_one = FALSE;
1944 char **cursor;
1945 for(cursor = mac_list; *cursor; cursor++)
1947 had_one = TRUE;
1948 AddFontToList(*cursor, NULL, 0, flags);
1949 HeapFree(GetProcessHeap(), 0, *cursor);
1951 HeapFree(GetProcessHeap(), 0, mac_list);
1952 if(had_one)
1953 return 1;
1956 #endif /* HAVE_CARBON_CARBON_H */
1958 do {
1959 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_ALLOW_BITMAP );
1960 if (!ft_face) return 0;
1962 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1964 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1965 pFT_Done_Face(ft_face);
1966 return 0;
1969 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags);
1970 ++ret;
1972 if (FT_HAS_VERTICAL(ft_face))
1974 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index,
1975 flags | ADDFONT_VERTICAL_FONT);
1976 ++ret;
1979 num_faces = ft_face->num_faces;
1980 pFT_Done_Face(ft_face);
1981 } while(num_faces > ++face_index);
1982 return ret;
1985 static int remove_font_resource( const char *file, DWORD flags )
1987 Family *family, *family_next;
1988 Face *face, *face_next;
1989 char *filename;
1990 struct stat st, st2;
1991 int count = 0;
1993 if (stat( file, &st ) == -1) return 0;
1994 LIST_FOR_EACH_ENTRY_SAFE( family, family_next, &font_list, Family, entry )
1996 family->refcount++;
1997 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, Face, entry )
1999 if (!face->file) continue;
2000 if (LOWORD(face->flags) != LOWORD(flags)) continue;
2001 filename = strWtoA( CP_UNIXCP, face->file );
2002 if (!stat( filename, &st2 ) && st.st_dev == st2.st_dev && st.st_ino == st2.st_ino)
2004 TRACE( "removing matching face %s\n", debugstr_w(face->file) );
2005 release_face( face );
2006 count++;
2008 HeapFree( GetProcessHeap(), 0, filename );
2010 release_family( family );
2012 return count;
2015 static void DumpFontList(void)
2017 Family *family;
2018 Face *face;
2020 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2021 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
2022 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2023 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
2024 if(!face->scalable)
2025 TRACE(" %d", face->size.height);
2026 TRACE("\n");
2029 return;
2032 /***********************************************************
2033 * The replacement list is a way to map an entire font
2034 * family onto another family. For example adding
2036 * [HKCU\Software\Wine\Fonts\Replacements]
2037 * "Wingdings"="Winedings"
2039 * would enumerate the Winedings font both as Winedings and
2040 * Wingdings. However if a real Wingdings font is present the
2041 * replacement does not take place.
2044 static void LoadReplaceList(void)
2046 HKEY hkey;
2047 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2048 LPWSTR value;
2049 LPVOID data;
2051 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2052 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
2054 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2055 &valuelen, &datalen, NULL, NULL);
2057 valuelen++; /* returned value doesn't include room for '\0' */
2058 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2059 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2061 dlen = datalen;
2062 vlen = valuelen;
2063 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
2064 &dlen) == ERROR_SUCCESS) {
2065 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
2066 /* "NewName"="Oldname" */
2067 if(!find_family_from_any_name(value))
2069 Family * const family = find_family_from_any_name(data);
2070 if (family != NULL)
2072 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2073 if (new_family != NULL)
2075 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
2076 new_family->FamilyName = strdupW(value);
2077 new_family->EnglishName = NULL;
2078 list_init(&new_family->faces);
2079 new_family->replacement = &family->faces;
2080 list_add_tail(&font_list, &new_family->entry);
2083 else
2085 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2088 else
2090 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2092 /* reset dlen and vlen */
2093 dlen = datalen;
2094 vlen = valuelen;
2096 HeapFree(GetProcessHeap(), 0, data);
2097 HeapFree(GetProcessHeap(), 0, value);
2098 RegCloseKey(hkey);
2102 static const WCHAR *font_links_list[] =
2104 Lucida_Sans_Unicode,
2105 Microsoft_Sans_Serif,
2106 Tahoma
2109 static const struct font_links_defaults_list
2111 /* Keyed off substitution for "MS Shell Dlg" */
2112 const WCHAR *shelldlg;
2113 /* Maximum of four substitutes, plus terminating NULL pointer */
2114 const WCHAR *substitutes[5];
2115 } font_links_defaults_list[] =
2117 /* Non East-Asian */
2118 { Tahoma, /* FIXME unverified ordering */
2119 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2121 /* Below lists are courtesy of
2122 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2124 /* Japanese */
2125 { MS_UI_Gothic,
2126 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2128 /* Chinese Simplified */
2129 { SimSun,
2130 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2132 /* Korean */
2133 { Gulim,
2134 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2136 /* Chinese Traditional */
2137 { PMingLiU,
2138 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2143 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2145 SYSTEM_LINKS *font_link;
2147 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2149 if(!strcmpiW(font_link->font_name, name))
2150 return font_link;
2153 return NULL;
2156 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2158 const WCHAR *value;
2159 int i;
2160 FontSubst *psub;
2161 Family *family;
2162 Face *face;
2163 const WCHAR *file;
2165 if (values)
2167 SYSTEM_LINKS *font_link;
2169 psub = get_font_subst(&font_subst_list, name, -1);
2170 /* Don't store fonts that are only substitutes for other fonts */
2171 if(psub)
2173 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2174 return;
2177 font_link = find_font_link(name);
2178 if (font_link == NULL)
2180 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2181 font_link->font_name = strdupW(name);
2182 list_init(&font_link->links);
2183 list_add_tail(&system_links, &font_link->entry);
2186 memset(&font_link->fs, 0, sizeof font_link->fs);
2187 for (i = 0; values[i] != NULL; i++)
2189 const struct list *face_list;
2190 CHILD_FONT *child_font;
2192 value = values[i];
2193 if (!strcmpiW(name,value))
2194 continue;
2195 psub = get_font_subst(&font_subst_list, value, -1);
2196 if(psub)
2197 value = psub->to.name;
2198 family = find_family_from_name(value);
2199 if (!family)
2200 continue;
2201 file = NULL;
2202 /* Use first extant filename for this Family */
2203 face_list = get_face_list_from_family(family);
2204 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2206 if (!face->file)
2207 continue;
2208 file = strrchrW(face->file, '/');
2209 if (!file)
2210 file = face->file;
2211 else
2212 file++;
2213 break;
2215 if (!file)
2216 continue;
2217 face = find_face_from_filename(file, value);
2218 if(!face)
2220 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2221 continue;
2224 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2225 child_font->face = face;
2226 child_font->font = NULL;
2227 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2228 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2229 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2230 child_font->face->face_index);
2231 list_add_tail(&font_link->links, &child_font->entry);
2233 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2239 /*************************************************************
2240 * init_system_links
2242 static BOOL init_system_links(void)
2244 HKEY hkey;
2245 BOOL ret = FALSE;
2246 DWORD type, max_val, max_data, val_len, data_len, index;
2247 WCHAR *value, *data;
2248 WCHAR *entry, *next;
2249 SYSTEM_LINKS *font_link, *system_font_link;
2250 CHILD_FONT *child_font;
2251 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2252 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2253 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2254 Face *face;
2255 FontSubst *psub;
2256 UINT i, j;
2258 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2260 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2261 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2262 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2263 val_len = max_val + 1;
2264 data_len = max_data;
2265 index = 0;
2266 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2268 psub = get_font_subst(&font_subst_list, value, -1);
2269 /* Don't store fonts that are only substitutes for other fonts */
2270 if(psub)
2272 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2273 goto next;
2275 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2276 font_link->font_name = strdupW(value);
2277 memset(&font_link->fs, 0, sizeof font_link->fs);
2278 list_init(&font_link->links);
2279 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2281 WCHAR *face_name;
2282 CHILD_FONT *child_font;
2284 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2286 next = entry + strlenW(entry) + 1;
2288 face_name = strchrW(entry, ',');
2289 if(face_name)
2291 *face_name++ = 0;
2292 while(isspaceW(*face_name))
2293 face_name++;
2295 psub = get_font_subst(&font_subst_list, face_name, -1);
2296 if(psub)
2297 face_name = psub->to.name;
2299 face = find_face_from_filename(entry, face_name);
2300 if(!face)
2302 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2303 continue;
2306 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2307 child_font->face = face;
2308 child_font->font = NULL;
2309 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2310 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2311 TRACE("Adding file %s index %ld\n",
2312 debugstr_w(child_font->face->file), child_font->face->face_index);
2313 list_add_tail(&font_link->links, &child_font->entry);
2315 list_add_tail(&system_links, &font_link->entry);
2316 next:
2317 val_len = max_val + 1;
2318 data_len = max_data;
2321 HeapFree(GetProcessHeap(), 0, value);
2322 HeapFree(GetProcessHeap(), 0, data);
2323 RegCloseKey(hkey);
2327 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2328 if (!psub) {
2329 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2330 goto skip_internal;
2333 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2335 const FontSubst *psub2;
2336 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2338 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2340 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2341 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2343 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2344 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2346 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2348 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2352 skip_internal:
2354 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2355 that Tahoma has */
2357 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2358 system_font_link->font_name = strdupW(System);
2359 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2360 list_init(&system_font_link->links);
2362 face = find_face_from_filename(tahoma_ttf, Tahoma);
2363 if(face)
2365 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2366 child_font->face = face;
2367 child_font->font = NULL;
2368 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2369 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2370 TRACE("Found Tahoma in %s index %ld\n",
2371 debugstr_w(child_font->face->file), child_font->face->face_index);
2372 list_add_tail(&system_font_link->links, &child_font->entry);
2374 font_link = find_font_link(Tahoma);
2375 if (font_link != NULL)
2377 CHILD_FONT *font_link_entry;
2378 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2380 CHILD_FONT *new_child;
2381 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2382 new_child->face = font_link_entry->face;
2383 new_child->font = NULL;
2384 new_child->face->refcount++;
2385 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2386 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2387 list_add_tail(&system_font_link->links, &new_child->entry);
2390 list_add_tail(&system_links, &system_font_link->entry);
2391 return ret;
2394 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2396 DIR *dir;
2397 struct dirent *dent;
2398 char path[MAX_PATH];
2400 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2402 dir = opendir(dirname);
2403 if(!dir) {
2404 WARN("Can't open directory %s\n", debugstr_a(dirname));
2405 return FALSE;
2407 while((dent = readdir(dir)) != NULL) {
2408 struct stat statbuf;
2410 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2411 continue;
2413 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2415 sprintf(path, "%s/%s", dirname, dent->d_name);
2417 if(stat(path, &statbuf) == -1)
2419 WARN("Can't stat %s\n", debugstr_a(path));
2420 continue;
2422 if(S_ISDIR(statbuf.st_mode))
2423 ReadFontDir(path, external_fonts);
2424 else
2426 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2427 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2428 AddFontToList(path, NULL, 0, addfont_flags);
2431 closedir(dir);
2432 return TRUE;
2435 #ifdef SONAME_LIBFONTCONFIG
2437 static BOOL fontconfig_enabled;
2439 static UINT parse_aa_pattern( FcPattern *pattern )
2441 FcBool antialias;
2442 int rgba;
2443 UINT aa_flags = 0;
2445 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2446 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2448 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2450 switch (rgba)
2452 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2453 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2454 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2455 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2456 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2459 return aa_flags;
2462 static void init_fontconfig(void)
2464 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2466 if (!fc_handle)
2468 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2469 return;
2472 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2473 LOAD_FUNCPTR(FcConfigSubstitute);
2474 LOAD_FUNCPTR(FcFontList);
2475 LOAD_FUNCPTR(FcFontSetDestroy);
2476 LOAD_FUNCPTR(FcInit);
2477 LOAD_FUNCPTR(FcObjectSetAdd);
2478 LOAD_FUNCPTR(FcObjectSetCreate);
2479 LOAD_FUNCPTR(FcObjectSetDestroy);
2480 LOAD_FUNCPTR(FcPatternCreate);
2481 LOAD_FUNCPTR(FcPatternDestroy);
2482 LOAD_FUNCPTR(FcPatternGetBool);
2483 LOAD_FUNCPTR(FcPatternGetInteger);
2484 LOAD_FUNCPTR(FcPatternGetString);
2485 #undef LOAD_FUNCPTR
2487 if (pFcInit())
2489 FcPattern *pattern = pFcPatternCreate();
2490 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2491 default_aa_flags = parse_aa_pattern( pattern );
2492 pFcPatternDestroy( pattern );
2493 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2494 fontconfig_enabled = TRUE;
2498 static void load_fontconfig_fonts(void)
2500 FcPattern *pat;
2501 FcObjectSet *os;
2502 FcFontSet *fontset;
2503 int i, len;
2504 char *file;
2505 const char *ext;
2507 if (!fontconfig_enabled) return;
2509 pat = pFcPatternCreate();
2510 os = pFcObjectSetCreate();
2511 pFcObjectSetAdd(os, FC_FILE);
2512 pFcObjectSetAdd(os, FC_SCALABLE);
2513 pFcObjectSetAdd(os, FC_ANTIALIAS);
2514 pFcObjectSetAdd(os, FC_RGBA);
2515 fontset = pFcFontList(NULL, pat, os);
2516 if(!fontset) return;
2517 for(i = 0; i < fontset->nfont; i++) {
2518 FcBool scalable;
2519 DWORD aa_flags;
2521 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2522 continue;
2524 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2526 /* We're just interested in OT/TT fonts for now, so this hack just
2527 picks up the scalable fonts without extensions .pf[ab] to save time
2528 loading every other font */
2530 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2532 TRACE("not scalable\n");
2533 continue;
2536 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2537 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2539 len = strlen( file );
2540 if(len < 4) continue;
2541 ext = &file[ len - 3 ];
2542 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2543 AddFontToList(file, NULL, 0,
2544 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2546 pFcFontSetDestroy(fontset);
2547 pFcObjectSetDestroy(os);
2548 pFcPatternDestroy(pat);
2551 #elif defined(HAVE_CARBON_CARBON_H)
2553 static void load_mac_font_callback(const void *value, void *context)
2555 CFStringRef pathStr = value;
2556 CFIndex len;
2557 char* path;
2559 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2560 path = HeapAlloc(GetProcessHeap(), 0, len);
2561 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2563 TRACE("font file %s\n", path);
2564 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2566 HeapFree(GetProcessHeap(), 0, path);
2569 static void load_mac_fonts(void)
2571 CFStringRef removeDupesKey;
2572 CFBooleanRef removeDupesValue;
2573 CFDictionaryRef options;
2574 CTFontCollectionRef col;
2575 CFArrayRef descs;
2576 CFMutableSetRef paths;
2577 CFIndex i;
2579 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2580 removeDupesValue = kCFBooleanTrue;
2581 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2582 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2583 col = CTFontCollectionCreateFromAvailableFonts(options);
2584 if (options) CFRelease(options);
2585 if (!col)
2587 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2588 return;
2591 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2592 CFRelease(col);
2593 if (!descs)
2595 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2596 return;
2599 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2600 if (!paths)
2602 WARN("CFSetCreateMutable failed\n");
2603 CFRelease(descs);
2604 return;
2607 for (i = 0; i < CFArrayGetCount(descs); i++)
2609 CTFontDescriptorRef desc;
2610 CTFontRef font;
2611 ATSFontRef atsFont;
2612 OSStatus status;
2613 FSRef fsref;
2614 CFURLRef url;
2615 CFStringRef ext;
2616 CFStringRef path;
2618 desc = CFArrayGetValueAtIndex(descs, i);
2620 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2621 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2622 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2623 if (!font) continue;
2625 atsFont = CTFontGetPlatformFont(font, NULL);
2626 if (!atsFont)
2628 CFRelease(font);
2629 continue;
2632 status = ATSFontGetFileReference(atsFont, &fsref);
2633 CFRelease(font);
2634 if (status != noErr) continue;
2636 url = CFURLCreateFromFSRef(NULL, &fsref);
2637 if (!url) continue;
2639 ext = CFURLCopyPathExtension(url);
2640 if (ext)
2642 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2643 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2644 CFRelease(ext);
2645 if (skip)
2647 CFRelease(url);
2648 continue;
2652 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2653 CFRelease(url);
2654 if (!path) continue;
2656 CFSetAddValue(paths, path);
2657 CFRelease(path);
2660 CFRelease(descs);
2662 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2663 CFRelease(paths);
2666 #endif
2668 static char *get_data_dir_path( LPCWSTR file )
2670 char *unix_name = NULL;
2671 const char *data_dir = wine_get_data_dir();
2673 if (!data_dir) data_dir = wine_get_build_dir();
2675 if (data_dir)
2677 INT len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2679 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2680 strcpy(unix_name, data_dir);
2681 strcat(unix_name, "/fonts/");
2683 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2685 return unix_name;
2688 static BOOL load_font_from_data_dir(LPCWSTR file)
2690 BOOL ret = FALSE;
2691 char *unix_name = get_data_dir_path( file );
2693 if (unix_name)
2695 EnterCriticalSection( &freetype_cs );
2696 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
2697 LeaveCriticalSection( &freetype_cs );
2698 HeapFree(GetProcessHeap(), 0, unix_name);
2700 return ret;
2703 static char *get_winfonts_dir_path(LPCWSTR file)
2705 static const WCHAR slashW[] = {'\\','\0'};
2706 WCHAR windowsdir[MAX_PATH];
2708 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2709 strcatW(windowsdir, fontsW);
2710 strcatW(windowsdir, slashW);
2711 strcatW(windowsdir, file);
2712 return wine_get_unix_file_name( windowsdir );
2715 static void load_system_fonts(void)
2717 HKEY hkey;
2718 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2719 const WCHAR * const *value;
2720 DWORD dlen, type;
2721 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2722 char *unixname;
2724 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2725 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2726 strcatW(windowsdir, fontsW);
2727 for(value = SystemFontValues; *value; value++) {
2728 dlen = sizeof(data);
2729 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2730 type == REG_SZ) {
2731 BOOL added = FALSE;
2733 sprintfW(pathW, fmtW, windowsdir, data);
2734 if((unixname = wine_get_unix_file_name(pathW))) {
2735 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
2736 HeapFree(GetProcessHeap(), 0, unixname);
2738 if (!added)
2739 load_font_from_data_dir(data);
2742 RegCloseKey(hkey);
2746 /*************************************************************
2748 * This adds registry entries for any externally loaded fonts
2749 * (fonts from fontconfig or FontDirs). It also deletes entries
2750 * of no longer existing fonts.
2753 static void update_reg_entries(void)
2755 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2756 LPWSTR valueW;
2757 DWORD len;
2758 Family *family;
2759 Face *face;
2760 WCHAR *file, *path;
2761 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2763 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2764 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2765 ERR("Can't create Windows font reg key\n");
2766 goto end;
2769 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2770 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2771 ERR("Can't create Windows font reg key\n");
2772 goto end;
2775 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2776 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2777 ERR("Can't create external font reg key\n");
2778 goto end;
2781 /* enumerate the fonts and add external ones to the two keys */
2783 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2784 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2785 char *buffer;
2786 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
2788 if(face->FullName)
2790 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2791 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2792 strcpyW(valueW, face->FullName);
2794 else
2796 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2797 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2798 strcpyW(valueW, family->FamilyName);
2801 buffer = strWtoA( CP_UNIXCP, face->file );
2802 path = wine_get_dos_file_name( buffer );
2803 HeapFree( GetProcessHeap(), 0, buffer );
2805 if (path)
2806 file = path;
2807 else if ((file = strrchrW(face->file, '/')))
2808 file++;
2809 else
2810 file = face->file;
2812 len = strlenW(file) + 1;
2813 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2814 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2815 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2817 HeapFree(GetProcessHeap(), 0, path);
2818 HeapFree(GetProcessHeap(), 0, valueW);
2821 end:
2822 if(external_key) RegCloseKey(external_key);
2823 if(win9x_key) RegCloseKey(win9x_key);
2824 if(winnt_key) RegCloseKey(winnt_key);
2825 return;
2828 static void delete_external_font_keys(void)
2830 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2831 DWORD dlen, vlen, datalen, valuelen, i, type;
2832 LPWSTR valueW;
2833 LPVOID data;
2835 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2836 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2837 ERR("Can't create Windows font reg key\n");
2838 goto end;
2841 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2842 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2843 ERR("Can't create Windows font reg key\n");
2844 goto end;
2847 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2848 ERR("Can't create external font reg key\n");
2849 goto end;
2852 /* Delete all external fonts added last time */
2854 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2855 &valuelen, &datalen, NULL, NULL);
2856 valuelen++; /* returned value doesn't include room for '\0' */
2857 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2858 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2860 dlen = datalen * sizeof(WCHAR);
2861 vlen = valuelen;
2862 i = 0;
2863 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2864 &dlen) == ERROR_SUCCESS) {
2866 RegDeleteValueW(winnt_key, valueW);
2867 RegDeleteValueW(win9x_key, valueW);
2868 /* reset dlen and vlen */
2869 dlen = datalen;
2870 vlen = valuelen;
2872 HeapFree(GetProcessHeap(), 0, data);
2873 HeapFree(GetProcessHeap(), 0, valueW);
2875 /* Delete the old external fonts key */
2876 RegCloseKey(external_key);
2877 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2879 end:
2880 if(win9x_key) RegCloseKey(win9x_key);
2881 if(winnt_key) RegCloseKey(winnt_key);
2884 /*************************************************************
2885 * WineEngAddFontResourceEx
2888 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2890 INT ret = 0;
2892 GDI_CheckNotLock();
2894 if (ft_handle) /* do it only if we have freetype up and running */
2896 char *unixname;
2898 EnterCriticalSection( &freetype_cs );
2900 if((unixname = wine_get_unix_file_name(file)))
2902 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
2904 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2905 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2906 HeapFree(GetProcessHeap(), 0, unixname);
2908 if (!ret && !strchrW(file, '\\')) {
2909 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2910 if ((unixname = get_winfonts_dir_path( file )))
2912 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
2913 HeapFree(GetProcessHeap(), 0, unixname);
2915 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
2916 if (!ret && (unixname = get_data_dir_path( file )))
2918 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
2919 HeapFree(GetProcessHeap(), 0, unixname);
2923 LeaveCriticalSection( &freetype_cs );
2925 return ret;
2928 /*************************************************************
2929 * WineEngAddFontMemResourceEx
2932 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2934 GDI_CheckNotLock();
2936 if (ft_handle) /* do it only if we have freetype up and running */
2938 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2940 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2941 memcpy(pFontCopy, pbFont, cbFont);
2943 EnterCriticalSection( &freetype_cs );
2944 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
2945 LeaveCriticalSection( &freetype_cs );
2947 if (*pcFonts == 0)
2949 TRACE("AddFontToList failed\n");
2950 HeapFree(GetProcessHeap(), 0, pFontCopy);
2951 return 0;
2953 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2954 * For now return something unique but quite random
2956 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2957 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2960 *pcFonts = 0;
2961 return 0;
2964 /*************************************************************
2965 * WineEngRemoveFontResourceEx
2968 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2970 INT ret = 0;
2972 GDI_CheckNotLock();
2974 if (ft_handle) /* do it only if we have freetype up and running */
2976 char *unixname;
2978 EnterCriticalSection( &freetype_cs );
2980 if ((unixname = wine_get_unix_file_name(file)))
2982 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
2984 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2985 ret = remove_font_resource( unixname, addfont_flags );
2986 HeapFree(GetProcessHeap(), 0, unixname);
2988 if (!ret && !strchrW(file, '\\'))
2990 if ((unixname = get_winfonts_dir_path( file )))
2992 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
2993 HeapFree(GetProcessHeap(), 0, unixname);
2995 if (!ret && (unixname = get_data_dir_path( file )))
2997 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
2998 HeapFree(GetProcessHeap(), 0, unixname);
3002 LeaveCriticalSection( &freetype_cs );
3004 return ret;
3007 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
3009 WCHAR *fullname;
3010 char *unix_name;
3011 int file_len;
3013 if (!font_file) return NULL;
3015 file_len = strlenW( font_file );
3017 if (font_path && font_path[0])
3019 int path_len = strlenW( font_path );
3020 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
3021 if (!fullname) return NULL;
3022 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
3023 fullname[path_len] = '\\';
3024 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
3026 else
3028 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
3029 if (!len) return NULL;
3030 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3031 if (!fullname) return NULL;
3032 GetFullPathNameW( font_file, len, fullname, NULL );
3035 unix_name = wine_get_unix_file_name( fullname );
3036 HeapFree( GetProcessHeap(), 0, fullname );
3037 return unix_name;
3040 #include <pshpack1.h>
3041 struct fontdir
3043 WORD num_of_resources;
3044 WORD res_id;
3045 WORD dfVersion;
3046 DWORD dfSize;
3047 CHAR dfCopyright[60];
3048 WORD dfType;
3049 WORD dfPoints;
3050 WORD dfVertRes;
3051 WORD dfHorizRes;
3052 WORD dfAscent;
3053 WORD dfInternalLeading;
3054 WORD dfExternalLeading;
3055 BYTE dfItalic;
3056 BYTE dfUnderline;
3057 BYTE dfStrikeOut;
3058 WORD dfWeight;
3059 BYTE dfCharSet;
3060 WORD dfPixWidth;
3061 WORD dfPixHeight;
3062 BYTE dfPitchAndFamily;
3063 WORD dfAvgWidth;
3064 WORD dfMaxWidth;
3065 BYTE dfFirstChar;
3066 BYTE dfLastChar;
3067 BYTE dfDefaultChar;
3068 BYTE dfBreakChar;
3069 WORD dfWidthBytes;
3070 DWORD dfDevice;
3071 DWORD dfFace;
3072 DWORD dfReserved;
3073 CHAR szFaceName[LF_FACESIZE];
3076 #include <poppack.h>
3078 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
3079 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
3081 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
3083 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3084 Face *face;
3085 WCHAR *name, *english_name;
3086 ENUMLOGFONTEXW elf;
3087 NEWTEXTMETRICEXW ntm;
3088 DWORD type;
3090 if (!ft_face) return FALSE;
3091 face = create_face( ft_face, 0, unix_name, NULL, 0, 0 );
3092 get_family_names( ft_face, &name, &english_name, FALSE );
3093 pFT_Done_Face( ft_face );
3095 GetEnumStructs( face, name, &elf, &ntm, &type );
3096 release_face( face );
3097 HeapFree( GetProcessHeap(), 0, name );
3098 HeapFree( GetProcessHeap(), 0, english_name );
3100 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3102 memset( fd, 0, sizeof(*fd) );
3104 fd->num_of_resources = 1;
3105 fd->res_id = 0;
3106 fd->dfVersion = 0x200;
3107 fd->dfSize = sizeof(*fd);
3108 strcpy( fd->dfCopyright, "Wine fontdir" );
3109 fd->dfType = 0x4003; /* 0x0080 set if private */
3110 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3111 fd->dfVertRes = 72;
3112 fd->dfHorizRes = 72;
3113 fd->dfAscent = ntm.ntmTm.tmAscent;
3114 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3115 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3116 fd->dfItalic = ntm.ntmTm.tmItalic;
3117 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3118 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3119 fd->dfWeight = ntm.ntmTm.tmWeight;
3120 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3121 fd->dfPixWidth = 0;
3122 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3123 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3124 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3125 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3126 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3127 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3128 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3129 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3130 fd->dfWidthBytes = 0;
3131 fd->dfDevice = 0;
3132 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3133 fd->dfReserved = 0;
3134 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3136 return TRUE;
3139 #define NE_FFLAGS_LIBMODULE 0x8000
3140 #define NE_OSFLAGS_WINDOWS 0x02
3142 static const char dos_string[0x40] = "This is a TrueType resource file";
3143 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3145 #include <pshpack2.h>
3147 struct ne_typeinfo
3149 WORD type_id;
3150 WORD count;
3151 DWORD res;
3154 struct ne_nameinfo
3156 WORD off;
3157 WORD len;
3158 WORD flags;
3159 WORD id;
3160 DWORD res;
3163 struct rsrc_tab
3165 WORD align;
3166 struct ne_typeinfo fontdir_type;
3167 struct ne_nameinfo fontdir_name;
3168 struct ne_typeinfo scalable_type;
3169 struct ne_nameinfo scalable_name;
3170 WORD end_of_rsrc;
3171 BYTE fontdir_res_name[8];
3174 #include <poppack.h>
3176 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3178 BOOL ret = FALSE;
3179 HANDLE file;
3180 DWORD size, written;
3181 BYTE *ptr, *start;
3182 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3183 char *font_fileA, *last_part, *ext;
3184 IMAGE_DOS_HEADER dos;
3185 IMAGE_OS2_HEADER ne =
3187 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3188 0, 0, 0, 0, 0, 0,
3189 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3190 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3192 struct rsrc_tab rsrc_tab =
3195 { 0x8007, 1, 0 },
3196 { 0, 0, 0x0c50, 0x2c, 0 },
3197 { 0x80cc, 1, 0 },
3198 { 0, 0, 0x0c50, 0x8001, 0 },
3200 { 7,'F','O','N','T','D','I','R'}
3203 memset( &dos, 0, sizeof(dos) );
3204 dos.e_magic = IMAGE_DOS_SIGNATURE;
3205 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3207 /* import name is last part\0, resident name is last part without extension
3208 non-resident name is "FONTRES:" + lfFaceName */
3210 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3211 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3212 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3214 last_part = strrchr( font_fileA, '\\' );
3215 if (last_part) last_part++;
3216 else last_part = font_fileA;
3217 import_name_len = strlen( last_part ) + 1;
3219 ext = strchr( last_part, '.' );
3220 if (ext) res_name_len = ext - last_part;
3221 else res_name_len = import_name_len - 1;
3223 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3225 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3226 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3227 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3228 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3229 ne.ne_cbenttab = 2;
3230 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3232 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3233 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3234 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3235 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3237 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3238 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3240 if (!ptr)
3242 HeapFree( GetProcessHeap(), 0, font_fileA );
3243 return FALSE;
3246 memcpy( ptr, &dos, sizeof(dos) );
3247 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3248 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3250 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3251 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3253 ptr = start + dos.e_lfanew + ne.ne_restab;
3254 *ptr++ = res_name_len;
3255 memcpy( ptr, last_part, res_name_len );
3257 ptr = start + dos.e_lfanew + ne.ne_imptab;
3258 *ptr++ = import_name_len;
3259 memcpy( ptr, last_part, import_name_len );
3261 ptr = start + ne.ne_nrestab;
3262 *ptr++ = non_res_name_len;
3263 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3264 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3266 ptr = start + (rsrc_tab.scalable_name.off << 4);
3267 memcpy( ptr, font_fileA, font_file_len );
3269 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3270 memcpy( ptr, fontdir, fontdir->dfSize );
3272 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3273 if (file != INVALID_HANDLE_VALUE)
3275 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3276 ret = TRUE;
3277 CloseHandle( file );
3280 HeapFree( GetProcessHeap(), 0, start );
3281 HeapFree( GetProcessHeap(), 0, font_fileA );
3283 return ret;
3286 /*************************************************************
3287 * WineEngCreateScalableFontResource
3290 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3291 LPCWSTR font_file, LPCWSTR font_path )
3293 char *unix_name = get_ttf_file_name( font_file, font_path );
3294 struct fontdir fontdir;
3295 BOOL ret = FALSE;
3297 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3298 SetLastError( ERROR_INVALID_PARAMETER );
3299 else
3301 if (hidden) fontdir.dfType |= 0x80;
3302 ret = create_fot( resource, font_file, &fontdir );
3305 HeapFree( GetProcessHeap(), 0, unix_name );
3306 return ret;
3309 static const struct nls_update_font_list
3311 UINT ansi_cp, oem_cp;
3312 const char *oem, *fixed, *system;
3313 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3314 /* these are for font substitutes */
3315 const char *shelldlg, *tmsrmn;
3316 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3317 *helv_0, *tmsrmn_0;
3318 const struct subst
3320 const char *from, *to;
3321 } arial_0, courier_new_0, times_new_roman_0;
3322 } nls_update_font_list[] =
3324 /* Latin 1 (United States) */
3325 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3326 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3327 "Tahoma","Times New Roman",
3328 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3329 { 0 }, { 0 }, { 0 }
3331 /* Latin 1 (Multilingual) */
3332 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3333 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3334 "Tahoma","Times New Roman", /* FIXME unverified */
3335 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3336 { 0 }, { 0 }, { 0 }
3338 /* Eastern Europe */
3339 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3340 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3341 "Tahoma","Times New Roman", /* FIXME unverified */
3342 "Fixedsys,238", "System,238",
3343 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3344 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3345 { "Arial CE,0", "Arial,238" },
3346 { "Courier New CE,0", "Courier New,238" },
3347 { "Times New Roman CE,0", "Times New Roman,238" }
3349 /* Cyrillic */
3350 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3351 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3352 "Tahoma","Times New Roman", /* FIXME unverified */
3353 "Fixedsys,204", "System,204",
3354 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3355 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3356 { "Arial Cyr,0", "Arial,204" },
3357 { "Courier New Cyr,0", "Courier New,204" },
3358 { "Times New Roman Cyr,0", "Times New Roman,204" }
3360 /* Greek */
3361 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3362 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3363 "Tahoma","Times New Roman", /* FIXME unverified */
3364 "Fixedsys,161", "System,161",
3365 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3366 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3367 { "Arial Greek,0", "Arial,161" },
3368 { "Courier New Greek,0", "Courier New,161" },
3369 { "Times New Roman Greek,0", "Times New Roman,161" }
3371 /* Turkish */
3372 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3373 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3374 "Tahoma","Times New Roman", /* FIXME unverified */
3375 "Fixedsys,162", "System,162",
3376 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3377 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3378 { "Arial Tur,0", "Arial,162" },
3379 { "Courier New Tur,0", "Courier New,162" },
3380 { "Times New Roman Tur,0", "Times New Roman,162" }
3382 /* Hebrew */
3383 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3384 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3385 "Tahoma","Times New Roman", /* FIXME unverified */
3386 "Fixedsys,177", "System,177",
3387 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3388 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3389 { 0 }, { 0 }, { 0 }
3391 /* Arabic */
3392 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3393 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3394 "Tahoma","Times New Roman", /* FIXME unverified */
3395 "Fixedsys,178", "System,178",
3396 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3397 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3398 { 0 }, { 0 }, { 0 }
3400 /* Baltic */
3401 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3402 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3403 "Tahoma","Times New Roman", /* FIXME unverified */
3404 "Fixedsys,186", "System,186",
3405 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3406 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3407 { "Arial Baltic,0", "Arial,186" },
3408 { "Courier New Baltic,0", "Courier New,186" },
3409 { "Times New Roman Baltic,0", "Times New Roman,186" }
3411 /* Vietnamese */
3412 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3413 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3414 "Tahoma","Times New Roman", /* FIXME unverified */
3415 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3416 { 0 }, { 0 }, { 0 }
3418 /* Thai */
3419 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3420 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3421 "Tahoma","Times New Roman", /* FIXME unverified */
3422 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3423 { 0 }, { 0 }, { 0 }
3425 /* Japanese */
3426 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3427 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3428 "MS UI Gothic","MS Serif",
3429 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3430 { 0 }, { 0 }, { 0 }
3432 /* Chinese Simplified */
3433 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3434 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3435 "SimSun", "NSimSun",
3436 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3437 { 0 }, { 0 }, { 0 }
3439 /* Korean */
3440 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3441 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3442 "Gulim", "Batang",
3443 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3444 { 0 }, { 0 }, { 0 }
3446 /* Chinese Traditional */
3447 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3448 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3449 "PMingLiU", "MingLiU",
3450 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3451 { 0 }, { 0 }, { 0 }
3455 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3457 return ( ansi_cp == 932 /* CP932 for Japanese */
3458 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3459 || ansi_cp == 949 /* CP949 for Korean */
3460 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3463 static inline HKEY create_fonts_NT_registry_key(void)
3465 HKEY hkey = 0;
3467 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3468 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3469 return hkey;
3472 static inline HKEY create_fonts_9x_registry_key(void)
3474 HKEY hkey = 0;
3476 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3477 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3478 return hkey;
3481 static inline HKEY create_config_fonts_registry_key(void)
3483 HKEY hkey = 0;
3485 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3486 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3487 return hkey;
3490 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3492 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3494 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3495 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3496 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3497 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3500 static void set_value_key(HKEY hkey, const char *name, const char *value)
3502 if (value)
3503 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3504 else if (name)
3505 RegDeleteValueA(hkey, name);
3508 static void update_font_info(void)
3510 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3511 char buf[40], cpbuf[40];
3512 DWORD len, type;
3513 HKEY hkey = 0;
3514 UINT i, ansi_cp = 0, oem_cp = 0;
3515 DWORD screen_dpi = 96, font_dpi = 0;
3516 BOOL done = FALSE;
3518 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3519 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3520 &hkey) == ERROR_SUCCESS)
3522 reg_load_dword(hkey, logpixels, &screen_dpi);
3523 RegCloseKey(hkey);
3526 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3527 return;
3529 reg_load_dword(hkey, logpixels, &font_dpi);
3531 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3532 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3533 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3534 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3535 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3537 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3538 if (is_dbcs_ansi_cp(ansi_cp))
3539 use_default_fallback = TRUE;
3541 len = sizeof(buf);
3542 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3544 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3546 RegCloseKey(hkey);
3547 return;
3549 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3550 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3552 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3553 ansi_cp, oem_cp, screen_dpi);
3555 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3556 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3557 RegCloseKey(hkey);
3559 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3561 HKEY hkey;
3563 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3564 nls_update_font_list[i].oem_cp == oem_cp)
3566 hkey = create_config_fonts_registry_key();
3567 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3568 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3569 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3570 RegCloseKey(hkey);
3572 hkey = create_fonts_NT_registry_key();
3573 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3574 RegCloseKey(hkey);
3576 hkey = create_fonts_9x_registry_key();
3577 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3578 RegCloseKey(hkey);
3580 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3582 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3583 strlen(nls_update_font_list[i].shelldlg)+1);
3584 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3585 strlen(nls_update_font_list[i].tmsrmn)+1);
3587 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3588 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3589 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3590 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3591 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3592 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3593 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3594 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3596 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3597 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3598 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3600 RegCloseKey(hkey);
3602 done = TRUE;
3604 else
3606 /* Delete the FontSubstitutes from other locales */
3607 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3609 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3610 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3611 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3612 RegCloseKey(hkey);
3616 if (!done)
3617 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3620 static BOOL init_freetype(void)
3622 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3623 if(!ft_handle) {
3624 WINE_MESSAGE(
3625 "Wine cannot find the FreeType font library. To enable Wine to\n"
3626 "use TrueType fonts please install a version of FreeType greater than\n"
3627 "or equal to 2.0.5.\n"
3628 "http://www.freetype.org\n");
3629 return FALSE;
3632 #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;}
3634 LOAD_FUNCPTR(FT_Done_Face)
3635 LOAD_FUNCPTR(FT_Get_Char_Index)
3636 LOAD_FUNCPTR(FT_Get_First_Char)
3637 LOAD_FUNCPTR(FT_Get_Module)
3638 LOAD_FUNCPTR(FT_Get_Next_Char)
3639 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3640 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3641 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3642 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3643 LOAD_FUNCPTR(FT_Init_FreeType)
3644 LOAD_FUNCPTR(FT_Library_Version)
3645 LOAD_FUNCPTR(FT_Load_Glyph)
3646 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3647 LOAD_FUNCPTR(FT_Matrix_Multiply)
3648 #ifndef FT_MULFIX_INLINED
3649 LOAD_FUNCPTR(FT_MulFix)
3650 #endif
3651 LOAD_FUNCPTR(FT_New_Face)
3652 LOAD_FUNCPTR(FT_New_Memory_Face)
3653 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3654 LOAD_FUNCPTR(FT_Outline_Transform)
3655 LOAD_FUNCPTR(FT_Outline_Translate)
3656 LOAD_FUNCPTR(FT_Render_Glyph)
3657 LOAD_FUNCPTR(FT_Select_Charmap)
3658 LOAD_FUNCPTR(FT_Set_Charmap)
3659 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3660 LOAD_FUNCPTR(FT_Vector_Transform)
3661 LOAD_FUNCPTR(FT_Vector_Unit)
3662 #undef LOAD_FUNCPTR
3663 /* Don't warn if these ones are missing */
3664 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3665 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3666 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3667 #endif
3669 if(pFT_Init_FreeType(&library) != 0) {
3670 ERR("Can't init FreeType library\n");
3671 wine_dlclose(ft_handle, NULL, 0);
3672 ft_handle = NULL;
3673 return FALSE;
3675 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3677 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3678 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3679 ((FT_Version.minor << 8) & 0x00ff00) |
3680 ((FT_Version.patch ) & 0x0000ff);
3682 font_driver = &freetype_funcs;
3683 return TRUE;
3685 sym_not_found:
3686 WINE_MESSAGE(
3687 "Wine cannot find certain functions that it needs inside the FreeType\n"
3688 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3689 "FreeType to at least version 2.1.4.\n"
3690 "http://www.freetype.org\n");
3691 wine_dlclose(ft_handle, NULL, 0);
3692 ft_handle = NULL;
3693 return FALSE;
3696 static void init_font_list(void)
3698 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3699 static const WCHAR pathW[] = {'P','a','t','h',0};
3700 HKEY hkey;
3701 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3702 WCHAR windowsdir[MAX_PATH];
3703 char *unixname;
3704 const char *data_dir;
3706 delete_external_font_keys();
3708 /* load the system bitmap fonts */
3709 load_system_fonts();
3711 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3712 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3713 strcatW(windowsdir, fontsW);
3714 if((unixname = wine_get_unix_file_name(windowsdir)))
3716 ReadFontDir(unixname, FALSE);
3717 HeapFree(GetProcessHeap(), 0, unixname);
3720 /* load the system truetype fonts */
3721 data_dir = wine_get_data_dir();
3722 if (!data_dir) data_dir = wine_get_build_dir();
3723 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3725 strcpy(unixname, data_dir);
3726 strcat(unixname, "/fonts/");
3727 ReadFontDir(unixname, TRUE);
3728 HeapFree(GetProcessHeap(), 0, unixname);
3731 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3732 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3733 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3734 will skip these. */
3735 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3736 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3737 &hkey) == ERROR_SUCCESS)
3739 LPWSTR data, valueW;
3740 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3741 &valuelen, &datalen, NULL, NULL);
3743 valuelen++; /* returned value doesn't include room for '\0' */
3744 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3745 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3746 if (valueW && data)
3748 dlen = datalen * sizeof(WCHAR);
3749 vlen = valuelen;
3750 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3751 &dlen) == ERROR_SUCCESS)
3753 if(data[0] && (data[1] == ':'))
3755 if((unixname = wine_get_unix_file_name(data)))
3757 AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3758 HeapFree(GetProcessHeap(), 0, unixname);
3761 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3763 WCHAR pathW[MAX_PATH];
3764 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3765 BOOL added = FALSE;
3767 sprintfW(pathW, fmtW, windowsdir, data);
3768 if((unixname = wine_get_unix_file_name(pathW)))
3770 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3771 HeapFree(GetProcessHeap(), 0, unixname);
3773 if (!added)
3774 load_font_from_data_dir(data);
3776 /* reset dlen and vlen */
3777 dlen = datalen;
3778 vlen = valuelen;
3781 HeapFree(GetProcessHeap(), 0, data);
3782 HeapFree(GetProcessHeap(), 0, valueW);
3783 RegCloseKey(hkey);
3786 #ifdef SONAME_LIBFONTCONFIG
3787 load_fontconfig_fonts();
3788 #elif defined(HAVE_CARBON_CARBON_H)
3789 load_mac_fonts();
3790 #endif
3792 /* then look in any directories that we've specified in the config file */
3793 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3794 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3796 DWORD len;
3797 LPWSTR valueW;
3798 LPSTR valueA, ptr;
3800 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3802 len += sizeof(WCHAR);
3803 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3804 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3806 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3807 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3808 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3809 TRACE( "got font path %s\n", debugstr_a(valueA) );
3810 ptr = valueA;
3811 while (ptr)
3813 const char* home;
3814 LPSTR next = strchr( ptr, ':' );
3815 if (next) *next++ = 0;
3816 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3817 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3819 strcpy( unixname, home );
3820 strcat( unixname, ptr + 1 );
3821 ReadFontDir( unixname, TRUE );
3822 HeapFree( GetProcessHeap(), 0, unixname );
3824 else
3825 ReadFontDir( ptr, TRUE );
3826 ptr = next;
3828 HeapFree( GetProcessHeap(), 0, valueA );
3830 HeapFree( GetProcessHeap(), 0, valueW );
3832 RegCloseKey(hkey);
3836 static BOOL move_to_front(const WCHAR *name)
3838 Family *family, *cursor2;
3839 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3841 if(!strcmpiW(family->FamilyName, name))
3843 list_remove(&family->entry);
3844 list_add_head(&font_list, &family->entry);
3845 return TRUE;
3848 return FALSE;
3851 static BOOL set_default(const WCHAR **name_list)
3853 while (*name_list)
3855 if (move_to_front(*name_list)) return TRUE;
3856 name_list++;
3859 return FALSE;
3862 static void reorder_font_list(void)
3864 set_default( default_serif_list );
3865 set_default( default_fixed_list );
3866 set_default( default_sans_list );
3869 /*************************************************************
3870 * WineEngInit
3872 * Initialize FreeType library and create a list of available faces
3874 BOOL WineEngInit(void)
3876 DWORD disposition;
3877 HANDLE font_mutex;
3879 /* update locale dependent font info in registry */
3880 update_font_info();
3882 if(!init_freetype()) return FALSE;
3884 #ifdef SONAME_LIBFONTCONFIG
3885 init_fontconfig();
3886 #endif
3888 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3890 ERR("Failed to create font mutex\n");
3891 return FALSE;
3893 WaitForSingleObject(font_mutex, INFINITE);
3895 create_font_cache_key(&hkey_font_cache, &disposition);
3897 if(disposition == REG_CREATED_NEW_KEY)
3898 init_font_list();
3899 else
3900 load_font_list_from_cache(hkey_font_cache);
3902 reorder_font_list();
3904 DumpFontList();
3905 LoadSubstList();
3906 DumpSubstList();
3907 LoadReplaceList();
3909 if(disposition == REG_CREATED_NEW_KEY)
3910 update_reg_entries();
3912 init_system_links();
3914 ReleaseMutex(font_mutex);
3915 return TRUE;
3919 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3921 TT_OS2 *pOS2;
3922 TT_HoriHeader *pHori;
3924 LONG ppem;
3926 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3927 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3929 if(height == 0) height = 16;
3931 /* Calc. height of EM square:
3933 * For +ve lfHeight we have
3934 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3935 * Re-arranging gives:
3936 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3938 * For -ve lfHeight we have
3939 * |lfHeight| = ppem
3940 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3941 * with il = winAscent + winDescent - units_per_em]
3945 if(height > 0) {
3946 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3947 ppem = MulDiv(ft_face->units_per_EM, height,
3948 pHori->Ascender - pHori->Descender);
3949 else
3950 ppem = MulDiv(ft_face->units_per_EM, height,
3951 pOS2->usWinAscent + pOS2->usWinDescent);
3953 else
3954 ppem = -height;
3956 return ppem;
3959 static struct font_mapping *map_font_file( const char *name )
3961 struct font_mapping *mapping;
3962 struct stat st;
3963 int fd;
3965 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3966 if (fstat( fd, &st ) == -1) goto error;
3968 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3970 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3972 mapping->refcount++;
3973 close( fd );
3974 return mapping;
3977 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3978 goto error;
3980 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3981 close( fd );
3983 if (mapping->data == MAP_FAILED)
3985 HeapFree( GetProcessHeap(), 0, mapping );
3986 return NULL;
3988 mapping->refcount = 1;
3989 mapping->dev = st.st_dev;
3990 mapping->ino = st.st_ino;
3991 mapping->size = st.st_size;
3992 list_add_tail( &mappings_list, &mapping->entry );
3993 return mapping;
3995 error:
3996 close( fd );
3997 return NULL;
4000 static void unmap_font_file( struct font_mapping *mapping )
4002 if (!--mapping->refcount)
4004 list_remove( &mapping->entry );
4005 munmap( mapping->data, mapping->size );
4006 HeapFree( GetProcessHeap(), 0, mapping );
4010 static LONG load_VDMX(GdiFont*, LONG);
4012 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
4014 FT_Error err;
4015 FT_Face ft_face;
4016 void *data_ptr;
4017 DWORD data_size;
4019 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
4021 if (face->file)
4023 char *filename = strWtoA( CP_UNIXCP, face->file );
4024 font->mapping = map_font_file( filename );
4025 HeapFree( GetProcessHeap(), 0, filename );
4026 if (!font->mapping)
4028 WARN("failed to map %s\n", debugstr_w(face->file));
4029 return 0;
4031 data_ptr = font->mapping->data;
4032 data_size = font->mapping->size;
4034 else
4036 data_ptr = face->font_data_ptr;
4037 data_size = face->font_data_size;
4040 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
4041 if(err) {
4042 ERR("FT_New_Face rets %d\n", err);
4043 return 0;
4046 /* set it here, as load_VDMX needs it */
4047 font->ft_face = ft_face;
4049 if(FT_IS_SCALABLE(ft_face)) {
4050 /* load the VDMX table if we have one */
4051 font->ppem = load_VDMX(font, height);
4052 if(font->ppem == 0)
4053 font->ppem = calc_ppem_for_height(ft_face, height);
4054 TRACE("height %d => ppem %d\n", height, font->ppem);
4056 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
4057 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
4058 } else {
4059 font->ppem = height;
4060 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
4061 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
4063 return ft_face;
4067 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
4069 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4070 a single face with the requested charset. The idea is to check if
4071 the selected font supports the current ANSI codepage, if it does
4072 return the corresponding charset, else return the first charset */
4074 CHARSETINFO csi;
4075 int acp = GetACP(), i;
4076 DWORD fs0;
4078 *cp = acp;
4079 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
4081 const SYSTEM_LINKS *font_link;
4083 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4084 return csi.ciCharset;
4086 font_link = find_font_link(family_name);
4087 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4088 return csi.ciCharset;
4091 for(i = 0; i < 32; i++) {
4092 fs0 = 1L << i;
4093 if(face->fs.fsCsb[0] & fs0) {
4094 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4095 *cp = csi.ciACP;
4096 return csi.ciCharset;
4098 else
4099 FIXME("TCI failing on %x\n", fs0);
4103 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4104 face->fs.fsCsb[0], debugstr_w(face->file));
4105 *cp = acp;
4106 return DEFAULT_CHARSET;
4109 static GdiFont *alloc_font(void)
4111 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4112 ret->refcount = 1;
4113 ret->gmsize = 1;
4114 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4115 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4116 ret->potm = NULL;
4117 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4118 ret->total_kern_pairs = (DWORD)-1;
4119 ret->kern_pairs = NULL;
4120 list_init(&ret->child_fonts);
4121 return ret;
4124 static void free_font(GdiFont *font)
4126 CHILD_FONT *child, *child_next;
4127 DWORD i;
4129 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
4131 list_remove(&child->entry);
4132 if(child->font)
4133 free_font(child->font);
4134 release_face( child->face );
4135 HeapFree(GetProcessHeap(), 0, child);
4138 if (font->ft_face) pFT_Done_Face(font->ft_face);
4139 if (font->mapping) unmap_font_file( font->mapping );
4140 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4141 HeapFree(GetProcessHeap(), 0, font->potm);
4142 HeapFree(GetProcessHeap(), 0, font->name);
4143 for (i = 0; i < font->gmsize; i++)
4144 HeapFree(GetProcessHeap(),0,font->gm[i]);
4145 HeapFree(GetProcessHeap(), 0, font->gm);
4146 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4147 HeapFree(GetProcessHeap(), 0, font);
4151 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4153 FT_Face ft_face = font->ft_face;
4154 FT_ULong len;
4155 FT_Error err;
4157 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4159 if(!buf)
4160 len = 0;
4161 else
4162 len = cbData;
4164 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4166 /* make sure value of len is the value freetype says it needs */
4167 if (buf && len)
4169 FT_ULong needed = 0;
4170 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4171 if( !err && needed < len) len = needed;
4173 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4174 if (err)
4176 TRACE("Can't find table %c%c%c%c\n",
4177 /* bytes were reversed */
4178 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4179 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4180 return GDI_ERROR;
4182 return len;
4185 /*************************************************************
4186 * load_VDMX
4188 * load the vdmx entry for the specified height
4191 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4192 ( ( (FT_ULong)_x4 << 24 ) | \
4193 ( (FT_ULong)_x3 << 16 ) | \
4194 ( (FT_ULong)_x2 << 8 ) | \
4195 (FT_ULong)_x1 )
4197 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4199 typedef struct {
4200 BYTE bCharSet;
4201 BYTE xRatio;
4202 BYTE yStartRatio;
4203 BYTE yEndRatio;
4204 } Ratios;
4206 typedef struct {
4207 WORD recs;
4208 BYTE startsz;
4209 BYTE endsz;
4210 } VDMX_group;
4212 static LONG load_VDMX(GdiFont *font, LONG height)
4214 WORD hdr[3], tmp;
4215 VDMX_group group;
4216 BYTE devXRatio, devYRatio;
4217 USHORT numRecs, numRatios;
4218 DWORD result, offset = -1;
4219 LONG ppem = 0;
4220 int i;
4222 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
4224 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4225 return ppem;
4227 /* FIXME: need the real device aspect ratio */
4228 devXRatio = 1;
4229 devYRatio = 1;
4231 numRecs = GET_BE_WORD(hdr[1]);
4232 numRatios = GET_BE_WORD(hdr[2]);
4234 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4235 for(i = 0; i < numRatios; i++) {
4236 Ratios ratio;
4238 offset = (3 * 2) + (i * sizeof(Ratios));
4239 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4240 offset = -1;
4242 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4244 if((ratio.xRatio == 0 &&
4245 ratio.yStartRatio == 0 &&
4246 ratio.yEndRatio == 0) ||
4247 (devXRatio == ratio.xRatio &&
4248 devYRatio >= ratio.yStartRatio &&
4249 devYRatio <= ratio.yEndRatio))
4251 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4252 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4253 offset = GET_BE_WORD(tmp);
4254 break;
4258 if(offset == -1) {
4259 FIXME("No suitable ratio found\n");
4260 return ppem;
4263 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4264 USHORT recs;
4265 BYTE startsz, endsz;
4266 WORD *vTable;
4268 recs = GET_BE_WORD(group.recs);
4269 startsz = group.startsz;
4270 endsz = group.endsz;
4272 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4274 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4275 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4276 if(result == GDI_ERROR) {
4277 FIXME("Failed to retrieve vTable\n");
4278 goto end;
4281 if(height > 0) {
4282 for(i = 0; i < recs; i++) {
4283 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4284 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4285 ppem = GET_BE_WORD(vTable[i * 3]);
4287 if(yMax + -yMin == height) {
4288 font->yMax = yMax;
4289 font->yMin = yMin;
4290 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4291 break;
4293 if(yMax + -yMin > height) {
4294 if(--i < 0) {
4295 ppem = 0;
4296 goto end; /* failed */
4298 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4299 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4300 ppem = GET_BE_WORD(vTable[i * 3]);
4301 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4302 break;
4305 if(!font->yMax) {
4306 ppem = 0;
4307 TRACE("ppem not found for height %d\n", height);
4310 end:
4311 HeapFree(GetProcessHeap(), 0, vTable);
4314 return ppem;
4317 static void dump_gdi_font_list(void)
4319 GdiFont *font;
4321 TRACE("---------- Font Cache ----------\n");
4322 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct tagGdiFont, entry )
4323 TRACE("font=%p ref=%u %s %d\n", font, font->refcount,
4324 debugstr_w(font->font_desc.lf.lfFaceName), font->font_desc.lf.lfHeight);
4327 static void grab_font( GdiFont *font )
4329 if (!font->refcount++)
4331 list_remove( &font->unused_entry );
4332 unused_font_count--;
4336 static void release_font( GdiFont *font )
4338 if (!font) return;
4339 if (!--font->refcount)
4341 TRACE( "font %p\n", font );
4343 /* add it to the unused list */
4344 list_add_head( &unused_gdi_font_list, &font->unused_entry );
4345 if (unused_font_count > UNUSED_CACHE_SIZE)
4347 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct tagGdiFont, unused_entry );
4348 TRACE( "freeing %p\n", font );
4349 list_remove( &font->entry );
4350 list_remove( &font->unused_entry );
4351 free_font( font );
4353 else unused_font_count++;
4355 if (TRACE_ON(font)) dump_gdi_font_list();
4359 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4361 if(font->font_desc.hash != fd->hash) return TRUE;
4362 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4363 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4364 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4365 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4368 static void calc_hash(FONT_DESC *pfd)
4370 DWORD hash = 0, *ptr, two_chars;
4371 WORD *pwc;
4372 unsigned int i;
4374 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4375 hash ^= *ptr;
4376 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4377 hash ^= *ptr;
4378 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4379 two_chars = *ptr;
4380 pwc = (WCHAR *)&two_chars;
4381 if(!*pwc) break;
4382 *pwc = toupperW(*pwc);
4383 pwc++;
4384 *pwc = toupperW(*pwc);
4385 hash ^= two_chars;
4386 if(!*pwc) break;
4388 hash ^= !pfd->can_use_bitmap;
4389 pfd->hash = hash;
4390 return;
4393 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4395 GdiFont *ret;
4396 FONT_DESC fd;
4398 fd.lf = *plf;
4399 fd.matrix = *pmat;
4400 fd.can_use_bitmap = can_use_bitmap;
4401 calc_hash(&fd);
4403 /* try the in-use list */
4404 LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
4406 if(fontcmp(ret, &fd)) continue;
4407 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4408 list_remove( &ret->entry );
4409 list_add_head( &gdi_font_list, &ret->entry );
4410 grab_font( ret );
4411 return ret;
4413 return NULL;
4416 static void add_to_cache(GdiFont *font)
4418 static DWORD cache_num = 1;
4420 font->cache_num = cache_num++;
4421 list_add_head(&gdi_font_list, &font->entry);
4422 TRACE( "font %p\n", font );
4425 /*************************************************************
4426 * create_child_font_list
4428 static BOOL create_child_font_list(GdiFont *font)
4430 BOOL ret = FALSE;
4431 SYSTEM_LINKS *font_link;
4432 CHILD_FONT *font_link_entry, *new_child;
4433 FontSubst *psub;
4434 WCHAR* font_name;
4436 psub = get_font_subst(&font_subst_list, font->name, -1);
4437 font_name = psub ? psub->to.name : font->name;
4438 font_link = find_font_link(font_name);
4439 if (font_link != NULL)
4441 TRACE("found entry in system list\n");
4442 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4444 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4445 new_child->face = font_link_entry->face;
4446 new_child->font = NULL;
4447 new_child->face->refcount++;
4448 list_add_tail(&font->child_fonts, &new_child->entry);
4449 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4451 ret = TRUE;
4454 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4455 * Sans Serif. This is how asian windows get default fallbacks for fonts
4457 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4458 font->charset != OEM_CHARSET &&
4459 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4461 font_link = find_font_link(szDefaultFallbackLink);
4462 if (font_link != NULL)
4464 TRACE("found entry in default fallback list\n");
4465 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4467 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4468 new_child->face = font_link_entry->face;
4469 new_child->font = NULL;
4470 new_child->face->refcount++;
4471 list_add_tail(&font->child_fonts, &new_child->entry);
4472 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4474 ret = TRUE;
4478 return ret;
4481 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4483 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4485 if (pFT_Set_Charmap)
4487 FT_Int i;
4488 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4490 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4492 for (i = 0; i < ft_face->num_charmaps; i++)
4494 if (ft_face->charmaps[i]->encoding == encoding)
4496 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4497 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4499 switch (ft_face->charmaps[i]->platform_id)
4501 default:
4502 cmap_def = ft_face->charmaps[i];
4503 break;
4504 case 0: /* Apple Unicode */
4505 cmap0 = ft_face->charmaps[i];
4506 break;
4507 case 1: /* Macintosh */
4508 cmap1 = ft_face->charmaps[i];
4509 break;
4510 case 2: /* ISO */
4511 cmap2 = ft_face->charmaps[i];
4512 break;
4513 case 3: /* Microsoft */
4514 cmap3 = ft_face->charmaps[i];
4515 break;
4519 if (cmap3) /* prefer Microsoft cmap table */
4520 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4521 else if (cmap1)
4522 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4523 else if (cmap2)
4524 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4525 else if (cmap0)
4526 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4527 else if (cmap_def)
4528 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4530 return ft_err == FT_Err_Ok;
4533 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4537 /*************************************************************
4538 * freetype_CreateDC
4540 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4541 LPCWSTR output, const DEVMODEW *devmode )
4543 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4545 if (!physdev) return FALSE;
4546 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4547 return TRUE;
4551 /*************************************************************
4552 * freetype_DeleteDC
4554 static BOOL freetype_DeleteDC( PHYSDEV dev )
4556 struct freetype_physdev *physdev = get_freetype_dev( dev );
4557 release_font( physdev->font );
4558 HeapFree( GetProcessHeap(), 0, physdev );
4559 return TRUE;
4562 static FT_Encoding pick_charmap( FT_Face face, int charset )
4564 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
4565 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
4566 const FT_Encoding *encs = regular_order;
4568 if (charset == SYMBOL_CHARSET) encs = symbol_order;
4570 while (*encs != 0)
4572 if (select_charmap( face, *encs )) break;
4573 encs++;
4575 return *encs;
4578 #define GASP_GRIDFIT 0x01
4579 #define GASP_DOGRAY 0x02
4580 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4582 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
4584 DWORD size;
4585 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
4586 WORD *alloced = NULL, *ptr = buf;
4587 WORD num_recs, version;
4588 BOOL ret = FALSE;
4590 *flags = 0;
4591 size = get_font_data( font, GASP_TAG, 0, NULL, 0 );
4592 if (size == GDI_ERROR) return FALSE;
4593 if (size < 4 * sizeof(WORD)) return FALSE;
4594 if (size > sizeof(buf))
4596 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
4597 if (!ptr) return FALSE;
4600 get_font_data( font, GASP_TAG, 0, ptr, size );
4602 version = GET_BE_WORD( *ptr++ );
4603 num_recs = GET_BE_WORD( *ptr++ );
4605 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
4607 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
4608 goto done;
4611 while (num_recs--)
4613 *flags = GET_BE_WORD( *(ptr + 1) );
4614 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
4615 ptr += 2;
4617 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
4618 ret = TRUE;
4620 done:
4621 HeapFree( GetProcessHeap(), 0, alloced );
4622 return ret;
4625 /*************************************************************
4626 * freetype_SelectFont
4628 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
4630 struct freetype_physdev *physdev = get_freetype_dev( dev );
4631 GdiFont *ret;
4632 Face *face, *best, *best_bitmap;
4633 Family *family, *last_resort_family;
4634 const struct list *face_list;
4635 INT height, width = 0;
4636 unsigned int score = 0, new_score;
4637 signed int diff = 0, newdiff;
4638 BOOL bd, it, can_use_bitmap, want_vertical;
4639 LOGFONTW lf;
4640 CHARSETINFO csi;
4641 FMAT2 dcmat;
4642 FontSubst *psub = NULL;
4643 DC *dc = get_dc_ptr( dev->hdc );
4644 const SYSTEM_LINKS *font_link;
4646 if (!hfont) /* notification that the font has been changed by another driver */
4648 release_font( physdev->font );
4649 physdev->font = NULL;
4650 release_dc_ptr( dc );
4651 return 0;
4654 GetObjectW( hfont, sizeof(lf), &lf );
4655 lf.lfWidth = abs(lf.lfWidth);
4657 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4659 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4660 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4661 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4662 lf.lfEscapement);
4664 if(dc->GraphicsMode == GM_ADVANCED)
4666 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4667 /* Try to avoid not necessary glyph transformations */
4668 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4670 lf.lfHeight *= fabs(dcmat.eM11);
4671 lf.lfWidth *= fabs(dcmat.eM11);
4672 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
4675 else
4677 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4678 font scaling abilities. */
4679 dcmat.eM11 = dcmat.eM22 = 1.0;
4680 dcmat.eM21 = dcmat.eM12 = 0;
4681 lf.lfOrientation = lf.lfEscapement;
4682 if (dc->vport2WorldValid)
4684 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4685 lf.lfOrientation = -lf.lfOrientation;
4686 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4687 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4691 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4692 dcmat.eM21, dcmat.eM22);
4694 GDI_CheckNotLock();
4695 EnterCriticalSection( &freetype_cs );
4697 /* check the cache first */
4698 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4699 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4700 goto done;
4703 TRACE("not in cache\n");
4704 ret = alloc_font();
4706 ret->font_desc.matrix = dcmat;
4707 ret->font_desc.lf = lf;
4708 ret->font_desc.can_use_bitmap = can_use_bitmap;
4709 calc_hash(&ret->font_desc);
4711 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4712 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4713 original value lfCharSet. Note this is a special case for
4714 Symbol and doesn't happen at least for "Wingdings*" */
4716 if(!strcmpiW(lf.lfFaceName, SymbolW))
4717 lf.lfCharSet = SYMBOL_CHARSET;
4719 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4720 switch(lf.lfCharSet) {
4721 case DEFAULT_CHARSET:
4722 csi.fs.fsCsb[0] = 0;
4723 break;
4724 default:
4725 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4726 csi.fs.fsCsb[0] = 0;
4727 break;
4731 family = NULL;
4732 if(lf.lfFaceName[0] != '\0') {
4733 CHILD_FONT *font_link_entry;
4734 LPWSTR FaceName = lf.lfFaceName;
4736 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4738 if(psub) {
4739 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4740 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4741 if (psub->to.charset != -1)
4742 lf.lfCharSet = psub->to.charset;
4745 /* We want a match on name and charset or just name if
4746 charset was DEFAULT_CHARSET. If the latter then
4747 we fixup the returned charset later in get_nearest_charset
4748 where we'll either use the charset of the current ansi codepage
4749 or if that's unavailable the first charset that the font supports.
4751 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4752 if (!strcmpiW(family->FamilyName, FaceName) ||
4753 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4755 font_link = find_font_link(family->FamilyName);
4756 face_list = get_face_list_from_family(family);
4757 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4758 if (!(face->scalable || can_use_bitmap))
4759 continue;
4760 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4761 goto found;
4762 if (font_link != NULL &&
4763 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4764 goto found;
4765 if (!csi.fs.fsCsb[0])
4766 goto found;
4771 /* Search by full face name. */
4772 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4773 face_list = get_face_list_from_family(family);
4774 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4775 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4776 (face->scalable || can_use_bitmap))
4778 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4779 goto found_face;
4780 font_link = find_font_link(family->FamilyName);
4781 if (font_link != NULL &&
4782 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4783 goto found_face;
4789 * Try check the SystemLink list first for a replacement font.
4790 * We may find good replacements there.
4792 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4794 if(!strcmpiW(font_link->font_name, FaceName) ||
4795 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4797 TRACE("found entry in system list\n");
4798 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4800 const SYSTEM_LINKS *links;
4802 face = font_link_entry->face;
4803 if (!(face->scalable || can_use_bitmap))
4804 continue;
4805 family = face->family;
4806 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4807 goto found;
4808 links = find_font_link(family->FamilyName);
4809 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4810 goto found;
4816 psub = NULL; /* substitution is no more relevant */
4818 /* If requested charset was DEFAULT_CHARSET then try using charset
4819 corresponding to the current ansi codepage */
4820 if (!csi.fs.fsCsb[0])
4822 INT acp = GetACP();
4823 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4824 FIXME("TCI failed on codepage %d\n", acp);
4825 csi.fs.fsCsb[0] = 0;
4826 } else
4827 lf.lfCharSet = csi.ciCharset;
4830 want_vertical = (lf.lfFaceName[0] == '@');
4832 /* Face families are in the top 4 bits of lfPitchAndFamily,
4833 so mask with 0xF0 before testing */
4835 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4836 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4837 strcpyW(lf.lfFaceName, defFixed);
4838 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4839 strcpyW(lf.lfFaceName, defSerif);
4840 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4841 strcpyW(lf.lfFaceName, defSans);
4842 else
4843 strcpyW(lf.lfFaceName, defSans);
4844 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4845 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4846 font_link = find_font_link(family->FamilyName);
4847 face_list = get_face_list_from_family(family);
4848 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4849 if (!(face->scalable || can_use_bitmap))
4850 continue;
4851 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4852 goto found;
4853 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4854 goto found;
4859 last_resort_family = NULL;
4860 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4861 font_link = find_font_link(family->FamilyName);
4862 face_list = get_face_list_from_family(family);
4863 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4864 if(!(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical &&
4865 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4866 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4867 if(face->scalable)
4868 goto found;
4869 if(can_use_bitmap && !last_resort_family)
4870 last_resort_family = family;
4875 if(last_resort_family) {
4876 family = last_resort_family;
4877 csi.fs.fsCsb[0] = 0;
4878 goto found;
4881 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4882 face_list = get_face_list_from_family(family);
4883 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4884 if(face->scalable && !(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical) {
4885 csi.fs.fsCsb[0] = 0;
4886 WARN("just using first face for now\n");
4887 goto found;
4889 if(can_use_bitmap && !last_resort_family)
4890 last_resort_family = family;
4893 if(!last_resort_family) {
4894 FIXME("can't find a single appropriate font - bailing\n");
4895 free_font(ret);
4896 ret = NULL;
4897 goto done;
4900 WARN("could only find a bitmap font - this will probably look awful!\n");
4901 family = last_resort_family;
4902 csi.fs.fsCsb[0] = 0;
4904 found:
4905 it = lf.lfItalic ? 1 : 0;
4906 bd = lf.lfWeight > 550 ? 1 : 0;
4908 height = lf.lfHeight;
4910 face = best = best_bitmap = NULL;
4911 font_link = find_font_link(family->FamilyName);
4912 face_list = get_face_list_from_family(family);
4913 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4915 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4916 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4917 !csi.fs.fsCsb[0])
4919 BOOL italic, bold;
4921 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4922 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4923 new_score = (italic ^ it) + (bold ^ bd);
4924 if(!best || new_score <= score)
4926 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4927 italic, bold, it, bd);
4928 score = new_score;
4929 best = face;
4930 if(best->scalable && score == 0) break;
4931 if(!best->scalable)
4933 if(height > 0)
4934 newdiff = height - (signed int)(best->size.height);
4935 else
4936 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4937 if(!best_bitmap || new_score < score ||
4938 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4940 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4941 diff = newdiff;
4942 best_bitmap = best;
4943 if(score == 0 && diff == 0) break;
4949 if(best)
4950 face = best->scalable ? best : best_bitmap;
4951 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4952 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4954 found_face:
4955 height = lf.lfHeight;
4957 ret->fs = face->fs;
4959 if(csi.fs.fsCsb[0]) {
4960 ret->charset = lf.lfCharSet;
4961 ret->codepage = csi.ciACP;
4963 else
4964 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4966 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4967 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
4969 ret->aveWidth = height ? lf.lfWidth : 0;
4971 if(!face->scalable) {
4972 /* Windows uses integer scaling factors for bitmap fonts */
4973 INT scale, scaled_height;
4974 GdiFont *cachedfont;
4976 /* FIXME: rotation of bitmap fonts is ignored */
4977 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4978 if (ret->aveWidth)
4979 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4980 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4981 dcmat.eM11 = dcmat.eM22 = 1.0;
4982 /* As we changed the matrix, we need to search the cache for the font again,
4983 * otherwise we might explode the cache. */
4984 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4985 TRACE("Found cached font after non-scalable matrix rescale!\n");
4986 free_font( ret );
4987 ret = cachedfont;
4988 goto done;
4990 calc_hash(&ret->font_desc);
4992 if (height != 0) height = diff;
4993 height += face->size.height;
4995 scale = (height + face->size.height - 1) / face->size.height;
4996 scaled_height = scale * face->size.height;
4997 /* Only jump to the next height if the difference <= 25% original height */
4998 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4999 /* The jump between unscaled and doubled is delayed by 1 */
5000 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
5001 ret->scale_y = scale;
5003 width = face->size.x_ppem >> 6;
5004 height = face->size.y_ppem >> 6;
5006 else
5007 ret->scale_y = 1.0;
5008 TRACE("font scale y: %f\n", ret->scale_y);
5010 ret->ft_face = OpenFontFace(ret, face, width, height);
5012 if (!ret->ft_face)
5014 free_font( ret );
5015 ret = NULL;
5016 goto done;
5019 ret->ntmFlags = face->ntmFlags;
5021 pick_charmap( ret->ft_face, ret->charset );
5023 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
5024 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
5025 ret->underline = lf.lfUnderline ? 0xff : 0;
5026 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
5027 create_child_font_list(ret);
5029 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
5031 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
5032 if (length != GDI_ERROR)
5034 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
5035 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
5036 TRACE("Loaded GSUB table of %i bytes\n",length);
5039 ret->aa_flags = HIWORD( face->flags );
5041 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
5043 add_to_cache(ret);
5044 done:
5045 if (ret)
5047 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
5049 switch (lf.lfQuality)
5051 case NONANTIALIASED_QUALITY:
5052 case ANTIALIASED_QUALITY:
5053 next->funcs->pSelectFont( dev, hfont, aa_flags );
5054 break;
5055 case CLEARTYPE_QUALITY:
5056 case CLEARTYPE_NATURAL_QUALITY:
5057 default:
5058 if (!*aa_flags) *aa_flags = ret->aa_flags;
5059 next->funcs->pSelectFont( dev, hfont, aa_flags );
5061 /* fixup the antialiasing flags for that font */
5062 switch (*aa_flags)
5064 case WINE_GGO_HRGB_BITMAP:
5065 case WINE_GGO_HBGR_BITMAP:
5066 case WINE_GGO_VRGB_BITMAP:
5067 case WINE_GGO_VBGR_BITMAP:
5068 if (is_subpixel_rendering_enabled()) break;
5069 *aa_flags = GGO_GRAY4_BITMAP;
5070 /* fall through */
5071 case GGO_GRAY2_BITMAP:
5072 case GGO_GRAY4_BITMAP:
5073 case GGO_GRAY8_BITMAP:
5074 case WINE_GGO_GRAY16_BITMAP:
5075 if (is_hinting_enabled())
5077 WORD gasp_flags;
5078 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
5080 TRACE( "font %s %d aa disabled by GASP\n",
5081 debugstr_w(lf.lfFaceName), lf.lfHeight );
5082 *aa_flags = GGO_BITMAP;
5087 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5088 release_font( physdev->font );
5089 physdev->font = ret;
5091 LeaveCriticalSection( &freetype_cs );
5092 release_dc_ptr( dc );
5093 return ret ? hfont : 0;
5096 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5098 HRSRC rsrc;
5099 HGLOBAL hMem;
5100 WCHAR *p;
5101 int i;
5103 id += IDS_FIRST_SCRIPT;
5104 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5105 if (!rsrc) return 0;
5106 hMem = LoadResource( gdi32_module, rsrc );
5107 if (!hMem) return 0;
5109 p = LockResource( hMem );
5110 id &= 0x000f;
5111 while (id--) p += *p + 1;
5113 i = min(LF_FACESIZE - 1, *p);
5114 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5115 buffer[i] = 0;
5116 return i;
5120 /***************************************************
5121 * create_enum_charset_list
5123 * This function creates charset enumeration list because in DEFAULT_CHARSET
5124 * case, the ANSI codepage's charset takes precedence over other charsets.
5125 * This function works as a filter other than DEFAULT_CHARSET case.
5127 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5129 CHARSETINFO csi;
5130 DWORD n = 0;
5132 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5133 csi.fs.fsCsb[0] != 0) {
5134 list->element[n].mask = csi.fs.fsCsb[0];
5135 list->element[n].charset = csi.ciCharset;
5136 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5137 n++;
5139 else { /* charset is DEFAULT_CHARSET or invalid. */
5140 INT acp, i;
5141 DWORD mask = 0;
5143 /* Set the current codepage's charset as the first element. */
5144 acp = GetACP();
5145 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5146 csi.fs.fsCsb[0] != 0) {
5147 list->element[n].mask = csi.fs.fsCsb[0];
5148 list->element[n].charset = csi.ciCharset;
5149 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5150 mask |= csi.fs.fsCsb[0];
5151 n++;
5154 /* Fill out left elements. */
5155 for (i = 0; i < 32; i++) {
5156 FONTSIGNATURE fs;
5157 fs.fsCsb[0] = 1L << i;
5158 fs.fsCsb[1] = 0;
5159 if (fs.fsCsb[0] & mask)
5160 continue; /* skip, already added. */
5161 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5162 continue; /* skip, this is an invalid fsCsb bit. */
5164 list->element[n].mask = fs.fsCsb[0];
5165 list->element[n].charset = csi.ciCharset;
5166 load_script_name( i, list->element[n].name );
5167 mask |= fs.fsCsb[0];
5168 n++;
5171 /* add catch all mask for remaining bits */
5172 if (~mask)
5174 list->element[n].mask = ~mask;
5175 list->element[n].charset = DEFAULT_CHARSET;
5176 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5177 n++;
5180 list->total = n;
5182 return n;
5185 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
5186 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5188 GdiFont *font;
5189 LONG width, height;
5191 if (face->cached_enum_data)
5193 TRACE("Cached\n");
5194 *pelf = face->cached_enum_data->elf;
5195 *pntm = face->cached_enum_data->ntm;
5196 *ptype = face->cached_enum_data->type;
5197 return;
5200 font = alloc_font();
5202 if(face->scalable) {
5203 height = 100;
5204 width = 0;
5205 } else {
5206 height = face->size.y_ppem >> 6;
5207 width = face->size.x_ppem >> 6;
5209 font->scale_y = 1.0;
5211 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5213 free_font(font);
5214 return;
5217 font->name = strdupW( family_name );
5218 font->ntmFlags = face->ntmFlags;
5220 if (get_outline_text_metrics(font))
5222 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5224 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5225 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5226 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5228 lstrcpynW(pelf->elfLogFont.lfFaceName,
5229 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5230 LF_FACESIZE);
5231 lstrcpynW(pelf->elfFullName,
5232 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5233 LF_FULLFACESIZE);
5234 lstrcpynW(pelf->elfStyle,
5235 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5236 LF_FACESIZE);
5238 else
5240 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5242 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5243 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5244 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5246 lstrcpynW(pelf->elfLogFont.lfFaceName, family_name, LF_FACESIZE);
5247 if (face->FullName)
5248 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5249 else
5250 lstrcpynW(pelf->elfFullName, family_name, LF_FULLFACESIZE);
5251 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5254 pntm->ntmTm.ntmFlags = face->ntmFlags;
5255 pntm->ntmFontSig = face->fs;
5257 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5259 pelf->elfLogFont.lfEscapement = 0;
5260 pelf->elfLogFont.lfOrientation = 0;
5261 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5262 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5263 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5264 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5265 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5266 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5267 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5268 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5269 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5270 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5271 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5273 *ptype = 0;
5274 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5275 *ptype |= TRUETYPE_FONTTYPE;
5276 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5277 *ptype |= DEVICE_FONTTYPE;
5278 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5279 *ptype |= RASTER_FONTTYPE;
5281 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5282 if (face->cached_enum_data)
5284 face->cached_enum_data->elf = *pelf;
5285 face->cached_enum_data->ntm = *pntm;
5286 face->cached_enum_data->type = *ptype;
5289 free_font(font);
5292 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5294 Face *face;
5295 const struct list *face_list;
5297 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5299 face_list = get_face_list_from_family(family);
5300 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5301 if (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName)) return TRUE;
5303 return FALSE;
5306 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5308 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5310 return (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName));
5313 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5314 FONTENUMPROCW proc, LPARAM lparam)
5316 ENUMLOGFONTEXW elf;
5317 NEWTEXTMETRICEXW ntm;
5318 DWORD type = 0;
5319 DWORD i;
5321 GetEnumStructs(face, face->family->FamilyName, &elf, &ntm, &type);
5322 for(i = 0; i < list->total; i++) {
5323 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5324 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5325 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
5326 i = list->total; /* break out of loop after enumeration */
5328 else
5330 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
5331 /* use the DEFAULT_CHARSET case only if no other charset is present */
5332 if (list->element[i].charset == DEFAULT_CHARSET &&
5333 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
5334 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5335 strcpyW(elf.elfScript, list->element[i].name);
5336 if (!elf.elfScript[0])
5337 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5339 /* Font Replacement */
5340 if (family != face->family)
5342 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5343 if (face->FullName)
5344 strcpyW(elf.elfFullName, face->FullName);
5345 else
5346 strcpyW(elf.elfFullName, family->FamilyName);
5348 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5349 debugstr_w(elf.elfLogFont.lfFaceName),
5350 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5351 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5352 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5353 ntm.ntmTm.ntmFlags);
5354 /* release section before callback (FIXME) */
5355 LeaveCriticalSection( &freetype_cs );
5356 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5357 EnterCriticalSection( &freetype_cs );
5359 return TRUE;
5362 /*************************************************************
5363 * freetype_EnumFonts
5365 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5367 Family *family;
5368 Face *face;
5369 const struct list *face_list;
5370 LOGFONTW lf;
5371 struct enum_charset_list enum_charsets;
5373 if (!plf)
5375 lf.lfCharSet = DEFAULT_CHARSET;
5376 lf.lfPitchAndFamily = 0;
5377 lf.lfFaceName[0] = 0;
5378 plf = &lf;
5381 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5383 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5385 GDI_CheckNotLock();
5386 EnterCriticalSection( &freetype_cs );
5387 if(plf->lfFaceName[0]) {
5388 FontSubst *psub;
5389 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5391 if(psub) {
5392 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5393 debugstr_w(psub->to.name));
5394 lf = *plf;
5395 strcpyW(lf.lfFaceName, psub->to.name);
5396 plf = &lf;
5399 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5400 if (!family_matches(family, plf)) continue;
5401 face_list = get_face_list_from_family(family);
5402 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5403 if (!face_matches(family->FamilyName, face, plf)) continue;
5404 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5407 } else {
5408 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5409 face_list = get_face_list_from_family(family);
5410 face = LIST_ENTRY(list_head(face_list), Face, entry);
5411 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5414 LeaveCriticalSection( &freetype_cs );
5415 return TRUE;
5418 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5420 pt->x.value = vec->x >> 6;
5421 pt->x.fract = (vec->x & 0x3f) << 10;
5422 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5423 pt->y.value = vec->y >> 6;
5424 pt->y.fract = (vec->y & 0x3f) << 10;
5425 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5426 return;
5429 /***************************************************
5430 * According to the MSDN documentation on WideCharToMultiByte,
5431 * certain codepages cannot set the default_used parameter.
5432 * This returns TRUE if the codepage can set that parameter, false else
5433 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5435 static BOOL codepage_sets_default_used(UINT codepage)
5437 switch (codepage)
5439 case CP_UTF7:
5440 case CP_UTF8:
5441 case CP_SYMBOL:
5442 return FALSE;
5443 default:
5444 return TRUE;
5449 * GSUB Table handling functions
5452 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5454 const GSUB_CoverageFormat1* cf1;
5456 cf1 = table;
5458 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5460 int count = GET_BE_WORD(cf1->GlyphCount);
5461 int i;
5462 TRACE("Coverage Format 1, %i glyphs\n",count);
5463 for (i = 0; i < count; i++)
5464 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5465 return i;
5466 return -1;
5468 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5470 const GSUB_CoverageFormat2* cf2;
5471 int i;
5472 int count;
5473 cf2 = (const GSUB_CoverageFormat2*)cf1;
5475 count = GET_BE_WORD(cf2->RangeCount);
5476 TRACE("Coverage Format 2, %i ranges\n",count);
5477 for (i = 0; i < count; i++)
5479 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5480 return -1;
5481 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5482 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5484 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5485 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5488 return -1;
5490 else
5491 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5493 return -1;
5496 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5498 const GSUB_ScriptList *script;
5499 const GSUB_Script *deflt = NULL;
5500 int i;
5501 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5503 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5504 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5506 const GSUB_Script *scr;
5507 int offset;
5509 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5510 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5512 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5513 return scr;
5514 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5515 deflt = scr;
5517 return deflt;
5520 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5522 int i;
5523 int offset;
5524 const GSUB_LangSys *Lang;
5526 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5528 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5530 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5531 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5533 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5534 return Lang;
5536 offset = GET_BE_WORD(script->DefaultLangSys);
5537 if (offset)
5539 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5540 return Lang;
5542 return NULL;
5545 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5547 int i;
5548 const GSUB_FeatureList *feature;
5549 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5551 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5552 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5554 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5555 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5557 const GSUB_Feature *feat;
5558 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5559 return feat;
5562 return NULL;
5565 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5567 int i;
5568 int offset;
5569 const GSUB_LookupList *lookup;
5570 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5572 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5573 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5575 const GSUB_LookupTable *look;
5576 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5577 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5578 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5579 if (GET_BE_WORD(look->LookupType) != 1)
5580 FIXME("We only handle SubType 1\n");
5581 else
5583 int j;
5585 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5587 const GSUB_SingleSubstFormat1 *ssf1;
5588 offset = GET_BE_WORD(look->SubTable[j]);
5589 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5590 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5592 int offset = GET_BE_WORD(ssf1->Coverage);
5593 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5594 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5596 TRACE(" Glyph 0x%x ->",glyph);
5597 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5598 TRACE(" 0x%x\n",glyph);
5601 else
5603 const GSUB_SingleSubstFormat2 *ssf2;
5604 INT index;
5605 INT offset;
5607 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5608 offset = GET_BE_WORD(ssf1->Coverage);
5609 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5610 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5611 TRACE(" Coverage index %i\n",index);
5612 if (index != -1)
5614 TRACE(" Glyph is 0x%x ->",glyph);
5615 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5616 TRACE("0x%x\n",glyph);
5622 return glyph;
5625 static const char* get_opentype_script(const GdiFont *font)
5628 * I am not sure if this is the correct way to generate our script tag
5631 switch (font->charset)
5633 case ANSI_CHARSET: return "latn";
5634 case BALTIC_CHARSET: return "latn"; /* ?? */
5635 case CHINESEBIG5_CHARSET: return "hani";
5636 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5637 case GB2312_CHARSET: return "hani";
5638 case GREEK_CHARSET: return "grek";
5639 case HANGUL_CHARSET: return "hang";
5640 case RUSSIAN_CHARSET: return "cyrl";
5641 case SHIFTJIS_CHARSET: return "kana";
5642 case TURKISH_CHARSET: return "latn"; /* ?? */
5643 case VIETNAMESE_CHARSET: return "latn";
5644 case JOHAB_CHARSET: return "latn"; /* ?? */
5645 case ARABIC_CHARSET: return "arab";
5646 case HEBREW_CHARSET: return "hebr";
5647 case THAI_CHARSET: return "thai";
5648 default: return "latn";
5652 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5654 const GSUB_Header *header;
5655 const GSUB_Script *script;
5656 const GSUB_LangSys *language;
5657 const GSUB_Feature *feature;
5659 if (!font->GSUB_Table)
5660 return glyph;
5662 header = font->GSUB_Table;
5664 script = GSUB_get_script_table(header, get_opentype_script(font));
5665 if (!script)
5667 TRACE("Script not found\n");
5668 return glyph;
5670 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5671 if (!language)
5673 TRACE("Language not found\n");
5674 return glyph;
5676 feature = GSUB_get_feature(header, language, "vrt2");
5677 if (!feature)
5678 feature = GSUB_get_feature(header, language, "vert");
5679 if (!feature)
5681 TRACE("vrt2/vert feature not found\n");
5682 return glyph;
5684 return GSUB_apply_feature(header, feature, glyph);
5687 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5689 FT_UInt glyphId;
5691 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5692 WCHAR wc = (WCHAR)glyph;
5693 BOOL default_used;
5694 BOOL *default_used_pointer;
5695 FT_UInt ret;
5696 char buf;
5697 default_used_pointer = NULL;
5698 default_used = FALSE;
5699 if (codepage_sets_default_used(font->codepage))
5700 default_used_pointer = &default_used;
5701 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5703 if (font->codepage == CP_SYMBOL && wc < 0x100)
5704 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
5705 else
5706 ret = 0;
5708 else
5709 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5710 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5711 return ret;
5714 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5716 if (glyph < 0x100) glyph += 0xf000;
5717 /* there is a number of old pre-Unicode "broken" TTFs, which
5718 do have symbols at U+00XX instead of U+f0XX */
5719 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5720 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5722 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5724 return glyphId;
5727 /*************************************************************
5728 * freetype_GetGlyphIndices
5730 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5732 struct freetype_physdev *physdev = get_freetype_dev( dev );
5733 int i;
5734 WORD default_char;
5735 BOOL got_default = FALSE;
5737 if (!physdev->font)
5739 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5740 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5743 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5745 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5746 got_default = TRUE;
5749 GDI_CheckNotLock();
5750 EnterCriticalSection( &freetype_cs );
5752 for(i = 0; i < count; i++)
5754 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5755 if (pgi[i] == 0)
5757 if (!got_default)
5759 if (FT_IS_SFNT(physdev->font->ft_face))
5761 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5762 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5764 else
5766 TEXTMETRICW textm;
5767 get_text_metrics(physdev->font, &textm);
5768 default_char = textm.tmDefaultChar;
5770 got_default = TRUE;
5772 pgi[i] = default_char;
5775 LeaveCriticalSection( &freetype_cs );
5776 return count;
5779 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5781 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5782 return !memcmp(matrix, &identity, sizeof(FMAT2));
5785 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5787 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5788 return !memcmp(matrix, &identity, sizeof(MAT2));
5791 static inline BYTE get_max_level( UINT format )
5793 switch( format )
5795 case GGO_GRAY2_BITMAP: return 4;
5796 case GGO_GRAY4_BITMAP: return 16;
5797 case GGO_GRAY8_BITMAP: return 64;
5799 return 255;
5802 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5804 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5805 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
5806 const MAT2* lpmat)
5808 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5809 FT_Face ft_face = incoming_font->ft_face;
5810 GdiFont *font = incoming_font;
5811 FT_UInt glyph_index;
5812 DWORD width, height, pitch, needed = 0;
5813 FT_Bitmap ft_bitmap;
5814 FT_Error err;
5815 INT left, right, top = 0, bottom = 0, adv;
5816 FT_Angle angle = 0;
5817 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5818 double widthRatio = 1.0;
5819 FT_Matrix transMat = identityMat;
5820 FT_Matrix transMatUnrotated;
5821 BOOL needsTransform = FALSE;
5822 BOOL tategaki = (font->GSUB_Table != NULL);
5823 UINT original_index;
5824 FT_Fixed avgAdvance = 0;
5826 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5827 buflen, buf, lpmat);
5829 TRACE("font transform %f %f %f %f\n",
5830 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5831 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5833 if(format & GGO_GLYPH_INDEX) {
5834 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5835 original_index = glyph;
5836 format &= ~GGO_GLYPH_INDEX;
5837 } else {
5838 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5839 ft_face = font->ft_face;
5840 original_index = glyph_index;
5843 if(format & GGO_UNHINTED) {
5844 load_flags |= FT_LOAD_NO_HINTING;
5845 format &= ~GGO_UNHINTED;
5848 /* tategaki never appears to happen to lower glyph index */
5849 if (glyph_index < TATEGAKI_LOWER_BOUND )
5850 tategaki = FALSE;
5852 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5853 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5854 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5855 font->gmsize * sizeof(GM*));
5856 } else {
5857 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5858 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5860 *lpgm = FONT_GM(font,original_index)->gm;
5861 *abc = FONT_GM(font,original_index)->abc;
5862 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5863 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5864 lpgm->gmCellIncX, lpgm->gmCellIncY);
5865 return 1; /* FIXME */
5869 if (!font->gm[original_index / GM_BLOCK_SIZE])
5870 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5872 /* Scaling factor */
5873 if (font->aveWidth)
5875 TEXTMETRICW tm;
5877 get_text_metrics(font, &tm);
5879 widthRatio = (double)font->aveWidth;
5880 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5882 else
5883 widthRatio = font->scale_y;
5885 /* Scaling transform */
5886 if (widthRatio != 1.0 || font->scale_y != 1.0)
5888 FT_Matrix scaleMat;
5889 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5890 scaleMat.xy = 0;
5891 scaleMat.yx = 0;
5892 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5894 pFT_Matrix_Multiply(&scaleMat, &transMat);
5895 needsTransform = TRUE;
5898 /* Slant transform */
5899 if (font->fake_italic) {
5900 FT_Matrix slantMat;
5902 slantMat.xx = (1 << 16);
5903 slantMat.xy = ((1 << 16) >> 2);
5904 slantMat.yx = 0;
5905 slantMat.yy = (1 << 16);
5906 pFT_Matrix_Multiply(&slantMat, &transMat);
5907 needsTransform = TRUE;
5910 /* Rotation transform */
5911 transMatUnrotated = transMat;
5912 if(font->orientation && !tategaki) {
5913 FT_Matrix rotationMat;
5914 FT_Vector vecAngle;
5915 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5916 pFT_Vector_Unit(&vecAngle, angle);
5917 rotationMat.xx = vecAngle.x;
5918 rotationMat.xy = -vecAngle.y;
5919 rotationMat.yx = -rotationMat.xy;
5920 rotationMat.yy = rotationMat.xx;
5922 pFT_Matrix_Multiply(&rotationMat, &transMat);
5923 needsTransform = TRUE;
5926 /* World transform */
5927 if (!is_identity_FMAT2(&font->font_desc.matrix))
5929 FT_Matrix worldMat;
5930 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5931 worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21);
5932 worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12);
5933 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5934 pFT_Matrix_Multiply(&worldMat, &transMat);
5935 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5936 needsTransform = TRUE;
5939 /* Extra transformation specified by caller */
5940 if (!is_identity_MAT2(lpmat))
5942 FT_Matrix extraMat;
5943 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5944 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
5945 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
5946 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5947 pFT_Matrix_Multiply(&extraMat, &transMat);
5948 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5949 needsTransform = TRUE;
5952 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
5954 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5956 if(err) {
5957 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5958 return GDI_ERROR;
5961 if(FT_IS_SCALABLE(incoming_font->ft_face)) {
5962 TEXTMETRICW tm;
5963 if (get_text_metrics(incoming_font, &tm) &&
5964 !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
5965 avgAdvance = pFT_MulFix(incoming_font->ntmAvgWidth,
5966 incoming_font->ft_face->size->metrics.x_scale);
5967 if (avgAdvance && (ft_face->glyph->metrics.horiAdvance+63) >> 6 == (avgAdvance*2+63) >> 6)
5968 TRACE("Fixed-pitch full-width character detected\n");
5969 else
5970 avgAdvance = 0; /* cancel this feature */
5974 if(!needsTransform) {
5975 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5976 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5977 if (!avgAdvance)
5978 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5979 else
5980 adv = (INT)((avgAdvance + 32) >> 6) * 2;
5982 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5983 bottom = (ft_face->glyph->metrics.horiBearingY -
5984 ft_face->glyph->metrics.height) & -64;
5985 lpgm->gmCellIncX = adv;
5986 lpgm->gmCellIncY = 0;
5987 } else {
5988 INT xc, yc;
5989 FT_Vector vec;
5991 left = right = 0;
5993 for(xc = 0; xc < 2; xc++) {
5994 for(yc = 0; yc < 2; yc++) {
5995 vec.x = (ft_face->glyph->metrics.horiBearingX +
5996 xc * ft_face->glyph->metrics.width);
5997 vec.y = ft_face->glyph->metrics.horiBearingY -
5998 yc * ft_face->glyph->metrics.height;
5999 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
6000 pFT_Vector_Transform(&vec, &transMat);
6001 if(xc == 0 && yc == 0) {
6002 left = right = vec.x;
6003 top = bottom = vec.y;
6004 } else {
6005 if(vec.x < left) left = vec.x;
6006 else if(vec.x > right) right = vec.x;
6007 if(vec.y < bottom) bottom = vec.y;
6008 else if(vec.y > top) top = vec.y;
6012 left = left & -64;
6013 right = (right + 63) & -64;
6014 bottom = bottom & -64;
6015 top = (top + 63) & -64;
6017 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
6018 vec.x = ft_face->glyph->metrics.horiAdvance;
6019 vec.y = 0;
6020 pFT_Vector_Transform(&vec, &transMat);
6021 lpgm->gmCellIncY = -((vec.y+63) >> 6);
6022 if (!avgAdvance || vec.y)
6023 lpgm->gmCellIncX = (vec.x+63) >> 6;
6024 else {
6025 vec.x = avgAdvance;
6026 vec.y = 0;
6027 pFT_Vector_Transform(&vec, &transMat);
6028 lpgm->gmCellIncX = ((vec.x+32) >> 6) * 2;
6031 vec.x = ft_face->glyph->metrics.horiAdvance;
6032 vec.y = 0;
6033 pFT_Vector_Transform(&vec, &transMatUnrotated);
6034 if (!avgAdvance || vec.y)
6035 adv = (vec.x+63) >> 6;
6036 else {
6037 vec.x = avgAdvance;
6038 vec.y = 0;
6039 pFT_Vector_Transform(&vec, &transMatUnrotated);
6040 adv = ((vec.x+32) >> 6) * 2;
6044 lpgm->gmBlackBoxX = (right - left) >> 6;
6045 lpgm->gmBlackBoxY = (top - bottom) >> 6;
6046 lpgm->gmptGlyphOrigin.x = left >> 6;
6047 lpgm->gmptGlyphOrigin.y = top >> 6;
6048 abc->abcA = left >> 6;
6049 abc->abcB = (right - left) >> 6;
6050 abc->abcC = adv - abc->abcA - abc->abcB;
6052 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6053 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6054 lpgm->gmCellIncX, lpgm->gmCellIncY);
6056 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
6057 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
6059 FONT_GM(font,original_index)->gm = *lpgm;
6060 FONT_GM(font,original_index)->abc = *abc;
6061 FONT_GM(font,original_index)->init = TRUE;
6064 if(format == GGO_METRICS)
6066 return 1; /* FIXME */
6069 if(ft_face->glyph->format != ft_glyph_format_outline &&
6070 (format == GGO_NATIVE || format == GGO_BEZIER))
6072 TRACE("loaded a bitmap\n");
6073 return GDI_ERROR;
6076 switch(format) {
6077 case GGO_BITMAP:
6078 width = lpgm->gmBlackBoxX;
6079 height = lpgm->gmBlackBoxY;
6080 pitch = ((width + 31) >> 5) << 2;
6081 needed = pitch * height;
6083 if(!buf || !buflen) break;
6085 switch(ft_face->glyph->format) {
6086 case ft_glyph_format_bitmap:
6088 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6089 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
6090 INT h = ft_face->glyph->bitmap.rows;
6091 while(h--) {
6092 memcpy(dst, src, w);
6093 src += ft_face->glyph->bitmap.pitch;
6094 dst += pitch;
6096 break;
6099 case ft_glyph_format_outline:
6100 ft_bitmap.width = width;
6101 ft_bitmap.rows = height;
6102 ft_bitmap.pitch = pitch;
6103 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
6104 ft_bitmap.buffer = buf;
6106 if(needsTransform)
6107 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6109 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6111 /* Note: FreeType will only set 'black' bits for us. */
6112 memset(buf, 0, needed);
6113 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6114 break;
6116 default:
6117 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6118 return GDI_ERROR;
6120 break;
6122 case GGO_GRAY2_BITMAP:
6123 case GGO_GRAY4_BITMAP:
6124 case GGO_GRAY8_BITMAP:
6125 case WINE_GGO_GRAY16_BITMAP:
6127 unsigned int max_level, row, col;
6128 BYTE *start, *ptr;
6130 width = lpgm->gmBlackBoxX;
6131 height = lpgm->gmBlackBoxY;
6132 pitch = (width + 3) / 4 * 4;
6133 needed = pitch * height;
6135 if(!buf || !buflen) break;
6137 max_level = get_max_level( format );
6139 switch(ft_face->glyph->format) {
6140 case ft_glyph_format_bitmap:
6142 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6143 INT h = ft_face->glyph->bitmap.rows;
6144 INT x;
6145 memset( buf, 0, needed );
6146 while(h--) {
6147 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
6148 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
6149 src += ft_face->glyph->bitmap.pitch;
6150 dst += pitch;
6152 return needed;
6154 case ft_glyph_format_outline:
6156 ft_bitmap.width = width;
6157 ft_bitmap.rows = height;
6158 ft_bitmap.pitch = pitch;
6159 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6160 ft_bitmap.buffer = buf;
6162 if(needsTransform)
6163 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6165 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6167 memset(ft_bitmap.buffer, 0, buflen);
6169 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6171 if (max_level != 255)
6173 for (row = 0, start = buf; row < height; row++)
6175 for (col = 0, ptr = start; col < width; col++, ptr++)
6176 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6177 start += pitch;
6180 return needed;
6183 default:
6184 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6185 return GDI_ERROR;
6187 break;
6190 case WINE_GGO_HRGB_BITMAP:
6191 case WINE_GGO_HBGR_BITMAP:
6192 case WINE_GGO_VRGB_BITMAP:
6193 case WINE_GGO_VBGR_BITMAP:
6194 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6196 switch (ft_face->glyph->format)
6198 case FT_GLYPH_FORMAT_BITMAP:
6200 BYTE *src, *dst;
6201 INT src_pitch, x;
6203 width = lpgm->gmBlackBoxX;
6204 height = lpgm->gmBlackBoxY;
6205 pitch = width * 4;
6206 needed = pitch * height;
6208 if (!buf || !buflen) break;
6210 memset(buf, 0, buflen);
6211 dst = buf;
6212 src = ft_face->glyph->bitmap.buffer;
6213 src_pitch = ft_face->glyph->bitmap.pitch;
6215 height = min( height, ft_face->glyph->bitmap.rows );
6216 while ( height-- )
6218 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6220 if ( src[x / 8] & masks[x % 8] )
6221 ((unsigned int *)dst)[x] = ~0u;
6223 src += src_pitch;
6224 dst += pitch;
6227 break;
6230 case FT_GLYPH_FORMAT_OUTLINE:
6232 unsigned int *dst;
6233 BYTE *src;
6234 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6235 INT x_shift, y_shift;
6236 BOOL rgb;
6237 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6238 FT_Render_Mode render_mode =
6239 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6240 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6242 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6244 if ( render_mode == FT_RENDER_MODE_LCD)
6246 lpgm->gmBlackBoxX += 2;
6247 lpgm->gmptGlyphOrigin.x -= 1;
6249 else
6251 lpgm->gmBlackBoxY += 2;
6252 lpgm->gmptGlyphOrigin.y += 1;
6256 width = lpgm->gmBlackBoxX;
6257 height = lpgm->gmBlackBoxY;
6258 pitch = width * 4;
6259 needed = pitch * height;
6261 if (!buf || !buflen) break;
6263 memset(buf, 0, buflen);
6264 dst = buf;
6265 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6267 if ( needsTransform )
6268 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
6270 if ( pFT_Library_SetLcdFilter )
6271 pFT_Library_SetLcdFilter( library, lcdfilter );
6272 pFT_Render_Glyph (ft_face->glyph, render_mode);
6274 src = ft_face->glyph->bitmap.buffer;
6275 src_pitch = ft_face->glyph->bitmap.pitch;
6276 src_width = ft_face->glyph->bitmap.width;
6277 src_height = ft_face->glyph->bitmap.rows;
6279 if ( render_mode == FT_RENDER_MODE_LCD)
6281 rgb_interval = 1;
6282 hmul = 3;
6283 vmul = 1;
6285 else
6287 rgb_interval = src_pitch;
6288 hmul = 1;
6289 vmul = 3;
6292 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6293 if ( x_shift < 0 ) x_shift = 0;
6294 if ( x_shift + (src_width / hmul) > width )
6295 x_shift = width - (src_width / hmul);
6297 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6298 if ( y_shift < 0 ) y_shift = 0;
6299 if ( y_shift + (src_height / vmul) > height )
6300 y_shift = height - (src_height / vmul);
6302 dst += x_shift + y_shift * ( pitch / 4 );
6303 while ( src_height )
6305 for ( x = 0; x < src_width / hmul; x++ )
6307 if ( rgb )
6309 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6310 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6311 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6312 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6314 else
6316 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6317 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6318 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6319 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6322 src += src_pitch * vmul;
6323 dst += pitch / 4;
6324 src_height -= vmul;
6327 break;
6330 default:
6331 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6332 return GDI_ERROR;
6335 break;
6337 #else
6338 return GDI_ERROR;
6339 #endif
6341 case GGO_NATIVE:
6343 int contour, point = 0, first_pt;
6344 FT_Outline *outline = &ft_face->glyph->outline;
6345 TTPOLYGONHEADER *pph;
6346 TTPOLYCURVE *ppc;
6347 DWORD pph_start, cpfx, type;
6349 if(buflen == 0) buf = NULL;
6351 if (needsTransform && buf) {
6352 pFT_Outline_Transform(outline, &transMat);
6355 for(contour = 0; contour < outline->n_contours; contour++) {
6356 /* Ignore contours containing one point */
6357 if(point == outline->contours[contour]) {
6358 point++;
6359 continue;
6362 pph_start = needed;
6363 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6364 first_pt = point;
6365 if(buf) {
6366 pph->dwType = TT_POLYGON_TYPE;
6367 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6369 needed += sizeof(*pph);
6370 point++;
6371 while(point <= outline->contours[contour]) {
6372 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6373 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6374 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6375 cpfx = 0;
6376 do {
6377 if(buf)
6378 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6379 cpfx++;
6380 point++;
6381 } while(point <= outline->contours[contour] &&
6382 (outline->tags[point] & FT_Curve_Tag_On) ==
6383 (outline->tags[point-1] & FT_Curve_Tag_On));
6384 /* At the end of a contour Windows adds the start point, but
6385 only for Beziers */
6386 if(point > outline->contours[contour] &&
6387 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6388 if(buf)
6389 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6390 cpfx++;
6391 } else if(point <= outline->contours[contour] &&
6392 outline->tags[point] & FT_Curve_Tag_On) {
6393 /* add closing pt for bezier */
6394 if(buf)
6395 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6396 cpfx++;
6397 point++;
6399 if(buf) {
6400 ppc->wType = type;
6401 ppc->cpfx = cpfx;
6403 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6405 if(buf)
6406 pph->cb = needed - pph_start;
6408 break;
6410 case GGO_BEZIER:
6412 /* Convert the quadratic Beziers to cubic Beziers.
6413 The parametric eqn for a cubic Bezier is, from PLRM:
6414 r(t) = at^3 + bt^2 + ct + r0
6415 with the control points:
6416 r1 = r0 + c/3
6417 r2 = r1 + (c + b)/3
6418 r3 = r0 + c + b + a
6420 A quadratic Bezier has the form:
6421 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6423 So equating powers of t leads to:
6424 r1 = 2/3 p1 + 1/3 p0
6425 r2 = 2/3 p1 + 1/3 p2
6426 and of course r0 = p0, r3 = p2
6429 int contour, point = 0, first_pt;
6430 FT_Outline *outline = &ft_face->glyph->outline;
6431 TTPOLYGONHEADER *pph;
6432 TTPOLYCURVE *ppc;
6433 DWORD pph_start, cpfx, type;
6434 FT_Vector cubic_control[4];
6435 if(buflen == 0) buf = NULL;
6437 if (needsTransform && buf) {
6438 pFT_Outline_Transform(outline, &transMat);
6441 for(contour = 0; contour < outline->n_contours; contour++) {
6442 pph_start = needed;
6443 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6444 first_pt = point;
6445 if(buf) {
6446 pph->dwType = TT_POLYGON_TYPE;
6447 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6449 needed += sizeof(*pph);
6450 point++;
6451 while(point <= outline->contours[contour]) {
6452 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6453 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6454 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6455 cpfx = 0;
6456 do {
6457 if(type == TT_PRIM_LINE) {
6458 if(buf)
6459 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6460 cpfx++;
6461 point++;
6462 } else {
6463 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6464 so cpfx = 3n */
6466 /* FIXME: Possible optimization in endpoint calculation
6467 if there are two consecutive curves */
6468 cubic_control[0] = outline->points[point-1];
6469 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6470 cubic_control[0].x += outline->points[point].x + 1;
6471 cubic_control[0].y += outline->points[point].y + 1;
6472 cubic_control[0].x >>= 1;
6473 cubic_control[0].y >>= 1;
6475 if(point+1 > outline->contours[contour])
6476 cubic_control[3] = outline->points[first_pt];
6477 else {
6478 cubic_control[3] = outline->points[point+1];
6479 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6480 cubic_control[3].x += outline->points[point].x + 1;
6481 cubic_control[3].y += outline->points[point].y + 1;
6482 cubic_control[3].x >>= 1;
6483 cubic_control[3].y >>= 1;
6486 /* r1 = 1/3 p0 + 2/3 p1
6487 r2 = 1/3 p2 + 2/3 p1 */
6488 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6489 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6490 cubic_control[2] = cubic_control[1];
6491 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6492 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6493 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6494 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6495 if(buf) {
6496 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6497 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6498 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6500 cpfx += 3;
6501 point++;
6503 } while(point <= outline->contours[contour] &&
6504 (outline->tags[point] & FT_Curve_Tag_On) ==
6505 (outline->tags[point-1] & FT_Curve_Tag_On));
6506 /* At the end of a contour Windows adds the start point,
6507 but only for Beziers and we've already done that.
6509 if(point <= outline->contours[contour] &&
6510 outline->tags[point] & FT_Curve_Tag_On) {
6511 /* This is the closing pt of a bezier, but we've already
6512 added it, so just inc point and carry on */
6513 point++;
6515 if(buf) {
6516 ppc->wType = type;
6517 ppc->cpfx = cpfx;
6519 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6521 if(buf)
6522 pph->cb = needed - pph_start;
6524 break;
6527 default:
6528 FIXME("Unsupported format %d\n", format);
6529 return GDI_ERROR;
6531 return needed;
6534 static BOOL get_bitmap_text_metrics(GdiFont *font)
6536 FT_Face ft_face = font->ft_face;
6537 FT_WinFNT_HeaderRec winfnt_header;
6538 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6539 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6540 font->potm->otmSize = size;
6542 #define TM font->potm->otmTextMetrics
6543 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6545 TM.tmHeight = winfnt_header.pixel_height;
6546 TM.tmAscent = winfnt_header.ascent;
6547 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6548 TM.tmInternalLeading = winfnt_header.internal_leading;
6549 TM.tmExternalLeading = winfnt_header.external_leading;
6550 TM.tmAveCharWidth = winfnt_header.avg_width;
6551 TM.tmMaxCharWidth = winfnt_header.max_width;
6552 TM.tmWeight = winfnt_header.weight;
6553 TM.tmOverhang = 0;
6554 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6555 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6556 TM.tmFirstChar = winfnt_header.first_char;
6557 TM.tmLastChar = winfnt_header.last_char;
6558 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6559 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6560 TM.tmItalic = winfnt_header.italic;
6561 TM.tmUnderlined = font->underline;
6562 TM.tmStruckOut = font->strikeout;
6563 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6564 TM.tmCharSet = winfnt_header.charset;
6566 else
6568 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6569 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6570 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6571 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6572 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6573 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6574 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6575 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6576 TM.tmOverhang = 0;
6577 TM.tmDigitizedAspectX = 96; /* FIXME */
6578 TM.tmDigitizedAspectY = 96; /* FIXME */
6579 TM.tmFirstChar = 1;
6580 TM.tmLastChar = 255;
6581 TM.tmDefaultChar = 32;
6582 TM.tmBreakChar = 32;
6583 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6584 TM.tmUnderlined = font->underline;
6585 TM.tmStruckOut = font->strikeout;
6586 /* NB inverted meaning of TMPF_FIXED_PITCH */
6587 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6588 TM.tmCharSet = font->charset;
6590 #undef TM
6592 return TRUE;
6596 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6598 double scale_x, scale_y;
6600 if (font->aveWidth)
6602 scale_x = (double)font->aveWidth;
6603 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6605 else
6606 scale_x = font->scale_y;
6608 scale_x *= fabs(font->font_desc.matrix.eM11);
6609 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6611 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6612 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6614 SCALE_Y(ptm->tmHeight);
6615 SCALE_Y(ptm->tmAscent);
6616 SCALE_Y(ptm->tmDescent);
6617 SCALE_Y(ptm->tmInternalLeading);
6618 SCALE_Y(ptm->tmExternalLeading);
6619 SCALE_Y(ptm->tmOverhang);
6621 SCALE_X(ptm->tmAveCharWidth);
6622 SCALE_X(ptm->tmMaxCharWidth);
6624 #undef SCALE_X
6625 #undef SCALE_Y
6628 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6630 double scale_x, scale_y;
6632 if (font->aveWidth)
6634 scale_x = (double)font->aveWidth;
6635 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6637 else
6638 scale_x = font->scale_y;
6640 scale_x *= fabs(font->font_desc.matrix.eM11);
6641 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6643 scale_font_metrics(font, &potm->otmTextMetrics);
6645 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6646 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6648 SCALE_Y(potm->otmAscent);
6649 SCALE_Y(potm->otmDescent);
6650 SCALE_Y(potm->otmLineGap);
6651 SCALE_Y(potm->otmsCapEmHeight);
6652 SCALE_Y(potm->otmsXHeight);
6653 SCALE_Y(potm->otmrcFontBox.top);
6654 SCALE_Y(potm->otmrcFontBox.bottom);
6655 SCALE_X(potm->otmrcFontBox.left);
6656 SCALE_X(potm->otmrcFontBox.right);
6657 SCALE_Y(potm->otmMacAscent);
6658 SCALE_Y(potm->otmMacDescent);
6659 SCALE_Y(potm->otmMacLineGap);
6660 SCALE_X(potm->otmptSubscriptSize.x);
6661 SCALE_Y(potm->otmptSubscriptSize.y);
6662 SCALE_X(potm->otmptSubscriptOffset.x);
6663 SCALE_Y(potm->otmptSubscriptOffset.y);
6664 SCALE_X(potm->otmptSuperscriptSize.x);
6665 SCALE_Y(potm->otmptSuperscriptSize.y);
6666 SCALE_X(potm->otmptSuperscriptOffset.x);
6667 SCALE_Y(potm->otmptSuperscriptOffset.y);
6668 SCALE_Y(potm->otmsStrikeoutSize);
6669 SCALE_Y(potm->otmsStrikeoutPosition);
6670 SCALE_Y(potm->otmsUnderscoreSize);
6671 SCALE_Y(potm->otmsUnderscorePosition);
6673 #undef SCALE_X
6674 #undef SCALE_Y
6677 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6679 if(!font->potm)
6681 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6683 /* Make sure that the font has sane width/height ratio */
6684 if (font->aveWidth)
6686 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6688 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6689 font->aveWidth = 0;
6693 *ptm = font->potm->otmTextMetrics;
6694 scale_font_metrics(font, ptm);
6695 return TRUE;
6698 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6700 int i;
6702 for(i = 0; i < ft_face->num_charmaps; i++)
6704 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6705 return TRUE;
6707 return FALSE;
6710 static BOOL get_outline_text_metrics(GdiFont *font)
6712 BOOL ret = FALSE;
6713 FT_Face ft_face = font->ft_face;
6714 UINT needed, lenfam, lensty, lenface, lenfull;
6715 TT_OS2 *pOS2;
6716 TT_HoriHeader *pHori;
6717 TT_Postscript *pPost;
6718 FT_Fixed x_scale, y_scale;
6719 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
6720 char *cp;
6721 INT ascent, descent;
6723 TRACE("font=%p\n", font);
6725 if(!FT_IS_SCALABLE(ft_face))
6726 return FALSE;
6728 needed = sizeof(*font->potm);
6730 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6731 family_nameW = strdupW(font->name);
6733 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
6734 if (!style_nameW)
6735 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6736 if (!style_nameW)
6738 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
6739 style_nameW = towstr( CP_ACP, ft_face->style_name );
6741 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
6743 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
6744 if (!face_nameW)
6745 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6746 if (!face_nameW)
6748 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
6749 face_nameW = strdupW(font->name);
6751 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
6752 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
6754 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
6755 if (!full_nameW)
6756 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6757 if (!full_nameW)
6759 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
6760 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
6761 full_nameW = strdupW(fake_nameW);
6763 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
6765 /* These names should be read from the TT name table */
6767 /* length of otmpFamilyName */
6768 needed += lenfam;
6770 /* length of otmpFaceName */
6771 needed += lenface;
6773 /* length of otmpStyleName */
6774 needed += lensty;
6776 /* length of otmpFullName */
6777 needed += lenfull;
6780 x_scale = ft_face->size->metrics.x_scale;
6781 y_scale = ft_face->size->metrics.y_scale;
6783 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6784 if(!pOS2) {
6785 FIXME("Can't find OS/2 table - not TT font?\n");
6786 goto end;
6789 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6790 if(!pHori) {
6791 FIXME("Can't find HHEA table - not TT font?\n");
6792 goto end;
6795 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6797 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",
6798 pOS2->usWinAscent, pOS2->usWinDescent,
6799 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6800 pOS2->xAvgCharWidth,
6801 ft_face->ascender, ft_face->descender, ft_face->height,
6802 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6803 ft_face->bbox.yMax, ft_face->bbox.yMin);
6805 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6806 font->potm->otmSize = needed;
6808 #define TM font->potm->otmTextMetrics
6810 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6811 ascent = pHori->Ascender;
6812 descent = -pHori->Descender;
6813 } else {
6814 ascent = pOS2->usWinAscent;
6815 descent = pOS2->usWinDescent;
6818 font->ntmCellHeight = ascent + descent;
6819 font->ntmAvgWidth = pOS2->xAvgCharWidth;
6821 if(font->yMax) {
6822 TM.tmAscent = font->yMax;
6823 TM.tmDescent = -font->yMin;
6824 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6825 } else {
6826 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6827 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6828 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6829 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6832 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6834 /* MSDN says:
6835 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6837 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6838 ((ascent + descent) -
6839 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6841 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6842 if (TM.tmAveCharWidth == 0) {
6843 TM.tmAveCharWidth = 1;
6845 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6846 TM.tmWeight = FW_REGULAR;
6847 if (font->fake_bold)
6848 TM.tmWeight = FW_BOLD;
6849 else
6851 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6853 if (pOS2->usWeightClass > FW_MEDIUM)
6854 TM.tmWeight = pOS2->usWeightClass;
6856 else if (pOS2->usWeightClass <= FW_MEDIUM)
6857 TM.tmWeight = pOS2->usWeightClass;
6859 TM.tmOverhang = 0;
6860 TM.tmDigitizedAspectX = 96; /* FIXME */
6861 TM.tmDigitizedAspectY = 96; /* FIXME */
6862 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6863 * symbol range to 0 - f0ff
6866 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6868 TM.tmFirstChar = 0;
6869 switch(GetACP())
6871 case 1257: /* Baltic */
6872 TM.tmLastChar = 0xf8fd;
6873 break;
6874 default:
6875 TM.tmLastChar = 0xf0ff;
6877 TM.tmBreakChar = 0x20;
6878 TM.tmDefaultChar = 0x1f;
6880 else
6882 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6883 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6885 if(pOS2->usFirstCharIndex <= 1)
6886 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6887 else if (pOS2->usFirstCharIndex > 0xff)
6888 TM.tmBreakChar = 0x20;
6889 else
6890 TM.tmBreakChar = pOS2->usFirstCharIndex;
6891 TM.tmDefaultChar = TM.tmBreakChar - 1;
6893 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6894 TM.tmUnderlined = font->underline;
6895 TM.tmStruckOut = font->strikeout;
6897 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6898 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6899 (pOS2->version == 0xFFFFU ||
6900 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6901 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6902 else
6903 TM.tmPitchAndFamily = 0;
6905 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6907 case PAN_FAMILY_SCRIPT:
6908 TM.tmPitchAndFamily |= FF_SCRIPT;
6909 break;
6911 case PAN_FAMILY_DECORATIVE:
6912 TM.tmPitchAndFamily |= FF_DECORATIVE;
6913 break;
6915 case PAN_ANY:
6916 case PAN_NO_FIT:
6917 case PAN_FAMILY_TEXT_DISPLAY:
6918 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6919 /* which is clearly not what the panose spec says. */
6920 default:
6921 if(TM.tmPitchAndFamily == 0 || /* fixed */
6922 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6923 TM.tmPitchAndFamily = FF_MODERN;
6924 else
6926 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6928 case PAN_ANY:
6929 case PAN_NO_FIT:
6930 default:
6931 TM.tmPitchAndFamily |= FF_DONTCARE;
6932 break;
6934 case PAN_SERIF_COVE:
6935 case PAN_SERIF_OBTUSE_COVE:
6936 case PAN_SERIF_SQUARE_COVE:
6937 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6938 case PAN_SERIF_SQUARE:
6939 case PAN_SERIF_THIN:
6940 case PAN_SERIF_BONE:
6941 case PAN_SERIF_EXAGGERATED:
6942 case PAN_SERIF_TRIANGLE:
6943 TM.tmPitchAndFamily |= FF_ROMAN;
6944 break;
6946 case PAN_SERIF_NORMAL_SANS:
6947 case PAN_SERIF_OBTUSE_SANS:
6948 case PAN_SERIF_PERP_SANS:
6949 case PAN_SERIF_FLARED:
6950 case PAN_SERIF_ROUNDED:
6951 TM.tmPitchAndFamily |= FF_SWISS;
6952 break;
6955 break;
6958 if(FT_IS_SCALABLE(ft_face))
6959 TM.tmPitchAndFamily |= TMPF_VECTOR;
6961 if(FT_IS_SFNT(ft_face))
6963 if (font->ntmFlags & NTM_PS_OPENTYPE)
6964 TM.tmPitchAndFamily |= TMPF_DEVICE;
6965 else
6966 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6969 TM.tmCharSet = font->charset;
6971 font->potm->otmFiller = 0;
6972 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6973 font->potm->otmfsSelection = pOS2->fsSelection;
6974 font->potm->otmfsType = pOS2->fsType;
6975 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6976 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6977 font->potm->otmItalicAngle = 0; /* POST table */
6978 font->potm->otmEMSquare = ft_face->units_per_EM;
6979 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6980 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6981 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6982 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6983 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6984 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6985 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6986 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6987 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6988 font->potm->otmMacAscent = TM.tmAscent;
6989 font->potm->otmMacDescent = -TM.tmDescent;
6990 font->potm->otmMacLineGap = font->potm->otmLineGap;
6991 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6992 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6993 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6994 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6995 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6996 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6997 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6998 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6999 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
7000 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
7001 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
7002 if(!pPost) {
7003 font->potm->otmsUnderscoreSize = 0;
7004 font->potm->otmsUnderscorePosition = 0;
7005 } else {
7006 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
7007 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
7009 #undef TM
7011 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7012 cp = (char*)font->potm + sizeof(*font->potm);
7013 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
7014 strcpyW((WCHAR*)cp, family_nameW);
7015 cp += lenfam;
7016 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
7017 strcpyW((WCHAR*)cp, style_nameW);
7018 cp += lensty;
7019 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7020 strcpyW((WCHAR*)cp, face_nameW);
7021 cp += lenface;
7022 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
7023 strcpyW((WCHAR*)cp, full_nameW);
7024 ret = TRUE;
7026 end:
7027 HeapFree(GetProcessHeap(), 0, style_nameW);
7028 HeapFree(GetProcessHeap(), 0, family_nameW);
7029 HeapFree(GetProcessHeap(), 0, face_nameW);
7030 HeapFree(GetProcessHeap(), 0, full_nameW);
7031 return ret;
7034 /*************************************************************
7035 * freetype_GetGlyphOutline
7037 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
7038 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7040 struct freetype_physdev *physdev = get_freetype_dev( dev );
7041 DWORD ret;
7042 ABC abc;
7044 if (!physdev->font)
7046 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
7047 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
7050 GDI_CheckNotLock();
7051 EnterCriticalSection( &freetype_cs );
7052 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
7053 LeaveCriticalSection( &freetype_cs );
7054 return ret;
7057 /*************************************************************
7058 * freetype_GetTextMetrics
7060 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
7062 struct freetype_physdev *physdev = get_freetype_dev( dev );
7063 BOOL ret;
7065 if (!physdev->font)
7067 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
7068 return dev->funcs->pGetTextMetrics( dev, metrics );
7071 GDI_CheckNotLock();
7072 EnterCriticalSection( &freetype_cs );
7073 ret = get_text_metrics( physdev->font, metrics );
7074 LeaveCriticalSection( &freetype_cs );
7075 return ret;
7078 /*************************************************************
7079 * freetype_GetOutlineTextMetrics
7081 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
7083 struct freetype_physdev *physdev = get_freetype_dev( dev );
7084 UINT ret = 0;
7086 if (!physdev->font)
7088 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
7089 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
7092 TRACE("font=%p\n", physdev->font);
7094 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
7096 GDI_CheckNotLock();
7097 EnterCriticalSection( &freetype_cs );
7099 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
7101 if(cbSize >= physdev->font->potm->otmSize)
7103 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
7104 scale_outline_font_metrics(physdev->font, potm);
7106 ret = physdev->font->potm->otmSize;
7108 LeaveCriticalSection( &freetype_cs );
7109 return ret;
7112 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
7114 child->font = alloc_font();
7115 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
7116 if(!child->font->ft_face)
7118 free_font(child->font);
7119 child->font = NULL;
7120 return FALSE;
7123 child->font->font_desc = font->font_desc;
7124 child->font->ntmFlags = child->face->ntmFlags;
7125 child->font->orientation = font->orientation;
7126 child->font->scale_y = font->scale_y;
7127 child->font->name = strdupW(child->face->family->FamilyName);
7128 child->font->base_font = font;
7129 TRACE("created child font %p for base %p\n", child->font, font);
7130 return TRUE;
7133 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
7135 FT_UInt g;
7136 CHILD_FONT *child_font;
7138 if(font->base_font)
7139 font = font->base_font;
7141 *linked_font = font;
7143 if((*glyph = get_glyph_index(font, c)))
7145 *glyph = get_GSUB_vert_glyph(font, *glyph);
7146 return TRUE;
7149 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7151 if(!child_font->font)
7152 if(!load_child_font(font, child_font))
7153 continue;
7155 if(!child_font->font->ft_face)
7156 continue;
7157 g = get_glyph_index(child_font->font, c);
7158 g = get_GSUB_vert_glyph(child_font->font, g);
7159 if(g)
7161 *glyph = g;
7162 *linked_font = child_font->font;
7163 return TRUE;
7166 return FALSE;
7169 /*************************************************************
7170 * freetype_GetCharWidth
7172 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7174 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7175 UINT c;
7176 GLYPHMETRICS gm;
7177 ABC abc;
7178 struct freetype_physdev *physdev = get_freetype_dev( dev );
7180 if (!physdev->font)
7182 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7183 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7186 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7188 GDI_CheckNotLock();
7189 EnterCriticalSection( &freetype_cs );
7190 for(c = firstChar; c <= lastChar; c++) {
7191 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7192 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
7194 LeaveCriticalSection( &freetype_cs );
7195 return TRUE;
7198 /*************************************************************
7199 * freetype_GetCharABCWidths
7201 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7203 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7204 UINT c;
7205 GLYPHMETRICS gm;
7206 struct freetype_physdev *physdev = get_freetype_dev( dev );
7208 if (!physdev->font)
7210 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7211 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7214 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7216 GDI_CheckNotLock();
7217 EnterCriticalSection( &freetype_cs );
7219 for(c = firstChar; c <= lastChar; c++, buffer++)
7220 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
7222 LeaveCriticalSection( &freetype_cs );
7223 return TRUE;
7226 /*************************************************************
7227 * freetype_GetCharABCWidthsI
7229 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7231 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7232 UINT c;
7233 GLYPHMETRICS gm;
7234 struct freetype_physdev *physdev = get_freetype_dev( dev );
7236 if (!physdev->font)
7238 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7239 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7242 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7243 return FALSE;
7245 GDI_CheckNotLock();
7246 EnterCriticalSection( &freetype_cs );
7248 for(c = 0; c < count; c++, buffer++)
7249 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
7250 &gm, buffer, 0, NULL, &identity );
7252 LeaveCriticalSection( &freetype_cs );
7253 return TRUE;
7256 /*************************************************************
7257 * freetype_GetTextExtentExPoint
7259 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
7261 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7262 INT idx, pos;
7263 ABC abc;
7264 GLYPHMETRICS gm;
7265 struct freetype_physdev *physdev = get_freetype_dev( dev );
7267 if (!physdev->font)
7269 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7270 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
7273 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
7275 GDI_CheckNotLock();
7276 EnterCriticalSection( &freetype_cs );
7278 for (idx = pos = 0; idx < count; idx++)
7280 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7281 pos += abc.abcA + abc.abcB + abc.abcC;
7282 dxs[idx] = pos;
7285 LeaveCriticalSection( &freetype_cs );
7286 return TRUE;
7289 /*************************************************************
7290 * freetype_GetTextExtentExPointI
7292 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
7294 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7295 INT idx, pos;
7296 ABC abc;
7297 GLYPHMETRICS gm;
7298 struct freetype_physdev *physdev = get_freetype_dev( dev );
7300 if (!physdev->font)
7302 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7303 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
7306 TRACE("%p, %p, %d\n", physdev->font, indices, count);
7308 GDI_CheckNotLock();
7309 EnterCriticalSection( &freetype_cs );
7311 for (idx = pos = 0; idx < count; idx++)
7313 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
7314 &gm, &abc, 0, NULL, &identity );
7315 pos += abc.abcA + abc.abcB + abc.abcC;
7316 dxs[idx] = pos;
7319 LeaveCriticalSection( &freetype_cs );
7320 return TRUE;
7323 /*************************************************************
7324 * freetype_GetFontData
7326 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7328 struct freetype_physdev *physdev = get_freetype_dev( dev );
7330 if (!physdev->font)
7332 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7333 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7336 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7337 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7338 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7340 return get_font_data( physdev->font, table, offset, buf, cbData );
7343 /*************************************************************
7344 * freetype_GetTextFace
7346 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7348 INT n;
7349 struct freetype_physdev *physdev = get_freetype_dev( dev );
7351 if (!physdev->font)
7353 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7354 return dev->funcs->pGetTextFace( dev, count, str );
7357 n = strlenW(physdev->font->name) + 1;
7358 if (str)
7360 lstrcpynW(str, physdev->font->name, count);
7361 n = min(count, n);
7363 return n;
7366 /*************************************************************
7367 * freetype_GetTextCharsetInfo
7369 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7371 struct freetype_physdev *physdev = get_freetype_dev( dev );
7373 if (!physdev->font)
7375 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7376 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7378 if (fs) *fs = physdev->font->fs;
7379 return physdev->font->charset;
7382 /* Retrieve a list of supported Unicode ranges for a given font.
7383 * Can be called with NULL gs to calculate the buffer size. Returns
7384 * the number of ranges found.
7386 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7388 DWORD num_ranges = 0;
7390 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7392 FT_UInt glyph_code;
7393 FT_ULong char_code, char_code_prev;
7395 glyph_code = 0;
7396 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7398 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7399 face->num_glyphs, glyph_code, char_code);
7401 if (!glyph_code) return 0;
7403 if (gs)
7405 gs->ranges[0].wcLow = (USHORT)char_code;
7406 gs->ranges[0].cGlyphs = 0;
7407 gs->cGlyphsSupported = 0;
7410 num_ranges = 1;
7411 while (glyph_code)
7413 if (char_code < char_code_prev)
7415 ERR("expected increasing char code from FT_Get_Next_Char\n");
7416 return 0;
7418 if (char_code - char_code_prev > 1)
7420 num_ranges++;
7421 if (gs)
7423 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7424 gs->ranges[num_ranges - 1].cGlyphs = 1;
7425 gs->cGlyphsSupported++;
7428 else if (gs)
7430 gs->ranges[num_ranges - 1].cGlyphs++;
7431 gs->cGlyphsSupported++;
7433 char_code_prev = char_code;
7434 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7437 else
7438 FIXME("encoding %u not supported\n", face->charmap->encoding);
7440 return num_ranges;
7443 /*************************************************************
7444 * freetype_GetFontUnicodeRanges
7446 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7448 struct freetype_physdev *physdev = get_freetype_dev( dev );
7449 DWORD size, num_ranges;
7451 if (!physdev->font)
7453 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7454 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7457 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7458 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7459 if (glyphset)
7461 glyphset->cbThis = size;
7462 glyphset->cRanges = num_ranges;
7463 glyphset->flAccel = 0;
7465 return size;
7468 /*************************************************************
7469 * freetype_FontIsLinked
7471 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7473 struct freetype_physdev *physdev = get_freetype_dev( dev );
7474 BOOL ret;
7476 if (!physdev->font)
7478 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7479 return dev->funcs->pFontIsLinked( dev );
7482 GDI_CheckNotLock();
7483 EnterCriticalSection( &freetype_cs );
7484 ret = !list_empty(&physdev->font->child_fonts);
7485 LeaveCriticalSection( &freetype_cs );
7486 return ret;
7489 /*************************************************************************
7490 * GetRasterizerCaps (GDI32.@)
7492 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7494 lprs->nSize = sizeof(RASTERIZER_STATUS);
7495 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
7496 lprs->nLanguageID = 0;
7497 return TRUE;
7500 /*************************************************************
7501 * freetype_GdiRealizationInfo
7503 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7505 struct freetype_physdev *physdev = get_freetype_dev( dev );
7506 realization_info_t *info = ptr;
7508 if (!physdev->font)
7510 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7511 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7514 FIXME("(%p, %p): stub!\n", physdev->font, info);
7516 info->flags = 1;
7517 if(FT_IS_SCALABLE(physdev->font->ft_face))
7518 info->flags |= 2;
7520 info->cache_num = physdev->font->cache_num;
7521 info->unknown2 = -1;
7522 return TRUE;
7525 /*************************************************************************
7526 * Kerning support for TrueType fonts
7528 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7530 struct TT_kern_table
7532 USHORT version;
7533 USHORT nTables;
7536 struct TT_kern_subtable
7538 USHORT version;
7539 USHORT length;
7540 union
7542 USHORT word;
7543 struct
7545 USHORT horizontal : 1;
7546 USHORT minimum : 1;
7547 USHORT cross_stream: 1;
7548 USHORT override : 1;
7549 USHORT reserved1 : 4;
7550 USHORT format : 8;
7551 } bits;
7552 } coverage;
7555 struct TT_format0_kern_subtable
7557 USHORT nPairs;
7558 USHORT searchRange;
7559 USHORT entrySelector;
7560 USHORT rangeShift;
7563 struct TT_kern_pair
7565 USHORT left;
7566 USHORT right;
7567 short value;
7570 static DWORD parse_format0_kern_subtable(GdiFont *font,
7571 const struct TT_format0_kern_subtable *tt_f0_ks,
7572 const USHORT *glyph_to_char,
7573 KERNINGPAIR *kern_pair, DWORD cPairs)
7575 USHORT i, nPairs;
7576 const struct TT_kern_pair *tt_kern_pair;
7578 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7580 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7582 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7583 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7584 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7586 if (!kern_pair || !cPairs)
7587 return nPairs;
7589 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7591 nPairs = min(nPairs, cPairs);
7593 for (i = 0; i < nPairs; i++)
7595 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7596 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7597 /* this algorithm appears to better match what Windows does */
7598 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7599 if (kern_pair->iKernAmount < 0)
7601 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7602 kern_pair->iKernAmount -= font->ppem;
7604 else if (kern_pair->iKernAmount > 0)
7606 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7607 kern_pair->iKernAmount += font->ppem;
7609 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7611 TRACE("left %u right %u value %d\n",
7612 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7614 kern_pair++;
7616 TRACE("copied %u entries\n", nPairs);
7617 return nPairs;
7620 /*************************************************************
7621 * freetype_GetKerningPairs
7623 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7625 DWORD length;
7626 void *buf;
7627 const struct TT_kern_table *tt_kern_table;
7628 const struct TT_kern_subtable *tt_kern_subtable;
7629 USHORT i, nTables;
7630 USHORT *glyph_to_char;
7631 GdiFont *font;
7632 struct freetype_physdev *physdev = get_freetype_dev( dev );
7634 if (!(font = physdev->font))
7636 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7637 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7640 GDI_CheckNotLock();
7641 EnterCriticalSection( &freetype_cs );
7642 if (font->total_kern_pairs != (DWORD)-1)
7644 if (cPairs && kern_pair)
7646 cPairs = min(cPairs, font->total_kern_pairs);
7647 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7649 else cPairs = font->total_kern_pairs;
7651 LeaveCriticalSection( &freetype_cs );
7652 return cPairs;
7655 font->total_kern_pairs = 0;
7657 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7659 if (length == GDI_ERROR)
7661 TRACE("no kerning data in the font\n");
7662 LeaveCriticalSection( &freetype_cs );
7663 return 0;
7666 buf = HeapAlloc(GetProcessHeap(), 0, length);
7667 if (!buf)
7669 WARN("Out of memory\n");
7670 LeaveCriticalSection( &freetype_cs );
7671 return 0;
7674 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7676 /* build a glyph index to char code map */
7677 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7678 if (!glyph_to_char)
7680 WARN("Out of memory allocating a glyph index to char code map\n");
7681 HeapFree(GetProcessHeap(), 0, buf);
7682 LeaveCriticalSection( &freetype_cs );
7683 return 0;
7686 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7688 FT_UInt glyph_code;
7689 FT_ULong char_code;
7691 glyph_code = 0;
7692 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7694 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7695 font->ft_face->num_glyphs, glyph_code, char_code);
7697 while (glyph_code)
7699 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7701 /* FIXME: This doesn't match what Windows does: it does some fancy
7702 * things with duplicate glyph index to char code mappings, while
7703 * we just avoid overriding existing entries.
7705 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7706 glyph_to_char[glyph_code] = (USHORT)char_code;
7708 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7711 else
7713 ULONG n;
7715 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7716 for (n = 0; n <= 65535; n++)
7717 glyph_to_char[n] = (USHORT)n;
7720 tt_kern_table = buf;
7721 nTables = GET_BE_WORD(tt_kern_table->nTables);
7722 TRACE("version %u, nTables %u\n",
7723 GET_BE_WORD(tt_kern_table->version), nTables);
7725 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7727 for (i = 0; i < nTables; i++)
7729 struct TT_kern_subtable tt_kern_subtable_copy;
7731 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7732 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7733 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7735 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7736 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7737 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7739 /* According to the TrueType specification this is the only format
7740 * that will be properly interpreted by Windows and OS/2
7742 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7744 DWORD new_chunk, old_total = font->total_kern_pairs;
7746 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7747 glyph_to_char, NULL, 0);
7748 font->total_kern_pairs += new_chunk;
7750 if (!font->kern_pairs)
7751 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7752 font->total_kern_pairs * sizeof(*font->kern_pairs));
7753 else
7754 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7755 font->total_kern_pairs * sizeof(*font->kern_pairs));
7757 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7758 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7760 else
7761 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7763 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7766 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7767 HeapFree(GetProcessHeap(), 0, buf);
7769 if (cPairs && kern_pair)
7771 cPairs = min(cPairs, font->total_kern_pairs);
7772 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7774 else cPairs = font->total_kern_pairs;
7776 LeaveCriticalSection( &freetype_cs );
7777 return cPairs;
7780 static const struct gdi_dc_funcs freetype_funcs =
7782 NULL, /* pAbortDoc */
7783 NULL, /* pAbortPath */
7784 NULL, /* pAlphaBlend */
7785 NULL, /* pAngleArc */
7786 NULL, /* pArc */
7787 NULL, /* pArcTo */
7788 NULL, /* pBeginPath */
7789 NULL, /* pBlendImage */
7790 NULL, /* pChord */
7791 NULL, /* pCloseFigure */
7792 NULL, /* pCreateCompatibleDC */
7793 freetype_CreateDC, /* pCreateDC */
7794 freetype_DeleteDC, /* pDeleteDC */
7795 NULL, /* pDeleteObject */
7796 NULL, /* pDeviceCapabilities */
7797 NULL, /* pEllipse */
7798 NULL, /* pEndDoc */
7799 NULL, /* pEndPage */
7800 NULL, /* pEndPath */
7801 freetype_EnumFonts, /* pEnumFonts */
7802 NULL, /* pEnumICMProfiles */
7803 NULL, /* pExcludeClipRect */
7804 NULL, /* pExtDeviceMode */
7805 NULL, /* pExtEscape */
7806 NULL, /* pExtFloodFill */
7807 NULL, /* pExtSelectClipRgn */
7808 NULL, /* pExtTextOut */
7809 NULL, /* pFillPath */
7810 NULL, /* pFillRgn */
7811 NULL, /* pFlattenPath */
7812 freetype_FontIsLinked, /* pFontIsLinked */
7813 NULL, /* pFrameRgn */
7814 NULL, /* pGdiComment */
7815 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7816 NULL, /* pGetBoundsRect */
7817 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7818 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7819 freetype_GetCharWidth, /* pGetCharWidth */
7820 NULL, /* pGetDeviceCaps */
7821 NULL, /* pGetDeviceGammaRamp */
7822 freetype_GetFontData, /* pGetFontData */
7823 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7824 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7825 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7826 NULL, /* pGetICMProfile */
7827 NULL, /* pGetImage */
7828 freetype_GetKerningPairs, /* pGetKerningPairs */
7829 NULL, /* pGetNearestColor */
7830 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7831 NULL, /* pGetPixel */
7832 NULL, /* pGetSystemPaletteEntries */
7833 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7834 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7835 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7836 freetype_GetTextFace, /* pGetTextFace */
7837 freetype_GetTextMetrics, /* pGetTextMetrics */
7838 NULL, /* pGradientFill */
7839 NULL, /* pIntersectClipRect */
7840 NULL, /* pInvertRgn */
7841 NULL, /* pLineTo */
7842 NULL, /* pModifyWorldTransform */
7843 NULL, /* pMoveTo */
7844 NULL, /* pOffsetClipRgn */
7845 NULL, /* pOffsetViewportOrg */
7846 NULL, /* pOffsetWindowOrg */
7847 NULL, /* pPaintRgn */
7848 NULL, /* pPatBlt */
7849 NULL, /* pPie */
7850 NULL, /* pPolyBezier */
7851 NULL, /* pPolyBezierTo */
7852 NULL, /* pPolyDraw */
7853 NULL, /* pPolyPolygon */
7854 NULL, /* pPolyPolyline */
7855 NULL, /* pPolygon */
7856 NULL, /* pPolyline */
7857 NULL, /* pPolylineTo */
7858 NULL, /* pPutImage */
7859 NULL, /* pRealizeDefaultPalette */
7860 NULL, /* pRealizePalette */
7861 NULL, /* pRectangle */
7862 NULL, /* pResetDC */
7863 NULL, /* pRestoreDC */
7864 NULL, /* pRoundRect */
7865 NULL, /* pSaveDC */
7866 NULL, /* pScaleViewportExt */
7867 NULL, /* pScaleWindowExt */
7868 NULL, /* pSelectBitmap */
7869 NULL, /* pSelectBrush */
7870 NULL, /* pSelectClipPath */
7871 freetype_SelectFont, /* pSelectFont */
7872 NULL, /* pSelectPalette */
7873 NULL, /* pSelectPen */
7874 NULL, /* pSetArcDirection */
7875 NULL, /* pSetBkColor */
7876 NULL, /* pSetBkMode */
7877 NULL, /* pSetDCBrushColor */
7878 NULL, /* pSetDCPenColor */
7879 NULL, /* pSetDIBColorTable */
7880 NULL, /* pSetDIBitsToDevice */
7881 NULL, /* pSetDeviceClipping */
7882 NULL, /* pSetDeviceGammaRamp */
7883 NULL, /* pSetLayout */
7884 NULL, /* pSetMapMode */
7885 NULL, /* pSetMapperFlags */
7886 NULL, /* pSetPixel */
7887 NULL, /* pSetPolyFillMode */
7888 NULL, /* pSetROP2 */
7889 NULL, /* pSetRelAbs */
7890 NULL, /* pSetStretchBltMode */
7891 NULL, /* pSetTextAlign */
7892 NULL, /* pSetTextCharacterExtra */
7893 NULL, /* pSetTextColor */
7894 NULL, /* pSetTextJustification */
7895 NULL, /* pSetViewportExt */
7896 NULL, /* pSetViewportOrg */
7897 NULL, /* pSetWindowExt */
7898 NULL, /* pSetWindowOrg */
7899 NULL, /* pSetWorldTransform */
7900 NULL, /* pStartDoc */
7901 NULL, /* pStartPage */
7902 NULL, /* pStretchBlt */
7903 NULL, /* pStretchDIBits */
7904 NULL, /* pStrokeAndFillPath */
7905 NULL, /* pStrokePath */
7906 NULL, /* pUnrealizePalette */
7907 NULL, /* pWidenPath */
7908 NULL, /* wine_get_wgl_driver */
7909 GDI_PRIORITY_FONT_DRV /* priority */
7912 #else /* HAVE_FREETYPE */
7914 /*************************************************************************/
7916 BOOL WineEngInit(void)
7918 return FALSE;
7921 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7923 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7924 return 1;
7927 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7929 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7930 return TRUE;
7933 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7935 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7936 return NULL;
7939 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
7940 LPCWSTR font_file, LPCWSTR font_path )
7942 FIXME("stub\n");
7943 return FALSE;
7946 /*************************************************************************
7947 * GetRasterizerCaps (GDI32.@)
7949 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7951 lprs->nSize = sizeof(RASTERIZER_STATUS);
7952 lprs->wFlags = 0;
7953 lprs->nLanguageID = 0;
7954 return TRUE;
7957 #endif /* HAVE_FREETYPE */