gdi32: Vertical glyphs can be written tategaki even without a vertical GSUB feature.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blobbc437721be7833c607ff4819d239155398c400e5
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
35 #include <string.h>
36 #ifdef HAVE_DIRENT_H
37 # include <dirent.h>
38 #endif
39 #include <stdio.h>
40 #include <assert.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
60 #undef LoadResource
61 #undef CompareString
62 #undef GetCurrentThread
63 #undef _CDECL
64 #undef DPRINTF
65 #undef GetCurrentProcess
66 #undef AnimatePalette
67 #undef EqualRgn
68 #undef FillRgn
69 #undef FrameRgn
70 #undef GetPixel
71 #undef InvertRgn
72 #undef LineTo
73 #undef OffsetRgn
74 #undef PaintRgn
75 #undef Polygon
76 #undef ResizePalette
77 #undef SetRectRgn
78 #endif /* HAVE_CARBON_CARBON_H */
80 #include "windef.h"
81 #include "winbase.h"
82 #include "winternl.h"
83 #include "winerror.h"
84 #include "winreg.h"
85 #include "wingdi.h"
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
92 #include "resource.h"
94 WINE_DEFAULT_DEBUG_CHANNEL(font);
96 #ifdef HAVE_FREETYPE
98 #ifdef HAVE_FT2BUILD_H
99 #include <ft2build.h>
100 #endif
101 #ifdef HAVE_FREETYPE_FREETYPE_H
102 #include <freetype/freetype.h>
103 #endif
104 #ifdef HAVE_FREETYPE_FTGLYPH_H
105 #include <freetype/ftglyph.h>
106 #endif
107 #ifdef HAVE_FREETYPE_TTTABLES_H
108 #include <freetype/tttables.h>
109 #endif
110 #ifdef HAVE_FREETYPE_FTTYPES_H
111 #include <freetype/fttypes.h>
112 #endif
113 #ifdef HAVE_FREETYPE_FTSNAMES_H
114 #include <freetype/ftsnames.h>
115 #endif
116 #ifdef HAVE_FREETYPE_TTNAMEID_H
117 #include <freetype/ttnameid.h>
118 #endif
119 #ifdef HAVE_FREETYPE_FTOUTLN_H
120 #include <freetype/ftoutln.h>
121 #endif
122 #ifdef HAVE_FREETYPE_FTTRIGON_H
123 #include <freetype/fttrigon.h>
124 #endif
125 #ifdef HAVE_FREETYPE_FTWINFNT_H
126 #include <freetype/ftwinfnt.h>
127 #endif
128 #ifdef HAVE_FREETYPE_FTMODAPI_H
129 #include <freetype/ftmodapi.h>
130 #endif
131 #ifdef HAVE_FREETYPE_FTLCDFIL_H
132 #include <freetype/ftlcdfil.h>
133 #endif
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
136 typedef enum
138 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType;
142 #endif
144 static FT_Library library = 0;
145 typedef struct
147 FT_Int major;
148 FT_Int minor;
149 FT_Int patch;
150 } FT_Version_t;
151 static FT_Version_t FT_Version;
152 static DWORD FT_SimpleVersion;
154 static void *ft_handle = NULL;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_First_Char);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Next_Char);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
165 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
166 MAKE_FUNCPTR(FT_Init_FreeType);
167 MAKE_FUNCPTR(FT_Library_Version);
168 MAKE_FUNCPTR(FT_Load_Glyph);
169 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
170 MAKE_FUNCPTR(FT_Matrix_Multiply);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
173 #else
174 MAKE_FUNCPTR(FT_MulFix);
175 #endif
176 MAKE_FUNCPTR(FT_New_Face);
177 MAKE_FUNCPTR(FT_New_Memory_Face);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
179 MAKE_FUNCPTR(FT_Outline_Transform);
180 MAKE_FUNCPTR(FT_Outline_Translate);
181 MAKE_FUNCPTR(FT_Render_Glyph);
182 MAKE_FUNCPTR(FT_Select_Charmap);
183 MAKE_FUNCPTR(FT_Set_Charmap);
184 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
185 MAKE_FUNCPTR(FT_Vector_Transform);
186 MAKE_FUNCPTR(FT_Vector_Unit);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
190 #endif
192 #ifdef SONAME_LIBFONTCONFIG
193 #include <fontconfig/fontconfig.h>
194 MAKE_FUNCPTR(FcConfigSubstitute);
195 MAKE_FUNCPTR(FcFontList);
196 MAKE_FUNCPTR(FcFontSetDestroy);
197 MAKE_FUNCPTR(FcInit);
198 MAKE_FUNCPTR(FcObjectSetAdd);
199 MAKE_FUNCPTR(FcObjectSetCreate);
200 MAKE_FUNCPTR(FcObjectSetDestroy);
201 MAKE_FUNCPTR(FcPatternCreate);
202 MAKE_FUNCPTR(FcPatternDestroy);
203 MAKE_FUNCPTR(FcPatternGetBool);
204 MAKE_FUNCPTR(FcPatternGetInteger);
205 MAKE_FUNCPTR(FcPatternGetString);
206 #endif
208 #undef MAKE_FUNCPTR
210 #ifndef FT_MAKE_TAG
211 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
212 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
213 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
214 #endif
216 #ifndef ft_encoding_none
217 #define FT_ENCODING_NONE ft_encoding_none
218 #endif
219 #ifndef ft_encoding_ms_symbol
220 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
221 #endif
222 #ifndef ft_encoding_unicode
223 #define FT_ENCODING_UNICODE ft_encoding_unicode
224 #endif
225 #ifndef ft_encoding_apple_roman
226 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
227 #endif
229 #ifdef WORDS_BIGENDIAN
230 #define GET_BE_WORD(x) (x)
231 #else
232 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
233 #endif
235 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
236 typedef struct {
237 FT_Short height;
238 FT_Short width;
239 FT_Pos size;
240 FT_Pos x_ppem;
241 FT_Pos y_ppem;
242 FT_Short internal_leading;
243 } Bitmap_Size;
245 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
246 So to let this compile on older versions of FreeType we'll define the
247 new structure here. */
248 typedef struct {
249 FT_Short height, width;
250 FT_Pos size, x_ppem, y_ppem;
251 } My_FT_Bitmap_Size;
253 struct enum_data
255 ENUMLOGFONTEXW elf;
256 NEWTEXTMETRICEXW ntm;
257 DWORD type;
260 typedef struct tagFace {
261 struct list entry;
262 unsigned int refcount;
263 WCHAR *StyleName;
264 WCHAR *FullName;
265 WCHAR *file;
266 dev_t dev;
267 ino_t ino;
268 void *font_data_ptr;
269 DWORD font_data_size;
270 FT_Long face_index;
271 FONTSIGNATURE fs;
272 DWORD ntmFlags;
273 FT_Fixed font_version;
274 BOOL scalable;
275 Bitmap_Size size; /* set if face is a bitmap */
276 DWORD flags; /* ADDFONT flags */
277 struct tagFamily *family;
278 /* Cached data for Enum */
279 struct enum_data *cached_enum_data;
280 } Face;
282 #define ADDFONT_EXTERNAL_FONT 0x01
283 #define ADDFONT_ALLOW_BITMAP 0x02
284 #define ADDFONT_ADD_TO_CACHE 0x04
285 #define ADDFONT_ADD_RESOURCE 0x08 /* added through AddFontResource */
286 #define ADDFONT_VERTICAL_FONT 0x10
287 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
289 typedef struct tagFamily {
290 struct list entry;
291 unsigned int refcount;
292 WCHAR *FamilyName;
293 WCHAR *EnglishName;
294 struct list faces;
295 struct list *replacement;
296 } Family;
298 typedef struct {
299 GLYPHMETRICS gm;
300 ABC abc; /* metrics of the unrotated char */
301 BOOL init;
302 } GM;
304 typedef struct {
305 FLOAT eM11, eM12;
306 FLOAT eM21, eM22;
307 } FMAT2;
309 typedef struct {
310 DWORD hash;
311 LOGFONTW lf;
312 FMAT2 matrix;
313 BOOL can_use_bitmap;
314 } FONT_DESC;
316 typedef struct tagGdiFont GdiFont;
318 typedef struct {
319 struct list entry;
320 Face *face;
321 GdiFont *font;
322 } CHILD_FONT;
324 struct tagGdiFont {
325 struct list entry;
326 struct list unused_entry;
327 unsigned int refcount;
328 GM **gm;
329 DWORD gmsize;
330 OUTLINETEXTMETRICW *potm;
331 DWORD total_kern_pairs;
332 KERNINGPAIR *kern_pairs;
333 struct list child_fonts;
335 /* the following members can be accessed without locking, they are never modified after creation */
336 FT_Face ft_face;
337 struct font_mapping *mapping;
338 LPWSTR name;
339 int charset;
340 int codepage;
341 BOOL fake_italic;
342 BOOL fake_bold;
343 BYTE underline;
344 BYTE strikeout;
345 INT orientation;
346 FONT_DESC font_desc;
347 LONG aveWidth, ppem;
348 double scale_y;
349 SHORT yMax;
350 SHORT yMin;
351 DWORD ntmFlags;
352 DWORD aa_flags;
353 UINT ntmCellHeight, ntmAvgWidth;
354 FONTSIGNATURE fs;
355 GdiFont *base_font;
356 VOID *GSUB_Table;
357 const VOID *vert_feature;
358 DWORD cache_num;
361 typedef struct {
362 struct list entry;
363 const WCHAR *font_name;
364 FONTSIGNATURE fs;
365 struct list links;
366 } SYSTEM_LINKS;
368 struct enum_charset_element {
369 DWORD mask;
370 DWORD charset;
371 WCHAR name[LF_FACESIZE];
374 struct enum_charset_list {
375 DWORD total;
376 struct enum_charset_element element[32];
379 #define GM_BLOCK_SIZE 128
380 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
382 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
383 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
384 static unsigned int unused_font_count;
385 #define UNUSED_CACHE_SIZE 10
386 static struct list system_links = LIST_INIT(system_links);
388 static struct list font_subst_list = LIST_INIT(font_subst_list);
390 static struct list font_list = LIST_INIT(font_list);
392 struct freetype_physdev
394 struct gdi_physdev dev;
395 GdiFont *font;
398 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
400 return (struct freetype_physdev *)dev;
403 static const struct gdi_dc_funcs freetype_funcs;
405 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
406 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
407 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
409 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
410 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
411 'W','i','n','d','o','w','s','\\',
412 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
413 'F','o','n','t','s','\0'};
415 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
416 'W','i','n','d','o','w','s',' ','N','T','\\',
417 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
418 'F','o','n','t','s','\0'};
420 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
421 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
422 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
423 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
425 static const WCHAR * const SystemFontValues[] = {
426 System_Value,
427 OEMFont_Value,
428 FixedSys_Value,
429 NULL
432 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
433 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
435 /* Interesting and well-known (frequently-assumed!) font names */
436 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
437 static const WCHAR Microsoft_Sans_Serif[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0 };
438 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
439 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
440 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
441 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
442 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
443 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
445 static const WCHAR arial[] = {'A','r','i','a','l',0};
446 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
447 static const WCHAR bitstream_vera_sans_mono[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',' ','M','o','n','o',0};
448 static const WCHAR bitstream_vera_serif[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','e','r','i','f',0};
449 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
450 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
451 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
452 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
453 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
454 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
456 static const WCHAR *default_serif_list[] =
458 times_new_roman,
459 liberation_serif,
460 bitstream_vera_serif,
461 NULL
464 static const WCHAR *default_fixed_list[] =
466 courier_new,
467 liberation_mono,
468 bitstream_vera_sans_mono,
469 NULL
472 static const WCHAR *default_sans_list[] =
474 arial,
475 liberation_sans,
476 bitstream_vera_sans,
477 NULL
480 typedef struct {
481 WCHAR *name;
482 INT charset;
483 } NameCs;
485 typedef struct tagFontSubst {
486 struct list entry;
487 NameCs from;
488 NameCs to;
489 } FontSubst;
491 /* Registry font cache key and value names */
492 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
493 'F','o','n','t','s',0};
494 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
495 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
496 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
497 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
498 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
499 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
500 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
501 static const WCHAR face_size_value[] = {'S','i','z','e',0};
502 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
503 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
504 static const WCHAR face_flags_value[] = {'F','l','a','g','s',0};
505 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
506 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
507 static const WCHAR face_file_name_value[] = {'F','i','l','e',' ','N','a','m','e','\0'};
508 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
511 struct font_mapping
513 struct list entry;
514 int refcount;
515 dev_t dev;
516 ino_t ino;
517 void *data;
518 size_t size;
521 static struct list mappings_list = LIST_INIT( mappings_list );
523 static UINT default_aa_flags;
524 static HKEY hkey_font_cache;
526 static CRITICAL_SECTION freetype_cs;
527 static CRITICAL_SECTION_DEBUG critsect_debug =
529 0, 0, &freetype_cs,
530 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
531 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
533 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
535 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
537 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
538 static BOOL use_default_fallback = FALSE;
540 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
541 static BOOL get_outline_text_metrics(GdiFont *font);
542 static BOOL get_bitmap_text_metrics(GdiFont *font);
543 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
544 static void remove_face_from_cache( Face *face );
546 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
547 'W','i','n','d','o','w','s',' ','N','T','\\',
548 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
549 'S','y','s','t','e','m','L','i','n','k',0};
551 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
552 'F','o','n','t','L','i','n','k','\\',
553 'S','y','s','t','e','m','L','i','n','k',0};
555 /****************************************
556 * Notes on .fon files
558 * The fonts System, FixedSys and Terminal are special. There are typically multiple
559 * versions installed for different resolutions and codepages. Windows stores which one to use
560 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
561 * Key Meaning
562 * FIXEDFON.FON FixedSys
563 * FONTS.FON System
564 * OEMFONT.FON Terminal
565 * LogPixels Current dpi set by the display control panel applet
566 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
567 * also has a LogPixels value that appears to mirror this)
569 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
570 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
571 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
572 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
573 * so that makes sense.
575 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
576 * to be mapped into the registry on Windows 2000 at least).
577 * I have
578 * woafont=app850.fon
579 * ega80woa.fon=ega80850.fon
580 * ega40woa.fon=ega40850.fon
581 * cga80woa.fon=cga80850.fon
582 * cga40woa.fon=cga40850.fon
585 /* These are all structures needed for the GSUB table */
587 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
588 #define TATEGAKI_LOWER_BOUND 0x02F1
590 typedef struct {
591 DWORD version;
592 WORD ScriptList;
593 WORD FeatureList;
594 WORD LookupList;
595 } GSUB_Header;
597 typedef struct {
598 CHAR ScriptTag[4];
599 WORD Script;
600 } GSUB_ScriptRecord;
602 typedef struct {
603 WORD ScriptCount;
604 GSUB_ScriptRecord ScriptRecord[1];
605 } GSUB_ScriptList;
607 typedef struct {
608 CHAR LangSysTag[4];
609 WORD LangSys;
610 } GSUB_LangSysRecord;
612 typedef struct {
613 WORD DefaultLangSys;
614 WORD LangSysCount;
615 GSUB_LangSysRecord LangSysRecord[1];
616 } GSUB_Script;
618 typedef struct {
619 WORD LookupOrder; /* Reserved */
620 WORD ReqFeatureIndex;
621 WORD FeatureCount;
622 WORD FeatureIndex[1];
623 } GSUB_LangSys;
625 typedef struct {
626 CHAR FeatureTag[4];
627 WORD Feature;
628 } GSUB_FeatureRecord;
630 typedef struct {
631 WORD FeatureCount;
632 GSUB_FeatureRecord FeatureRecord[1];
633 } GSUB_FeatureList;
635 typedef struct {
636 WORD FeatureParams; /* Reserved */
637 WORD LookupCount;
638 WORD LookupListIndex[1];
639 } GSUB_Feature;
641 typedef struct {
642 WORD LookupCount;
643 WORD Lookup[1];
644 } GSUB_LookupList;
646 typedef struct {
647 WORD LookupType;
648 WORD LookupFlag;
649 WORD SubTableCount;
650 WORD SubTable[1];
651 } GSUB_LookupTable;
653 typedef struct {
654 WORD CoverageFormat;
655 WORD GlyphCount;
656 WORD GlyphArray[1];
657 } GSUB_CoverageFormat1;
659 typedef struct {
660 WORD Start;
661 WORD End;
662 WORD StartCoverageIndex;
663 } GSUB_RangeRecord;
665 typedef struct {
666 WORD CoverageFormat;
667 WORD RangeCount;
668 GSUB_RangeRecord RangeRecord[1];
669 } GSUB_CoverageFormat2;
671 typedef struct {
672 WORD SubstFormat; /* = 1 */
673 WORD Coverage;
674 WORD DeltaGlyphID;
675 } GSUB_SingleSubstFormat1;
677 typedef struct {
678 WORD SubstFormat; /* = 2 */
679 WORD Coverage;
680 WORD GlyphCount;
681 WORD Substitute[1];
682 }GSUB_SingleSubstFormat2;
684 #ifdef HAVE_CARBON_CARBON_H
685 static char *find_cache_dir(void)
687 FSRef ref;
688 OSErr err;
689 static char cached_path[MAX_PATH];
690 static const char *wine = "/Wine", *fonts = "/Fonts";
692 if(*cached_path) return cached_path;
694 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
695 if(err != noErr)
697 WARN("can't create cached data folder\n");
698 return NULL;
700 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
701 if(err != noErr)
703 WARN("can't create cached data path\n");
704 *cached_path = '\0';
705 return NULL;
707 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
709 ERR("Could not create full path\n");
710 *cached_path = '\0';
711 return NULL;
713 strcat(cached_path, wine);
715 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
717 WARN("Couldn't mkdir %s\n", cached_path);
718 *cached_path = '\0';
719 return NULL;
721 strcat(cached_path, fonts);
722 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
724 WARN("Couldn't mkdir %s\n", cached_path);
725 *cached_path = '\0';
726 return NULL;
728 return cached_path;
731 /******************************************************************
732 * expand_mac_font
734 * Extracts individual TrueType font files from a Mac suitcase font
735 * and saves them into the user's caches directory (see
736 * find_cache_dir()).
737 * Returns a NULL terminated array of filenames.
739 * We do this because they are apps that try to read ttf files
740 * themselves and they don't like Mac suitcase files.
742 static char **expand_mac_font(const char *path)
744 FSRef ref;
745 SInt16 res_ref;
746 OSStatus s;
747 unsigned int idx;
748 const char *out_dir;
749 const char *filename;
750 int output_len;
751 struct {
752 char **array;
753 unsigned int size, max_size;
754 } ret;
756 TRACE("path %s\n", path);
758 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
759 if(s != noErr)
761 WARN("failed to get ref\n");
762 return NULL;
765 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
766 if(s != noErr)
768 TRACE("no data fork, so trying resource fork\n");
769 res_ref = FSOpenResFile(&ref, fsRdPerm);
770 if(res_ref == -1)
772 TRACE("unable to open resource fork\n");
773 return NULL;
777 ret.size = 0;
778 ret.max_size = 10;
779 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
780 if(!ret.array)
782 CloseResFile(res_ref);
783 return NULL;
786 out_dir = find_cache_dir();
788 filename = strrchr(path, '/');
789 if(!filename) filename = path;
790 else filename++;
792 /* output filename has the form out_dir/filename_%04x.ttf */
793 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
795 UseResFile(res_ref);
796 idx = 1;
797 while(1)
799 FamRec *fam_rec;
800 unsigned short *num_faces_ptr, num_faces, face;
801 AsscEntry *assoc;
802 Handle fond;
803 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
805 fond = Get1IndResource(fond_res, idx);
806 if(!fond) break;
807 TRACE("got fond resource %d\n", idx);
808 HLock(fond);
810 fam_rec = *(FamRec**)fond;
811 num_faces_ptr = (unsigned short *)(fam_rec + 1);
812 num_faces = GET_BE_WORD(*num_faces_ptr);
813 num_faces++;
814 assoc = (AsscEntry*)(num_faces_ptr + 1);
815 TRACE("num faces %04x\n", num_faces);
816 for(face = 0; face < num_faces; face++, assoc++)
818 Handle sfnt;
819 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
820 unsigned short size, font_id;
821 char *output;
823 size = GET_BE_WORD(assoc->fontSize);
824 font_id = GET_BE_WORD(assoc->fontID);
825 if(size != 0)
827 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
828 continue;
831 TRACE("trying to load sfnt id %04x\n", font_id);
832 sfnt = GetResource(sfnt_res, font_id);
833 if(!sfnt)
835 TRACE("can't get sfnt resource %04x\n", font_id);
836 continue;
839 output = HeapAlloc(GetProcessHeap(), 0, output_len);
840 if(output)
842 int fd;
844 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
846 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
847 if(fd != -1 || errno == EEXIST)
849 if(fd != -1)
851 unsigned char *sfnt_data;
853 HLock(sfnt);
854 sfnt_data = *(unsigned char**)sfnt;
855 write(fd, sfnt_data, GetHandleSize(sfnt));
856 HUnlock(sfnt);
857 close(fd);
859 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
861 ret.max_size *= 2;
862 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
864 ret.array[ret.size++] = output;
866 else
868 WARN("unable to create %s\n", output);
869 HeapFree(GetProcessHeap(), 0, output);
872 ReleaseResource(sfnt);
874 HUnlock(fond);
875 ReleaseResource(fond);
876 idx++;
878 CloseResFile(res_ref);
880 return ret.array;
883 #endif /* HAVE_CARBON_CARBON_H */
885 static inline BOOL is_win9x(void)
887 return GetVersion() & 0x80000000;
890 This function builds an FT_Fixed from a double. It fails if the absolute
891 value of the float number is greater than 32768.
893 static inline FT_Fixed FT_FixedFromFloat(double f)
895 return f * 0x10000;
899 This function builds an FT_Fixed from a FIXED. It simply put f.value
900 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
902 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
904 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
907 static BOOL is_hinting_enabled(void)
909 static int enabled = -1;
911 if (enabled == -1)
913 /* Use the >= 2.2.0 function if available */
914 if (pFT_Get_TrueType_Engine_Type)
916 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
917 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
919 #ifdef FT_DRIVER_HAS_HINTER
920 else
922 /* otherwise if we've been compiled with < 2.2.0 headers use the internal macro */
923 FT_Module mod = pFT_Get_Module(library, "truetype");
924 enabled = (mod && FT_DRIVER_HAS_HINTER(mod));
926 #endif
927 else enabled = FALSE;
928 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
930 return enabled;
933 static BOOL is_subpixel_rendering_enabled( void )
935 #ifdef HAVE_FREETYPE_FTLCDFIL_H
936 static int enabled = -1;
937 if (enabled == -1)
939 enabled = (pFT_Library_SetLcdFilter &&
940 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature);
941 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
943 return enabled;
944 #else
945 return FALSE;
946 #endif
950 static const struct list *get_face_list_from_family(const Family *family)
952 if (!list_empty(&family->faces))
953 return &family->faces;
954 else
955 return family->replacement;
958 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
960 Family *family;
961 Face *face;
962 const WCHAR *file;
964 TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
966 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
968 const struct list *face_list;
969 if(face_name && strcmpiW(face_name, family->FamilyName))
970 continue;
971 face_list = get_face_list_from_family(family);
972 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
974 if (!face->file)
975 continue;
976 file = strrchrW(face->file, '/');
977 if(!file)
978 file = face->file;
979 else
980 file++;
981 if(strcmpiW(file, file_name)) continue;
982 face->refcount++;
983 return face;
986 return NULL;
989 static Family *find_family_from_name(const WCHAR *name)
991 Family *family;
993 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
995 if(!strcmpiW(family->FamilyName, name))
996 return family;
999 return NULL;
1002 static Family *find_family_from_any_name(const WCHAR *name)
1004 Family *family;
1006 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1008 if(!strcmpiW(family->FamilyName, name))
1009 return family;
1010 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
1011 return family;
1014 return NULL;
1017 static void DumpSubstList(void)
1019 FontSubst *psub;
1021 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
1023 if(psub->from.charset != -1 || psub->to.charset != -1)
1024 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
1025 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
1026 else
1027 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
1028 debugstr_w(psub->to.name));
1030 return;
1033 static LPWSTR strdupW(LPCWSTR p)
1035 LPWSTR ret;
1036 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
1037 ret = HeapAlloc(GetProcessHeap(), 0, len);
1038 memcpy(ret, p, len);
1039 return ret;
1042 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1043 INT from_charset)
1045 FontSubst *element;
1047 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1049 if(!strcmpiW(element->from.name, from_name) &&
1050 (element->from.charset == from_charset ||
1051 element->from.charset == -1))
1052 return element;
1055 return NULL;
1058 #define ADD_FONT_SUBST_FORCE 1
1060 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1062 FontSubst *from_exist, *to_exist;
1064 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1066 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1068 list_remove(&from_exist->entry);
1069 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
1070 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
1071 HeapFree(GetProcessHeap(), 0, from_exist);
1072 from_exist = NULL;
1075 if(!from_exist)
1077 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1079 if(to_exist)
1081 HeapFree(GetProcessHeap(), 0, subst->to.name);
1082 subst->to.name = strdupW(to_exist->to.name);
1085 list_add_tail(subst_list, &subst->entry);
1087 return TRUE;
1090 HeapFree(GetProcessHeap(), 0, subst->from.name);
1091 HeapFree(GetProcessHeap(), 0, subst->to.name);
1092 HeapFree(GetProcessHeap(), 0, subst);
1093 return FALSE;
1096 static WCHAR *towstr(UINT cp, const char *str)
1098 int len;
1099 WCHAR *wstr;
1101 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1102 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1103 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1104 return wstr;
1107 static char *strWtoA(UINT cp, const WCHAR *str)
1109 int len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL );
1110 char *ret = HeapAlloc( GetProcessHeap(), 0, len );
1111 WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL );
1112 return ret;
1115 static void split_subst_info(NameCs *nc, LPSTR str)
1117 CHAR *p = strrchr(str, ',');
1119 nc->charset = -1;
1120 if(p && *(p+1)) {
1121 nc->charset = strtol(p+1, NULL, 10);
1122 *p = '\0';
1124 nc->name = towstr(CP_ACP, str);
1127 static void LoadSubstList(void)
1129 FontSubst *psub;
1130 HKEY hkey;
1131 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1132 LPSTR value;
1133 LPVOID data;
1135 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1136 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1137 &hkey) == ERROR_SUCCESS) {
1139 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1140 &valuelen, &datalen, NULL, NULL);
1142 valuelen++; /* returned value doesn't include room for '\0' */
1143 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1144 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1146 dlen = datalen;
1147 vlen = valuelen;
1148 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1149 &dlen) == ERROR_SUCCESS) {
1150 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1152 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1153 split_subst_info(&psub->from, value);
1154 split_subst_info(&psub->to, data);
1156 /* Win 2000 doesn't allow mapping between different charsets
1157 or mapping of DEFAULT_CHARSET */
1158 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1159 psub->to.charset == DEFAULT_CHARSET) {
1160 HeapFree(GetProcessHeap(), 0, psub->to.name);
1161 HeapFree(GetProcessHeap(), 0, psub->from.name);
1162 HeapFree(GetProcessHeap(), 0, psub);
1163 } else {
1164 add_font_subst(&font_subst_list, psub, 0);
1166 /* reset dlen and vlen */
1167 dlen = datalen;
1168 vlen = valuelen;
1170 HeapFree(GetProcessHeap(), 0, data);
1171 HeapFree(GetProcessHeap(), 0, value);
1172 RegCloseKey(hkey);
1177 /*****************************************************************
1178 * get_name_table_entry
1180 * Supply the platform, encoding, language and name ids in req
1181 * and if the name exists the function will fill in the string
1182 * and string_len members. The string is owned by FreeType so
1183 * don't free it. Returns TRUE if the name is found else FALSE.
1185 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1187 FT_SfntName name;
1188 FT_UInt num_names, name_index;
1190 if(FT_IS_SFNT(ft_face))
1192 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1194 for(name_index = 0; name_index < num_names; name_index++)
1196 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1198 if((name.platform_id == req->platform_id) &&
1199 ((name.encoding_id == TT_MS_ID_UNICODE_CS) || (name.encoding_id == TT_MS_ID_SYMBOL_CS)) &&
1200 (name.language_id == req->language_id) &&
1201 (name.name_id == req->name_id))
1203 req->string = name.string;
1204 req->string_len = name.string_len;
1205 return TRUE;
1210 req->string = NULL;
1211 req->string_len = 0;
1212 return FALSE;
1215 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1217 WCHAR *ret = NULL;
1218 FT_SfntName name;
1220 name.platform_id = TT_PLATFORM_MICROSOFT;
1221 name.language_id = language_id;
1222 name.name_id = name_id;
1224 if(get_name_table_entry(ft_face, &name))
1226 FT_UInt i;
1228 /* String is not nul terminated and string_len is a byte length. */
1229 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1230 for(i = 0; i < name.string_len / 2; i++)
1232 WORD *tmp = (WORD *)&name.string[i * 2];
1233 ret[i] = GET_BE_WORD(*tmp);
1235 ret[i] = 0;
1236 TRACE("Got localised name %s\n", debugstr_w(ret));
1239 return ret;
1242 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1244 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1245 if (f1->scalable) return TRUE;
1246 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1247 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1250 static void release_family( Family *family )
1252 if (--family->refcount) return;
1253 assert( list_empty( &family->faces ));
1254 list_remove( &family->entry );
1255 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1256 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1257 HeapFree( GetProcessHeap(), 0, family );
1260 static void release_face( Face *face )
1262 if (--face->refcount) return;
1263 if (face->family)
1265 if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
1266 list_remove( &face->entry );
1267 release_family( face->family );
1269 HeapFree( GetProcessHeap(), 0, face->file );
1270 HeapFree( GetProcessHeap(), 0, face->StyleName );
1271 HeapFree( GetProcessHeap(), 0, face->FullName );
1272 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1273 HeapFree( GetProcessHeap(), 0, face );
1276 static inline int style_order(const Face *face)
1278 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1280 case NTM_REGULAR:
1281 return 0;
1282 case NTM_BOLD:
1283 return 1;
1284 case NTM_ITALIC:
1285 return 2;
1286 case NTM_BOLD | NTM_ITALIC:
1287 return 3;
1288 default:
1289 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1290 debugstr_w(face->family->FamilyName),
1291 debugstr_w(face->StyleName),
1292 face->ntmFlags);
1293 return 9999;
1297 static BOOL insert_face_in_family_list( Face *face, Family *family )
1299 Face *cursor;
1301 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1303 if (faces_equal( face, cursor ))
1305 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1306 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1307 cursor->font_version, face->font_version);
1309 if (face->file && face->dev == cursor->dev && face->ino == cursor->ino)
1311 cursor->refcount++;
1312 TRACE("Font %s already in list, refcount now %d\n",
1313 debugstr_w(face->file), cursor->refcount);
1314 return FALSE;
1316 if (face->font_version <= cursor->font_version)
1318 TRACE("Original font %s is newer so skipping %s\n",
1319 debugstr_w(cursor->file), debugstr_w(face->file));
1320 return FALSE;
1322 else
1324 TRACE("Replacing original %s with %s\n",
1325 debugstr_w(cursor->file), debugstr_w(face->file));
1326 list_add_before( &cursor->entry, &face->entry );
1327 face->family = family;
1328 family->refcount++;
1329 face->refcount++;
1330 release_face( cursor );
1331 return TRUE;
1334 else
1335 TRACE("Adding new %s\n", debugstr_w(face->file));
1337 if (style_order( face ) < style_order( cursor )) break;
1340 list_add_before( &cursor->entry, &face->entry );
1341 face->family = family;
1342 family->refcount++;
1343 face->refcount++;
1344 return TRUE;
1347 /****************************************************************
1348 * NB This function stores the ptrs to the strings to save copying.
1349 * Don't free them after calling.
1351 static Family *create_family( WCHAR *name, WCHAR *english_name )
1353 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1354 family->refcount = 1;
1355 family->FamilyName = name;
1356 family->EnglishName = english_name;
1357 list_init( &family->faces );
1358 family->replacement = &family->faces;
1359 list_add_tail( &font_list, &family->entry );
1361 return family;
1364 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1366 DWORD type, size = sizeof(DWORD);
1368 if (RegQueryValueExW(hkey, value, NULL, &type, (BYTE *)data, &size) ||
1369 type != REG_DWORD || size != sizeof(DWORD))
1371 *data = 0;
1372 return ERROR_BAD_CONFIGURATION;
1374 return ERROR_SUCCESS;
1377 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1379 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1382 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1384 DWORD needed, strike_index = 0;
1385 HKEY hkey_strike;
1387 /* If we have a File Name key then this is a real font, not just the parent
1388 key of a bunch of non-scalable strikes */
1389 needed = buffer_size;
1390 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1392 Face *face;
1393 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1394 face->cached_enum_data = NULL;
1395 face->family = NULL;
1397 face->refcount = 1;
1398 face->file = strdupW( buffer );
1399 face->StyleName = strdupW(face_name);
1401 needed = buffer_size;
1402 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1403 face->FullName = strdupW( buffer );
1404 else
1405 face->FullName = NULL;
1407 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1408 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1409 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1410 reg_load_dword(hkey_face, face_flags_value, (DWORD*)&face->flags);
1412 needed = sizeof(face->fs);
1413 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1415 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1417 face->scalable = TRUE;
1418 memset(&face->size, 0, sizeof(face->size));
1420 else
1422 face->scalable = FALSE;
1423 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1424 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1425 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1426 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1427 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1429 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1430 face->size.height, face->size.width, face->size.size >> 6,
1431 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1434 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1435 face->fs.fsCsb[0], face->fs.fsCsb[1],
1436 face->fs.fsUsb[0], face->fs.fsUsb[1],
1437 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1439 if (insert_face_in_family_list(face, family))
1440 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1442 release_face( face );
1445 /* load bitmap strikes */
1447 needed = buffer_size;
1448 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1450 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1452 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1453 RegCloseKey(hkey_strike);
1455 needed = buffer_size;
1459 static void load_font_list_from_cache(HKEY hkey_font_cache)
1461 DWORD size, family_index = 0;
1462 Family *family;
1463 HKEY hkey_family;
1464 WCHAR buffer[4096];
1466 size = sizeof(buffer);
1467 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1469 WCHAR *english_family = NULL;
1470 WCHAR *family_name = strdupW( buffer );
1471 DWORD face_index = 0;
1473 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1474 TRACE("opened family key %s\n", debugstr_w(family_name));
1475 size = sizeof(buffer);
1476 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1477 english_family = strdupW( buffer );
1479 family = create_family(family_name, english_family);
1481 if(english_family)
1483 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1484 subst->from.name = strdupW(english_family);
1485 subst->from.charset = -1;
1486 subst->to.name = strdupW(family_name);
1487 subst->to.charset = -1;
1488 add_font_subst(&font_subst_list, subst, 0);
1491 size = sizeof(buffer);
1492 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1494 WCHAR *face_name = strdupW( buffer );
1495 HKEY hkey_face;
1497 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1499 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1500 RegCloseKey(hkey_face);
1502 HeapFree( GetProcessHeap(), 0, face_name );
1503 size = sizeof(buffer);
1505 RegCloseKey(hkey_family);
1506 release_family( family );
1507 size = sizeof(buffer);
1511 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1513 LONG ret;
1514 HKEY hkey_wine_fonts;
1516 /* We don't want to create the fonts key as volatile, so open this first */
1517 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1518 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1519 if(ret != ERROR_SUCCESS)
1521 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1522 return ret;
1525 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1526 KEY_ALL_ACCESS, NULL, hkey, disposition);
1527 RegCloseKey(hkey_wine_fonts);
1528 return ret;
1531 static void add_face_to_cache(Face *face)
1533 HKEY hkey_family, hkey_face;
1534 WCHAR *face_key_name;
1536 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1537 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1538 if(face->family->EnglishName)
1539 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1540 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1542 if(face->scalable)
1543 face_key_name = face->StyleName;
1544 else
1546 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1547 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1548 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1550 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1551 &hkey_face, NULL);
1552 if(!face->scalable)
1553 HeapFree(GetProcessHeap(), 0, face_key_name);
1555 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1556 (strlenW(face->file) + 1) * sizeof(WCHAR));
1557 if (face->FullName)
1558 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1559 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1561 reg_save_dword(hkey_face, face_index_value, face->face_index);
1562 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1563 reg_save_dword(hkey_face, face_version_value, face->font_version);
1564 if (face->flags) reg_save_dword(hkey_face, face_flags_value, face->flags);
1566 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1568 if(!face->scalable)
1570 reg_save_dword(hkey_face, face_height_value, face->size.height);
1571 reg_save_dword(hkey_face, face_width_value, face->size.width);
1572 reg_save_dword(hkey_face, face_size_value, face->size.size);
1573 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1574 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1575 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1577 RegCloseKey(hkey_face);
1578 RegCloseKey(hkey_family);
1581 static void remove_face_from_cache( Face *face )
1583 HKEY hkey_family;
1585 RegOpenKeyExW( hkey_font_cache, face->family->FamilyName, 0, KEY_ALL_ACCESS, &hkey_family );
1587 if (face->scalable)
1589 RegDeleteKeyW( hkey_family, face->StyleName );
1591 else
1593 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1594 WCHAR *face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1595 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1596 RegDeleteKeyW( hkey_family, face_key_name );
1597 HeapFree(GetProcessHeap(), 0, face_key_name);
1599 RegCloseKey(hkey_family);
1602 static WCHAR *prepend_at(WCHAR *family)
1604 WCHAR *str;
1606 if (!family)
1607 return NULL;
1609 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1610 str[0] = '@';
1611 strcpyW(str + 1, family);
1612 HeapFree(GetProcessHeap(), 0, family);
1613 return str;
1616 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1618 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1619 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1621 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1622 if (!*name)
1624 *name = *english;
1625 *english = NULL;
1627 else if (!strcmpiW( *name, *english ))
1629 HeapFree( GetProcessHeap(), 0, *english );
1630 *english = NULL;
1633 if (vertical)
1635 *name = prepend_at( *name );
1636 *english = prepend_at( *english );
1640 static Family *get_family( FT_Face ft_face, BOOL vertical )
1642 Family *family;
1643 WCHAR *name, *english_name;
1645 get_family_names( ft_face, &name, &english_name, vertical );
1647 family = find_family_from_name( name );
1649 if (!family)
1651 family = create_family( name, english_name );
1652 if (english_name)
1654 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1655 subst->from.name = strdupW( english_name );
1656 subst->from.charset = -1;
1657 subst->to.name = strdupW( name );
1658 subst->to.charset = -1;
1659 add_font_subst( &font_subst_list, subst, 0 );
1662 else
1664 HeapFree( GetProcessHeap(), 0, name );
1665 HeapFree( GetProcessHeap(), 0, english_name );
1666 family->refcount++;
1669 return family;
1672 static inline FT_Fixed get_font_version( FT_Face ft_face )
1674 FT_Fixed version = 0;
1675 TT_Header *header;
1677 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1678 if (header) version = header->Font_Revision;
1680 return version;
1683 static inline DWORD get_ntm_flags( FT_Face ft_face )
1685 DWORD flags = 0;
1686 FT_ULong table_size = 0;
1688 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1689 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1690 if (flags == 0) flags = NTM_REGULAR;
1692 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1693 flags |= NTM_PS_OPENTYPE;
1695 return flags;
1698 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1700 int internal_leading = 0;
1701 FT_WinFNT_HeaderRec winfnt_header;
1703 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1704 internal_leading = winfnt_header.internal_leading;
1706 return internal_leading;
1709 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1711 TT_OS2 *os2;
1712 FT_UInt dummy;
1713 CHARSETINFO csi;
1714 FT_WinFNT_HeaderRec winfnt_header;
1715 int i;
1717 memset( fs, 0, sizeof(*fs) );
1719 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1720 if (os2)
1722 fs->fsUsb[0] = os2->ulUnicodeRange1;
1723 fs->fsUsb[1] = os2->ulUnicodeRange2;
1724 fs->fsUsb[2] = os2->ulUnicodeRange3;
1725 fs->fsUsb[3] = os2->ulUnicodeRange4;
1727 if (os2->version == 0)
1729 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1730 fs->fsCsb[0] = FS_LATIN1;
1731 else
1732 fs->fsCsb[0] = FS_SYMBOL;
1734 else
1736 fs->fsCsb[0] = os2->ulCodePageRange1;
1737 fs->fsCsb[1] = os2->ulCodePageRange2;
1740 else
1742 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1744 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1745 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1746 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1747 *fs = csi.fs;
1751 if (fs->fsCsb[0] == 0)
1753 /* let's see if we can find any interesting cmaps */
1754 for (i = 0; i < ft_face->num_charmaps; i++)
1756 switch (ft_face->charmaps[i]->encoding)
1758 case FT_ENCODING_UNICODE:
1759 case FT_ENCODING_APPLE_ROMAN:
1760 fs->fsCsb[0] |= FS_LATIN1;
1761 break;
1762 case FT_ENCODING_MS_SYMBOL:
1763 fs->fsCsb[0] |= FS_SYMBOL;
1764 break;
1765 default:
1766 break;
1772 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1773 DWORD flags )
1775 struct stat st;
1776 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1777 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1779 face->refcount = 1;
1780 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
1781 if (!face->StyleName)
1782 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1783 if (!face->StyleName)
1785 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1788 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
1789 if (!face->FullName)
1790 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1791 if (flags & ADDFONT_VERTICAL_FONT)
1792 face->FullName = prepend_at( face->FullName );
1794 face->dev = 0;
1795 face->ino = 0;
1796 if (file)
1798 face->file = towstr( CP_UNIXCP, file );
1799 face->font_data_ptr = NULL;
1800 face->font_data_size = 0;
1801 if (!stat( file, &st ))
1803 face->dev = st.st_dev;
1804 face->ino = st.st_ino;
1807 else
1809 face->file = NULL;
1810 face->font_data_ptr = font_data_ptr;
1811 face->font_data_size = font_data_size;
1814 face->face_index = face_index;
1815 get_fontsig( ft_face, &face->fs );
1816 face->ntmFlags = get_ntm_flags( ft_face );
1817 face->font_version = get_font_version( ft_face );
1819 if (FT_IS_SCALABLE( ft_face ))
1821 memset( &face->size, 0, sizeof(face->size) );
1822 face->scalable = TRUE;
1824 else
1826 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1827 size->height, size->width, size->size >> 6,
1828 size->x_ppem >> 6, size->y_ppem >> 6);
1829 face->size.height = size->height;
1830 face->size.width = size->width;
1831 face->size.size = size->size;
1832 face->size.x_ppem = size->x_ppem;
1833 face->size.y_ppem = size->y_ppem;
1834 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1835 face->scalable = FALSE;
1838 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
1839 face->flags = flags;
1840 face->family = NULL;
1841 face->cached_enum_data = NULL;
1843 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1844 face->fs.fsCsb[0], face->fs.fsCsb[1],
1845 face->fs.fsUsb[0], face->fs.fsUsb[1],
1846 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1848 return face;
1851 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1852 FT_Long face_index, DWORD flags )
1854 Face *face;
1855 Family *family;
1857 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags );
1858 family = get_family( ft_face, flags & ADDFONT_VERTICAL_FONT );
1859 if (insert_face_in_family_list( face, family ))
1861 if (flags & ADDFONT_ADD_TO_CACHE)
1862 add_face_to_cache( face );
1864 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1865 debugstr_w(face->StyleName));
1867 release_face( face );
1868 release_family( family );
1871 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1872 FT_Long face_index, BOOL allow_bitmap )
1874 FT_Error err;
1875 TT_OS2 *pOS2;
1876 FT_Face ft_face;
1878 if (file)
1880 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1881 err = pFT_New_Face(library, file, face_index, &ft_face);
1883 else
1885 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1886 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1889 if (err != 0)
1891 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1892 return NULL;
1895 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1896 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1898 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1899 goto fail;
1902 if (!FT_IS_SFNT( ft_face ))
1904 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1906 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1907 goto fail;
1910 else
1912 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1913 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1914 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1916 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1917 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1918 goto fail;
1921 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1922 we don't want to load these. */
1923 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1925 FT_ULong len = 0;
1927 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1929 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1930 goto fail;
1935 if (!ft_face->family_name || !ft_face->style_name)
1937 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1938 goto fail;
1941 return ft_face;
1942 fail:
1943 pFT_Done_Face( ft_face );
1944 return NULL;
1947 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1949 FT_Face ft_face;
1950 FT_Long face_index = 0, num_faces;
1951 INT ret = 0;
1953 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1954 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1956 #ifdef HAVE_CARBON_CARBON_H
1957 if(file)
1959 char **mac_list = expand_mac_font(file);
1960 if(mac_list)
1962 BOOL had_one = FALSE;
1963 char **cursor;
1964 for(cursor = mac_list; *cursor; cursor++)
1966 had_one = TRUE;
1967 AddFontToList(*cursor, NULL, 0, flags);
1968 HeapFree(GetProcessHeap(), 0, *cursor);
1970 HeapFree(GetProcessHeap(), 0, mac_list);
1971 if(had_one)
1972 return 1;
1975 #endif /* HAVE_CARBON_CARBON_H */
1977 do {
1978 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_ALLOW_BITMAP );
1979 if (!ft_face) return 0;
1981 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1983 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1984 pFT_Done_Face(ft_face);
1985 return 0;
1988 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags);
1989 ++ret;
1991 if (FT_HAS_VERTICAL(ft_face))
1993 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index,
1994 flags | ADDFONT_VERTICAL_FONT);
1995 ++ret;
1998 num_faces = ft_face->num_faces;
1999 pFT_Done_Face(ft_face);
2000 } while(num_faces > ++face_index);
2001 return ret;
2004 static int remove_font_resource( const char *file, DWORD flags )
2006 Family *family, *family_next;
2007 Face *face, *face_next;
2008 struct stat st;
2009 int count = 0;
2011 if (stat( file, &st ) == -1) return 0;
2012 LIST_FOR_EACH_ENTRY_SAFE( family, family_next, &font_list, Family, entry )
2014 family->refcount++;
2015 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, Face, entry )
2017 if (!face->file) continue;
2018 if (LOWORD(face->flags) != LOWORD(flags)) continue;
2019 if (st.st_dev == face->dev && st.st_ino == face->ino)
2021 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount );
2022 release_face( face );
2023 count++;
2026 release_family( family );
2028 return count;
2031 static void DumpFontList(void)
2033 Family *family;
2034 Face *face;
2036 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2037 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
2038 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2039 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
2040 if(!face->scalable)
2041 TRACE(" %d", face->size.height);
2042 TRACE("\n");
2045 return;
2048 /***********************************************************
2049 * The replacement list is a way to map an entire font
2050 * family onto another family. For example adding
2052 * [HKCU\Software\Wine\Fonts\Replacements]
2053 * "Wingdings"="Winedings"
2055 * would enumerate the Winedings font both as Winedings and
2056 * Wingdings. However if a real Wingdings font is present the
2057 * replacement does not take place.
2060 static void LoadReplaceList(void)
2062 HKEY hkey;
2063 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2064 LPWSTR value;
2065 LPVOID data;
2067 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2068 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
2070 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2071 &valuelen, &datalen, NULL, NULL);
2073 valuelen++; /* returned value doesn't include room for '\0' */
2074 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2075 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2077 dlen = datalen;
2078 vlen = valuelen;
2079 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
2080 &dlen) == ERROR_SUCCESS) {
2081 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
2082 /* "NewName"="Oldname" */
2083 if(!find_family_from_any_name(value))
2085 Family * const family = find_family_from_any_name(data);
2086 if (family != NULL)
2088 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2089 if (new_family != NULL)
2091 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
2092 new_family->FamilyName = strdupW(value);
2093 new_family->EnglishName = NULL;
2094 list_init(&new_family->faces);
2095 new_family->replacement = &family->faces;
2096 list_add_tail(&font_list, &new_family->entry);
2099 else
2101 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2104 else
2106 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2108 /* reset dlen and vlen */
2109 dlen = datalen;
2110 vlen = valuelen;
2112 HeapFree(GetProcessHeap(), 0, data);
2113 HeapFree(GetProcessHeap(), 0, value);
2114 RegCloseKey(hkey);
2118 static const WCHAR *font_links_list[] =
2120 Lucida_Sans_Unicode,
2121 Microsoft_Sans_Serif,
2122 Tahoma
2125 static const struct font_links_defaults_list
2127 /* Keyed off substitution for "MS Shell Dlg" */
2128 const WCHAR *shelldlg;
2129 /* Maximum of four substitutes, plus terminating NULL pointer */
2130 const WCHAR *substitutes[5];
2131 } font_links_defaults_list[] =
2133 /* Non East-Asian */
2134 { Tahoma, /* FIXME unverified ordering */
2135 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2137 /* Below lists are courtesy of
2138 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2140 /* Japanese */
2141 { MS_UI_Gothic,
2142 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2144 /* Chinese Simplified */
2145 { SimSun,
2146 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2148 /* Korean */
2149 { Gulim,
2150 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2152 /* Chinese Traditional */
2153 { PMingLiU,
2154 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2159 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2161 SYSTEM_LINKS *font_link;
2163 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2165 if(!strcmpiW(font_link->font_name, name))
2166 return font_link;
2169 return NULL;
2172 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2174 const WCHAR *value;
2175 int i;
2176 FontSubst *psub;
2177 Family *family;
2178 Face *face;
2179 const WCHAR *file;
2181 if (values)
2183 SYSTEM_LINKS *font_link;
2185 psub = get_font_subst(&font_subst_list, name, -1);
2186 /* Don't store fonts that are only substitutes for other fonts */
2187 if(psub)
2189 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2190 return;
2193 font_link = find_font_link(name);
2194 if (font_link == NULL)
2196 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2197 font_link->font_name = strdupW(name);
2198 list_init(&font_link->links);
2199 list_add_tail(&system_links, &font_link->entry);
2202 memset(&font_link->fs, 0, sizeof font_link->fs);
2203 for (i = 0; values[i] != NULL; i++)
2205 const struct list *face_list;
2206 CHILD_FONT *child_font;
2208 value = values[i];
2209 if (!strcmpiW(name,value))
2210 continue;
2211 psub = get_font_subst(&font_subst_list, value, -1);
2212 if(psub)
2213 value = psub->to.name;
2214 family = find_family_from_name(value);
2215 if (!family)
2216 continue;
2217 file = NULL;
2218 /* Use first extant filename for this Family */
2219 face_list = get_face_list_from_family(family);
2220 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2222 if (!face->file)
2223 continue;
2224 file = strrchrW(face->file, '/');
2225 if (!file)
2226 file = face->file;
2227 else
2228 file++;
2229 break;
2231 if (!file)
2232 continue;
2233 face = find_face_from_filename(file, value);
2234 if(!face)
2236 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2237 continue;
2240 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2241 child_font->face = face;
2242 child_font->font = NULL;
2243 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2244 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2245 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2246 child_font->face->face_index);
2247 list_add_tail(&font_link->links, &child_font->entry);
2249 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2255 /*************************************************************
2256 * init_system_links
2258 static BOOL init_system_links(void)
2260 HKEY hkey;
2261 BOOL ret = FALSE;
2262 DWORD type, max_val, max_data, val_len, data_len, index;
2263 WCHAR *value, *data;
2264 WCHAR *entry, *next;
2265 SYSTEM_LINKS *font_link, *system_font_link;
2266 CHILD_FONT *child_font;
2267 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2268 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2269 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2270 Face *face;
2271 FontSubst *psub;
2272 UINT i, j;
2274 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2276 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2277 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2278 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2279 val_len = max_val + 1;
2280 data_len = max_data;
2281 index = 0;
2282 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2284 psub = get_font_subst(&font_subst_list, value, -1);
2285 /* Don't store fonts that are only substitutes for other fonts */
2286 if(psub)
2288 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2289 goto next;
2291 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2292 font_link->font_name = strdupW(value);
2293 memset(&font_link->fs, 0, sizeof font_link->fs);
2294 list_init(&font_link->links);
2295 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2297 WCHAR *face_name;
2298 CHILD_FONT *child_font;
2300 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2302 next = entry + strlenW(entry) + 1;
2304 face_name = strchrW(entry, ',');
2305 if(face_name)
2307 *face_name++ = 0;
2308 while(isspaceW(*face_name))
2309 face_name++;
2311 psub = get_font_subst(&font_subst_list, face_name, -1);
2312 if(psub)
2313 face_name = psub->to.name;
2315 face = find_face_from_filename(entry, face_name);
2316 if(!face)
2318 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2319 continue;
2322 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2323 child_font->face = face;
2324 child_font->font = NULL;
2325 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2326 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2327 TRACE("Adding file %s index %ld\n",
2328 debugstr_w(child_font->face->file), child_font->face->face_index);
2329 list_add_tail(&font_link->links, &child_font->entry);
2331 list_add_tail(&system_links, &font_link->entry);
2332 next:
2333 val_len = max_val + 1;
2334 data_len = max_data;
2337 HeapFree(GetProcessHeap(), 0, value);
2338 HeapFree(GetProcessHeap(), 0, data);
2339 RegCloseKey(hkey);
2343 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2344 if (!psub) {
2345 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2346 goto skip_internal;
2349 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2351 const FontSubst *psub2;
2352 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2354 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2356 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2357 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2359 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2360 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2362 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2364 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2368 skip_internal:
2370 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2371 that Tahoma has */
2373 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2374 system_font_link->font_name = strdupW(System);
2375 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2376 list_init(&system_font_link->links);
2378 face = find_face_from_filename(tahoma_ttf, Tahoma);
2379 if(face)
2381 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2382 child_font->face = face;
2383 child_font->font = NULL;
2384 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2385 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2386 TRACE("Found Tahoma in %s index %ld\n",
2387 debugstr_w(child_font->face->file), child_font->face->face_index);
2388 list_add_tail(&system_font_link->links, &child_font->entry);
2390 font_link = find_font_link(Tahoma);
2391 if (font_link != NULL)
2393 CHILD_FONT *font_link_entry;
2394 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2396 CHILD_FONT *new_child;
2397 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2398 new_child->face = font_link_entry->face;
2399 new_child->font = NULL;
2400 new_child->face->refcount++;
2401 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2402 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2403 list_add_tail(&system_font_link->links, &new_child->entry);
2406 list_add_tail(&system_links, &system_font_link->entry);
2407 return ret;
2410 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2412 DIR *dir;
2413 struct dirent *dent;
2414 char path[MAX_PATH];
2416 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2418 dir = opendir(dirname);
2419 if(!dir) {
2420 WARN("Can't open directory %s\n", debugstr_a(dirname));
2421 return FALSE;
2423 while((dent = readdir(dir)) != NULL) {
2424 struct stat statbuf;
2426 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2427 continue;
2429 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2431 sprintf(path, "%s/%s", dirname, dent->d_name);
2433 if(stat(path, &statbuf) == -1)
2435 WARN("Can't stat %s\n", debugstr_a(path));
2436 continue;
2438 if(S_ISDIR(statbuf.st_mode))
2439 ReadFontDir(path, external_fonts);
2440 else
2442 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2443 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2444 AddFontToList(path, NULL, 0, addfont_flags);
2447 closedir(dir);
2448 return TRUE;
2451 #ifdef SONAME_LIBFONTCONFIG
2453 static BOOL fontconfig_enabled;
2455 static UINT parse_aa_pattern( FcPattern *pattern )
2457 FcBool antialias;
2458 int rgba;
2459 UINT aa_flags = 0;
2461 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2462 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2464 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2466 switch (rgba)
2468 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2469 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2470 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2471 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2472 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2475 return aa_flags;
2478 static void init_fontconfig(void)
2480 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2482 if (!fc_handle)
2484 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2485 return;
2488 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2489 LOAD_FUNCPTR(FcConfigSubstitute);
2490 LOAD_FUNCPTR(FcFontList);
2491 LOAD_FUNCPTR(FcFontSetDestroy);
2492 LOAD_FUNCPTR(FcInit);
2493 LOAD_FUNCPTR(FcObjectSetAdd);
2494 LOAD_FUNCPTR(FcObjectSetCreate);
2495 LOAD_FUNCPTR(FcObjectSetDestroy);
2496 LOAD_FUNCPTR(FcPatternCreate);
2497 LOAD_FUNCPTR(FcPatternDestroy);
2498 LOAD_FUNCPTR(FcPatternGetBool);
2499 LOAD_FUNCPTR(FcPatternGetInteger);
2500 LOAD_FUNCPTR(FcPatternGetString);
2501 #undef LOAD_FUNCPTR
2503 if (pFcInit())
2505 FcPattern *pattern = pFcPatternCreate();
2506 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2507 default_aa_flags = parse_aa_pattern( pattern );
2508 pFcPatternDestroy( pattern );
2509 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2510 fontconfig_enabled = TRUE;
2514 static void load_fontconfig_fonts(void)
2516 FcPattern *pat;
2517 FcObjectSet *os;
2518 FcFontSet *fontset;
2519 int i, len;
2520 char *file;
2521 const char *ext;
2523 if (!fontconfig_enabled) return;
2525 pat = pFcPatternCreate();
2526 os = pFcObjectSetCreate();
2527 pFcObjectSetAdd(os, FC_FILE);
2528 pFcObjectSetAdd(os, FC_SCALABLE);
2529 pFcObjectSetAdd(os, FC_ANTIALIAS);
2530 pFcObjectSetAdd(os, FC_RGBA);
2531 fontset = pFcFontList(NULL, pat, os);
2532 if(!fontset) return;
2533 for(i = 0; i < fontset->nfont; i++) {
2534 FcBool scalable;
2535 DWORD aa_flags;
2537 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2538 continue;
2540 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2542 /* We're just interested in OT/TT fonts for now, so this hack just
2543 picks up the scalable fonts without extensions .pf[ab] to save time
2544 loading every other font */
2546 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2548 TRACE("not scalable\n");
2549 continue;
2552 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2553 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2555 len = strlen( file );
2556 if(len < 4) continue;
2557 ext = &file[ len - 3 ];
2558 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2559 AddFontToList(file, NULL, 0,
2560 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2562 pFcFontSetDestroy(fontset);
2563 pFcObjectSetDestroy(os);
2564 pFcPatternDestroy(pat);
2567 #elif defined(HAVE_CARBON_CARBON_H)
2569 static void load_mac_font_callback(const void *value, void *context)
2571 CFStringRef pathStr = value;
2572 CFIndex len;
2573 char* path;
2575 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2576 path = HeapAlloc(GetProcessHeap(), 0, len);
2577 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2579 TRACE("font file %s\n", path);
2580 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2582 HeapFree(GetProcessHeap(), 0, path);
2585 static void load_mac_fonts(void)
2587 CFStringRef removeDupesKey;
2588 CFBooleanRef removeDupesValue;
2589 CFDictionaryRef options;
2590 CTFontCollectionRef col;
2591 CFArrayRef descs;
2592 CFMutableSetRef paths;
2593 CFIndex i;
2595 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2596 removeDupesValue = kCFBooleanTrue;
2597 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2598 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2599 col = CTFontCollectionCreateFromAvailableFonts(options);
2600 if (options) CFRelease(options);
2601 if (!col)
2603 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2604 return;
2607 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2608 CFRelease(col);
2609 if (!descs)
2611 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2612 return;
2615 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2616 if (!paths)
2618 WARN("CFSetCreateMutable failed\n");
2619 CFRelease(descs);
2620 return;
2623 for (i = 0; i < CFArrayGetCount(descs); i++)
2625 CTFontDescriptorRef desc;
2626 CTFontRef font;
2627 ATSFontRef atsFont;
2628 OSStatus status;
2629 FSRef fsref;
2630 CFURLRef url;
2631 CFStringRef ext;
2632 CFStringRef path;
2634 desc = CFArrayGetValueAtIndex(descs, i);
2636 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2637 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2638 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2639 if (!font) continue;
2641 atsFont = CTFontGetPlatformFont(font, NULL);
2642 if (!atsFont)
2644 CFRelease(font);
2645 continue;
2648 status = ATSFontGetFileReference(atsFont, &fsref);
2649 CFRelease(font);
2650 if (status != noErr) continue;
2652 url = CFURLCreateFromFSRef(NULL, &fsref);
2653 if (!url) continue;
2655 ext = CFURLCopyPathExtension(url);
2656 if (ext)
2658 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2659 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2660 CFRelease(ext);
2661 if (skip)
2663 CFRelease(url);
2664 continue;
2668 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2669 CFRelease(url);
2670 if (!path) continue;
2672 CFSetAddValue(paths, path);
2673 CFRelease(path);
2676 CFRelease(descs);
2678 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2679 CFRelease(paths);
2682 #endif
2684 static char *get_data_dir_path( LPCWSTR file )
2686 char *unix_name = NULL;
2687 const char *data_dir = wine_get_data_dir();
2689 if (!data_dir) data_dir = wine_get_build_dir();
2691 if (data_dir)
2693 INT len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2695 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2696 strcpy(unix_name, data_dir);
2697 strcat(unix_name, "/fonts/");
2699 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2701 return unix_name;
2704 static BOOL load_font_from_data_dir(LPCWSTR file)
2706 BOOL ret = FALSE;
2707 char *unix_name = get_data_dir_path( file );
2709 if (unix_name)
2711 EnterCriticalSection( &freetype_cs );
2712 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
2713 LeaveCriticalSection( &freetype_cs );
2714 HeapFree(GetProcessHeap(), 0, unix_name);
2716 return ret;
2719 static char *get_winfonts_dir_path(LPCWSTR file)
2721 static const WCHAR slashW[] = {'\\','\0'};
2722 WCHAR windowsdir[MAX_PATH];
2724 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2725 strcatW(windowsdir, fontsW);
2726 strcatW(windowsdir, slashW);
2727 strcatW(windowsdir, file);
2728 return wine_get_unix_file_name( windowsdir );
2731 static void load_system_fonts(void)
2733 HKEY hkey;
2734 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2735 const WCHAR * const *value;
2736 DWORD dlen, type;
2737 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2738 char *unixname;
2740 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2741 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2742 strcatW(windowsdir, fontsW);
2743 for(value = SystemFontValues; *value; value++) {
2744 dlen = sizeof(data);
2745 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2746 type == REG_SZ) {
2747 BOOL added = FALSE;
2749 sprintfW(pathW, fmtW, windowsdir, data);
2750 if((unixname = wine_get_unix_file_name(pathW))) {
2751 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
2752 HeapFree(GetProcessHeap(), 0, unixname);
2754 if (!added)
2755 load_font_from_data_dir(data);
2758 RegCloseKey(hkey);
2762 /*************************************************************
2764 * This adds registry entries for any externally loaded fonts
2765 * (fonts from fontconfig or FontDirs). It also deletes entries
2766 * of no longer existing fonts.
2769 static void update_reg_entries(void)
2771 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2772 LPWSTR valueW;
2773 DWORD len;
2774 Family *family;
2775 Face *face;
2776 WCHAR *file, *path;
2777 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2779 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2780 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2781 ERR("Can't create Windows font reg key\n");
2782 goto end;
2785 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2786 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2787 ERR("Can't create Windows font reg key\n");
2788 goto end;
2791 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2792 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2793 ERR("Can't create external font reg key\n");
2794 goto end;
2797 /* enumerate the fonts and add external ones to the two keys */
2799 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2800 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2801 char *buffer;
2802 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
2804 if(face->FullName)
2806 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2807 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2808 strcpyW(valueW, face->FullName);
2810 else
2812 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2813 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2814 strcpyW(valueW, family->FamilyName);
2817 buffer = strWtoA( CP_UNIXCP, face->file );
2818 path = wine_get_dos_file_name( buffer );
2819 HeapFree( GetProcessHeap(), 0, buffer );
2821 if (path)
2822 file = path;
2823 else if ((file = strrchrW(face->file, '/')))
2824 file++;
2825 else
2826 file = face->file;
2828 len = strlenW(file) + 1;
2829 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2830 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2831 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2833 HeapFree(GetProcessHeap(), 0, path);
2834 HeapFree(GetProcessHeap(), 0, valueW);
2837 end:
2838 if(external_key) RegCloseKey(external_key);
2839 if(win9x_key) RegCloseKey(win9x_key);
2840 if(winnt_key) RegCloseKey(winnt_key);
2841 return;
2844 static void delete_external_font_keys(void)
2846 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2847 DWORD dlen, vlen, datalen, valuelen, i, type;
2848 LPWSTR valueW;
2849 LPVOID data;
2851 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2852 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2853 ERR("Can't create Windows font reg key\n");
2854 goto end;
2857 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2858 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2859 ERR("Can't create Windows font reg key\n");
2860 goto end;
2863 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2864 ERR("Can't create external font reg key\n");
2865 goto end;
2868 /* Delete all external fonts added last time */
2870 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2871 &valuelen, &datalen, NULL, NULL);
2872 valuelen++; /* returned value doesn't include room for '\0' */
2873 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2874 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2876 dlen = datalen * sizeof(WCHAR);
2877 vlen = valuelen;
2878 i = 0;
2879 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2880 &dlen) == ERROR_SUCCESS) {
2882 RegDeleteValueW(winnt_key, valueW);
2883 RegDeleteValueW(win9x_key, valueW);
2884 /* reset dlen and vlen */
2885 dlen = datalen;
2886 vlen = valuelen;
2888 HeapFree(GetProcessHeap(), 0, data);
2889 HeapFree(GetProcessHeap(), 0, valueW);
2891 /* Delete the old external fonts key */
2892 RegCloseKey(external_key);
2893 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2895 end:
2896 if(win9x_key) RegCloseKey(win9x_key);
2897 if(winnt_key) RegCloseKey(winnt_key);
2900 /*************************************************************
2901 * WineEngAddFontResourceEx
2904 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2906 INT ret = 0;
2908 GDI_CheckNotLock();
2910 if (ft_handle) /* do it only if we have freetype up and running */
2912 char *unixname;
2914 EnterCriticalSection( &freetype_cs );
2916 if((unixname = wine_get_unix_file_name(file)))
2918 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
2920 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2921 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2922 HeapFree(GetProcessHeap(), 0, unixname);
2924 if (!ret && !strchrW(file, '\\')) {
2925 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2926 if ((unixname = get_winfonts_dir_path( file )))
2928 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
2929 HeapFree(GetProcessHeap(), 0, unixname);
2931 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
2932 if (!ret && (unixname = get_data_dir_path( file )))
2934 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
2935 HeapFree(GetProcessHeap(), 0, unixname);
2939 LeaveCriticalSection( &freetype_cs );
2941 return ret;
2944 /*************************************************************
2945 * WineEngAddFontMemResourceEx
2948 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2950 GDI_CheckNotLock();
2952 if (ft_handle) /* do it only if we have freetype up and running */
2954 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2956 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2957 memcpy(pFontCopy, pbFont, cbFont);
2959 EnterCriticalSection( &freetype_cs );
2960 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
2961 LeaveCriticalSection( &freetype_cs );
2963 if (*pcFonts == 0)
2965 TRACE("AddFontToList failed\n");
2966 HeapFree(GetProcessHeap(), 0, pFontCopy);
2967 return 0;
2969 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2970 * For now return something unique but quite random
2972 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2973 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2976 *pcFonts = 0;
2977 return 0;
2980 /*************************************************************
2981 * WineEngRemoveFontResourceEx
2984 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2986 INT ret = 0;
2988 GDI_CheckNotLock();
2990 if (ft_handle) /* do it only if we have freetype up and running */
2992 char *unixname;
2994 EnterCriticalSection( &freetype_cs );
2996 if ((unixname = wine_get_unix_file_name(file)))
2998 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3000 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3001 ret = remove_font_resource( unixname, addfont_flags );
3002 HeapFree(GetProcessHeap(), 0, unixname);
3004 if (!ret && !strchrW(file, '\\'))
3006 if ((unixname = get_winfonts_dir_path( file )))
3008 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3009 HeapFree(GetProcessHeap(), 0, unixname);
3011 if (!ret && (unixname = get_data_dir_path( file )))
3013 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3014 HeapFree(GetProcessHeap(), 0, unixname);
3018 LeaveCriticalSection( &freetype_cs );
3020 return ret;
3023 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
3025 WCHAR *fullname;
3026 char *unix_name;
3027 int file_len;
3029 if (!font_file) return NULL;
3031 file_len = strlenW( font_file );
3033 if (font_path && font_path[0])
3035 int path_len = strlenW( font_path );
3036 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
3037 if (!fullname) return NULL;
3038 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
3039 fullname[path_len] = '\\';
3040 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
3042 else
3044 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
3045 if (!len) return NULL;
3046 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3047 if (!fullname) return NULL;
3048 GetFullPathNameW( font_file, len, fullname, NULL );
3051 unix_name = wine_get_unix_file_name( fullname );
3052 HeapFree( GetProcessHeap(), 0, fullname );
3053 return unix_name;
3056 #include <pshpack1.h>
3057 struct fontdir
3059 WORD num_of_resources;
3060 WORD res_id;
3061 WORD dfVersion;
3062 DWORD dfSize;
3063 CHAR dfCopyright[60];
3064 WORD dfType;
3065 WORD dfPoints;
3066 WORD dfVertRes;
3067 WORD dfHorizRes;
3068 WORD dfAscent;
3069 WORD dfInternalLeading;
3070 WORD dfExternalLeading;
3071 BYTE dfItalic;
3072 BYTE dfUnderline;
3073 BYTE dfStrikeOut;
3074 WORD dfWeight;
3075 BYTE dfCharSet;
3076 WORD dfPixWidth;
3077 WORD dfPixHeight;
3078 BYTE dfPitchAndFamily;
3079 WORD dfAvgWidth;
3080 WORD dfMaxWidth;
3081 BYTE dfFirstChar;
3082 BYTE dfLastChar;
3083 BYTE dfDefaultChar;
3084 BYTE dfBreakChar;
3085 WORD dfWidthBytes;
3086 DWORD dfDevice;
3087 DWORD dfFace;
3088 DWORD dfReserved;
3089 CHAR szFaceName[LF_FACESIZE];
3092 #include <poppack.h>
3094 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
3095 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
3097 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
3099 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3100 Face *face;
3101 WCHAR *name, *english_name;
3102 ENUMLOGFONTEXW elf;
3103 NEWTEXTMETRICEXW ntm;
3104 DWORD type;
3106 if (!ft_face) return FALSE;
3107 face = create_face( ft_face, 0, unix_name, NULL, 0, 0 );
3108 get_family_names( ft_face, &name, &english_name, FALSE );
3109 pFT_Done_Face( ft_face );
3111 GetEnumStructs( face, name, &elf, &ntm, &type );
3112 release_face( face );
3113 HeapFree( GetProcessHeap(), 0, name );
3114 HeapFree( GetProcessHeap(), 0, english_name );
3116 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3118 memset( fd, 0, sizeof(*fd) );
3120 fd->num_of_resources = 1;
3121 fd->res_id = 0;
3122 fd->dfVersion = 0x200;
3123 fd->dfSize = sizeof(*fd);
3124 strcpy( fd->dfCopyright, "Wine fontdir" );
3125 fd->dfType = 0x4003; /* 0x0080 set if private */
3126 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3127 fd->dfVertRes = 72;
3128 fd->dfHorizRes = 72;
3129 fd->dfAscent = ntm.ntmTm.tmAscent;
3130 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3131 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3132 fd->dfItalic = ntm.ntmTm.tmItalic;
3133 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3134 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3135 fd->dfWeight = ntm.ntmTm.tmWeight;
3136 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3137 fd->dfPixWidth = 0;
3138 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3139 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3140 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3141 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3142 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3143 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3144 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3145 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3146 fd->dfWidthBytes = 0;
3147 fd->dfDevice = 0;
3148 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3149 fd->dfReserved = 0;
3150 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3152 return TRUE;
3155 #define NE_FFLAGS_LIBMODULE 0x8000
3156 #define NE_OSFLAGS_WINDOWS 0x02
3158 static const char dos_string[0x40] = "This is a TrueType resource file";
3159 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3161 #include <pshpack2.h>
3163 struct ne_typeinfo
3165 WORD type_id;
3166 WORD count;
3167 DWORD res;
3170 struct ne_nameinfo
3172 WORD off;
3173 WORD len;
3174 WORD flags;
3175 WORD id;
3176 DWORD res;
3179 struct rsrc_tab
3181 WORD align;
3182 struct ne_typeinfo fontdir_type;
3183 struct ne_nameinfo fontdir_name;
3184 struct ne_typeinfo scalable_type;
3185 struct ne_nameinfo scalable_name;
3186 WORD end_of_rsrc;
3187 BYTE fontdir_res_name[8];
3190 #include <poppack.h>
3192 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3194 BOOL ret = FALSE;
3195 HANDLE file;
3196 DWORD size, written;
3197 BYTE *ptr, *start;
3198 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3199 char *font_fileA, *last_part, *ext;
3200 IMAGE_DOS_HEADER dos;
3201 IMAGE_OS2_HEADER ne =
3203 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3204 0, 0, 0, 0, 0, 0,
3205 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3206 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3208 struct rsrc_tab rsrc_tab =
3211 { 0x8007, 1, 0 },
3212 { 0, 0, 0x0c50, 0x2c, 0 },
3213 { 0x80cc, 1, 0 },
3214 { 0, 0, 0x0c50, 0x8001, 0 },
3216 { 7,'F','O','N','T','D','I','R'}
3219 memset( &dos, 0, sizeof(dos) );
3220 dos.e_magic = IMAGE_DOS_SIGNATURE;
3221 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3223 /* import name is last part\0, resident name is last part without extension
3224 non-resident name is "FONTRES:" + lfFaceName */
3226 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3227 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3228 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3230 last_part = strrchr( font_fileA, '\\' );
3231 if (last_part) last_part++;
3232 else last_part = font_fileA;
3233 import_name_len = strlen( last_part ) + 1;
3235 ext = strchr( last_part, '.' );
3236 if (ext) res_name_len = ext - last_part;
3237 else res_name_len = import_name_len - 1;
3239 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3241 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3242 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3243 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3244 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3245 ne.ne_cbenttab = 2;
3246 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3248 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3249 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3250 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3251 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3253 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3254 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3256 if (!ptr)
3258 HeapFree( GetProcessHeap(), 0, font_fileA );
3259 return FALSE;
3262 memcpy( ptr, &dos, sizeof(dos) );
3263 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3264 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3266 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3267 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3269 ptr = start + dos.e_lfanew + ne.ne_restab;
3270 *ptr++ = res_name_len;
3271 memcpy( ptr, last_part, res_name_len );
3273 ptr = start + dos.e_lfanew + ne.ne_imptab;
3274 *ptr++ = import_name_len;
3275 memcpy( ptr, last_part, import_name_len );
3277 ptr = start + ne.ne_nrestab;
3278 *ptr++ = non_res_name_len;
3279 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3280 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3282 ptr = start + (rsrc_tab.scalable_name.off << 4);
3283 memcpy( ptr, font_fileA, font_file_len );
3285 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3286 memcpy( ptr, fontdir, fontdir->dfSize );
3288 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3289 if (file != INVALID_HANDLE_VALUE)
3291 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3292 ret = TRUE;
3293 CloseHandle( file );
3296 HeapFree( GetProcessHeap(), 0, start );
3297 HeapFree( GetProcessHeap(), 0, font_fileA );
3299 return ret;
3302 /*************************************************************
3303 * WineEngCreateScalableFontResource
3306 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3307 LPCWSTR font_file, LPCWSTR font_path )
3309 char *unix_name = get_ttf_file_name( font_file, font_path );
3310 struct fontdir fontdir;
3311 BOOL ret = FALSE;
3313 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3314 SetLastError( ERROR_INVALID_PARAMETER );
3315 else
3317 if (hidden) fontdir.dfType |= 0x80;
3318 ret = create_fot( resource, font_file, &fontdir );
3321 HeapFree( GetProcessHeap(), 0, unix_name );
3322 return ret;
3325 static const struct nls_update_font_list
3327 UINT ansi_cp, oem_cp;
3328 const char *oem, *fixed, *system;
3329 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3330 /* these are for font substitutes */
3331 const char *shelldlg, *tmsrmn;
3332 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3333 *helv_0, *tmsrmn_0;
3334 const struct subst
3336 const char *from, *to;
3337 } arial_0, courier_new_0, times_new_roman_0;
3338 } nls_update_font_list[] =
3340 /* Latin 1 (United States) */
3341 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3342 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3343 "Tahoma","Times New Roman",
3344 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3345 { 0 }, { 0 }, { 0 }
3347 /* Latin 1 (Multilingual) */
3348 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3349 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3350 "Tahoma","Times New Roman", /* FIXME unverified */
3351 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3352 { 0 }, { 0 }, { 0 }
3354 /* Eastern Europe */
3355 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3356 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3357 "Tahoma","Times New Roman", /* FIXME unverified */
3358 "Fixedsys,238", "System,238",
3359 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3360 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3361 { "Arial CE,0", "Arial,238" },
3362 { "Courier New CE,0", "Courier New,238" },
3363 { "Times New Roman CE,0", "Times New Roman,238" }
3365 /* Cyrillic */
3366 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3367 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3368 "Tahoma","Times New Roman", /* FIXME unverified */
3369 "Fixedsys,204", "System,204",
3370 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3371 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3372 { "Arial Cyr,0", "Arial,204" },
3373 { "Courier New Cyr,0", "Courier New,204" },
3374 { "Times New Roman Cyr,0", "Times New Roman,204" }
3376 /* Greek */
3377 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3378 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3379 "Tahoma","Times New Roman", /* FIXME unverified */
3380 "Fixedsys,161", "System,161",
3381 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3382 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3383 { "Arial Greek,0", "Arial,161" },
3384 { "Courier New Greek,0", "Courier New,161" },
3385 { "Times New Roman Greek,0", "Times New Roman,161" }
3387 /* Turkish */
3388 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3389 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3390 "Tahoma","Times New Roman", /* FIXME unverified */
3391 "Fixedsys,162", "System,162",
3392 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3393 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3394 { "Arial Tur,0", "Arial,162" },
3395 { "Courier New Tur,0", "Courier New,162" },
3396 { "Times New Roman Tur,0", "Times New Roman,162" }
3398 /* Hebrew */
3399 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3400 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3401 "Tahoma","Times New Roman", /* FIXME unverified */
3402 "Fixedsys,177", "System,177",
3403 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3404 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3405 { 0 }, { 0 }, { 0 }
3407 /* Arabic */
3408 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3409 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3410 "Tahoma","Times New Roman", /* FIXME unverified */
3411 "Fixedsys,178", "System,178",
3412 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3413 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3414 { 0 }, { 0 }, { 0 }
3416 /* Baltic */
3417 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3418 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3419 "Tahoma","Times New Roman", /* FIXME unverified */
3420 "Fixedsys,186", "System,186",
3421 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3422 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3423 { "Arial Baltic,0", "Arial,186" },
3424 { "Courier New Baltic,0", "Courier New,186" },
3425 { "Times New Roman Baltic,0", "Times New Roman,186" }
3427 /* Vietnamese */
3428 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3429 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3430 "Tahoma","Times New Roman", /* FIXME unverified */
3431 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3432 { 0 }, { 0 }, { 0 }
3434 /* Thai */
3435 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3436 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3437 "Tahoma","Times New Roman", /* FIXME unverified */
3438 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3439 { 0 }, { 0 }, { 0 }
3441 /* Japanese */
3442 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3443 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3444 "MS UI Gothic","MS Serif",
3445 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3446 { 0 }, { 0 }, { 0 }
3448 /* Chinese Simplified */
3449 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3450 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3451 "SimSun", "NSimSun",
3452 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3453 { 0 }, { 0 }, { 0 }
3455 /* Korean */
3456 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3457 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3458 "Gulim", "Batang",
3459 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3460 { 0 }, { 0 }, { 0 }
3462 /* Chinese Traditional */
3463 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3464 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3465 "PMingLiU", "MingLiU",
3466 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3467 { 0 }, { 0 }, { 0 }
3471 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3473 return ( ansi_cp == 932 /* CP932 for Japanese */
3474 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3475 || ansi_cp == 949 /* CP949 for Korean */
3476 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3479 static inline HKEY create_fonts_NT_registry_key(void)
3481 HKEY hkey = 0;
3483 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3484 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3485 return hkey;
3488 static inline HKEY create_fonts_9x_registry_key(void)
3490 HKEY hkey = 0;
3492 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3493 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3494 return hkey;
3497 static inline HKEY create_config_fonts_registry_key(void)
3499 HKEY hkey = 0;
3501 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3502 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3503 return hkey;
3506 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3508 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3510 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3511 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3512 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3513 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3516 static void set_value_key(HKEY hkey, const char *name, const char *value)
3518 if (value)
3519 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3520 else if (name)
3521 RegDeleteValueA(hkey, name);
3524 static void update_font_association_info(UINT current_ansi_codepage)
3526 static const char *font_assoc_reg_key = "System\\CurrentControlSet\\Control\\FontAssoc";
3527 static const char *assoc_charset_subkey = "Associated Charset";
3529 if (is_dbcs_ansi_cp(current_ansi_codepage))
3531 HKEY hkey;
3532 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, font_assoc_reg_key, &hkey) == ERROR_SUCCESS)
3534 HKEY hsubkey;
3535 if (RegCreateKeyA(hkey, assoc_charset_subkey, &hsubkey) == ERROR_SUCCESS)
3537 switch (current_ansi_codepage)
3539 case 932:
3540 set_value_key(hsubkey, "ANSI(00)", "NO");
3541 set_value_key(hsubkey, "OEM(FF)", "NO");
3542 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3543 break;
3544 case 936:
3545 case 949:
3546 case 950:
3547 set_value_key(hsubkey, "ANSI(00)", "YES");
3548 set_value_key(hsubkey, "OEM(FF)", "YES");
3549 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3550 break;
3552 RegCloseKey(hsubkey);
3555 /* TODO: Associated DefaultFonts */
3557 RegCloseKey(hkey);
3560 else
3561 RegDeleteTreeA(HKEY_LOCAL_MACHINE, font_assoc_reg_key);
3564 static void update_font_info(void)
3566 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3567 char buf[40], cpbuf[40];
3568 DWORD len, type;
3569 HKEY hkey = 0;
3570 UINT i, ansi_cp = 0, oem_cp = 0;
3571 DWORD screen_dpi = 96, font_dpi = 0;
3572 BOOL done = FALSE;
3574 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3575 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3576 &hkey) == ERROR_SUCCESS)
3578 reg_load_dword(hkey, logpixels, &screen_dpi);
3579 RegCloseKey(hkey);
3582 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3583 return;
3585 reg_load_dword(hkey, logpixels, &font_dpi);
3587 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3588 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3589 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3590 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3591 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3593 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3594 if (is_dbcs_ansi_cp(ansi_cp))
3595 use_default_fallback = TRUE;
3597 buf[0] = 0;
3598 len = sizeof(buf);
3599 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3601 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3603 RegCloseKey(hkey);
3604 return;
3606 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3607 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3609 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3610 ansi_cp, oem_cp, screen_dpi);
3612 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3613 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3614 RegCloseKey(hkey);
3616 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3618 HKEY hkey;
3620 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3621 nls_update_font_list[i].oem_cp == oem_cp)
3623 hkey = create_config_fonts_registry_key();
3624 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3625 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3626 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3627 RegCloseKey(hkey);
3629 hkey = create_fonts_NT_registry_key();
3630 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3631 RegCloseKey(hkey);
3633 hkey = create_fonts_9x_registry_key();
3634 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3635 RegCloseKey(hkey);
3637 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3639 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3640 strlen(nls_update_font_list[i].shelldlg)+1);
3641 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3642 strlen(nls_update_font_list[i].tmsrmn)+1);
3644 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3645 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3646 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3647 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3648 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3649 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3650 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3651 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3653 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3654 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3655 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3657 RegCloseKey(hkey);
3659 done = TRUE;
3661 else
3663 /* Delete the FontSubstitutes from other locales */
3664 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3666 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3667 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3668 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3669 RegCloseKey(hkey);
3673 if (!done)
3674 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3676 /* update locale dependent font association info in registry.
3677 update only when codepages changed, not logpixels. */
3678 if (strcmp(buf, cpbuf) != 0)
3679 update_font_association_info(ansi_cp);
3682 static BOOL init_freetype(void)
3684 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3685 if(!ft_handle) {
3686 WINE_MESSAGE(
3687 "Wine cannot find the FreeType font library. To enable Wine to\n"
3688 "use TrueType fonts please install a version of FreeType greater than\n"
3689 "or equal to 2.0.5.\n"
3690 "http://www.freetype.org\n");
3691 return FALSE;
3694 #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;}
3696 LOAD_FUNCPTR(FT_Done_Face)
3697 LOAD_FUNCPTR(FT_Get_Char_Index)
3698 LOAD_FUNCPTR(FT_Get_First_Char)
3699 LOAD_FUNCPTR(FT_Get_Module)
3700 LOAD_FUNCPTR(FT_Get_Next_Char)
3701 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3702 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3703 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3704 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3705 LOAD_FUNCPTR(FT_Init_FreeType)
3706 LOAD_FUNCPTR(FT_Library_Version)
3707 LOAD_FUNCPTR(FT_Load_Glyph)
3708 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3709 LOAD_FUNCPTR(FT_Matrix_Multiply)
3710 #ifndef FT_MULFIX_INLINED
3711 LOAD_FUNCPTR(FT_MulFix)
3712 #endif
3713 LOAD_FUNCPTR(FT_New_Face)
3714 LOAD_FUNCPTR(FT_New_Memory_Face)
3715 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3716 LOAD_FUNCPTR(FT_Outline_Transform)
3717 LOAD_FUNCPTR(FT_Outline_Translate)
3718 LOAD_FUNCPTR(FT_Render_Glyph)
3719 LOAD_FUNCPTR(FT_Select_Charmap)
3720 LOAD_FUNCPTR(FT_Set_Charmap)
3721 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3722 LOAD_FUNCPTR(FT_Vector_Transform)
3723 LOAD_FUNCPTR(FT_Vector_Unit)
3724 #undef LOAD_FUNCPTR
3725 /* Don't warn if these ones are missing */
3726 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3727 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3728 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3729 #endif
3731 if(pFT_Init_FreeType(&library) != 0) {
3732 ERR("Can't init FreeType library\n");
3733 wine_dlclose(ft_handle, NULL, 0);
3734 ft_handle = NULL;
3735 return FALSE;
3737 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3739 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3740 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3741 ((FT_Version.minor << 8) & 0x00ff00) |
3742 ((FT_Version.patch ) & 0x0000ff);
3744 font_driver = &freetype_funcs;
3745 return TRUE;
3747 sym_not_found:
3748 WINE_MESSAGE(
3749 "Wine cannot find certain functions that it needs inside the FreeType\n"
3750 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3751 "FreeType to at least version 2.1.4.\n"
3752 "http://www.freetype.org\n");
3753 wine_dlclose(ft_handle, NULL, 0);
3754 ft_handle = NULL;
3755 return FALSE;
3758 static void init_font_list(void)
3760 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3761 static const WCHAR pathW[] = {'P','a','t','h',0};
3762 HKEY hkey;
3763 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3764 WCHAR windowsdir[MAX_PATH];
3765 char *unixname;
3766 const char *data_dir;
3768 delete_external_font_keys();
3770 /* load the system bitmap fonts */
3771 load_system_fonts();
3773 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3774 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3775 strcatW(windowsdir, fontsW);
3776 if((unixname = wine_get_unix_file_name(windowsdir)))
3778 ReadFontDir(unixname, FALSE);
3779 HeapFree(GetProcessHeap(), 0, unixname);
3782 /* load the system truetype fonts */
3783 data_dir = wine_get_data_dir();
3784 if (!data_dir) data_dir = wine_get_build_dir();
3785 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3787 strcpy(unixname, data_dir);
3788 strcat(unixname, "/fonts/");
3789 ReadFontDir(unixname, TRUE);
3790 HeapFree(GetProcessHeap(), 0, unixname);
3793 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3794 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3795 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3796 will skip these. */
3797 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3798 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3799 &hkey) == ERROR_SUCCESS)
3801 LPWSTR data, valueW;
3802 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3803 &valuelen, &datalen, NULL, NULL);
3805 valuelen++; /* returned value doesn't include room for '\0' */
3806 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3807 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3808 if (valueW && data)
3810 dlen = datalen * sizeof(WCHAR);
3811 vlen = valuelen;
3812 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3813 &dlen) == ERROR_SUCCESS)
3815 if(data[0] && (data[1] == ':'))
3817 if((unixname = wine_get_unix_file_name(data)))
3819 AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3820 HeapFree(GetProcessHeap(), 0, unixname);
3823 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3825 WCHAR pathW[MAX_PATH];
3826 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3827 BOOL added = FALSE;
3829 sprintfW(pathW, fmtW, windowsdir, data);
3830 if((unixname = wine_get_unix_file_name(pathW)))
3832 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3833 HeapFree(GetProcessHeap(), 0, unixname);
3835 if (!added)
3836 load_font_from_data_dir(data);
3838 /* reset dlen and vlen */
3839 dlen = datalen;
3840 vlen = valuelen;
3843 HeapFree(GetProcessHeap(), 0, data);
3844 HeapFree(GetProcessHeap(), 0, valueW);
3845 RegCloseKey(hkey);
3848 #ifdef SONAME_LIBFONTCONFIG
3849 load_fontconfig_fonts();
3850 #elif defined(HAVE_CARBON_CARBON_H)
3851 load_mac_fonts();
3852 #endif
3854 /* then look in any directories that we've specified in the config file */
3855 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3856 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3858 DWORD len;
3859 LPWSTR valueW;
3860 LPSTR valueA, ptr;
3862 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3864 len += sizeof(WCHAR);
3865 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3866 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3868 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3869 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3870 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3871 TRACE( "got font path %s\n", debugstr_a(valueA) );
3872 ptr = valueA;
3873 while (ptr)
3875 const char* home;
3876 LPSTR next = strchr( ptr, ':' );
3877 if (next) *next++ = 0;
3878 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3879 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3881 strcpy( unixname, home );
3882 strcat( unixname, ptr + 1 );
3883 ReadFontDir( unixname, TRUE );
3884 HeapFree( GetProcessHeap(), 0, unixname );
3886 else
3887 ReadFontDir( ptr, TRUE );
3888 ptr = next;
3890 HeapFree( GetProcessHeap(), 0, valueA );
3892 HeapFree( GetProcessHeap(), 0, valueW );
3894 RegCloseKey(hkey);
3898 static BOOL move_to_front(const WCHAR *name)
3900 Family *family, *cursor2;
3901 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3903 if(!strcmpiW(family->FamilyName, name))
3905 list_remove(&family->entry);
3906 list_add_head(&font_list, &family->entry);
3907 return TRUE;
3910 return FALSE;
3913 static BOOL set_default(const WCHAR **name_list)
3915 while (*name_list)
3917 if (move_to_front(*name_list)) return TRUE;
3918 name_list++;
3921 return FALSE;
3924 static void reorder_font_list(void)
3926 set_default( default_serif_list );
3927 set_default( default_fixed_list );
3928 set_default( default_sans_list );
3931 /*************************************************************
3932 * WineEngInit
3934 * Initialize FreeType library and create a list of available faces
3936 BOOL WineEngInit(void)
3938 DWORD disposition;
3939 HANDLE font_mutex;
3941 /* update locale dependent font info in registry */
3942 update_font_info();
3944 if(!init_freetype()) return FALSE;
3946 #ifdef SONAME_LIBFONTCONFIG
3947 init_fontconfig();
3948 #endif
3950 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3952 ERR("Failed to create font mutex\n");
3953 return FALSE;
3955 WaitForSingleObject(font_mutex, INFINITE);
3957 create_font_cache_key(&hkey_font_cache, &disposition);
3959 if(disposition == REG_CREATED_NEW_KEY)
3960 init_font_list();
3961 else
3962 load_font_list_from_cache(hkey_font_cache);
3964 reorder_font_list();
3966 DumpFontList();
3967 LoadSubstList();
3968 DumpSubstList();
3969 LoadReplaceList();
3971 if(disposition == REG_CREATED_NEW_KEY)
3972 update_reg_entries();
3974 init_system_links();
3976 ReleaseMutex(font_mutex);
3977 return TRUE;
3981 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3983 TT_OS2 *pOS2;
3984 TT_HoriHeader *pHori;
3986 LONG ppem;
3987 const LONG MAX_PPEM = (1 << 16) - 1;
3989 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3990 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3992 if(height == 0) height = 16;
3994 /* Calc. height of EM square:
3996 * For +ve lfHeight we have
3997 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3998 * Re-arranging gives:
3999 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4001 * For -ve lfHeight we have
4002 * |lfHeight| = ppem
4003 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4004 * with il = winAscent + winDescent - units_per_em]
4008 if(height > 0) {
4009 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
4010 ppem = MulDiv(ft_face->units_per_EM, height,
4011 pHori->Ascender - pHori->Descender);
4012 else
4013 ppem = MulDiv(ft_face->units_per_EM, height,
4014 pOS2->usWinAscent + pOS2->usWinDescent);
4015 if(ppem > MAX_PPEM) {
4016 WARN("Ignoring too large height %d, ppem %d\n", height, ppem);
4017 ppem = 1;
4020 else if(height >= -MAX_PPEM)
4021 ppem = -height;
4022 else {
4023 WARN("Ignoring too large height %d\n", height);
4024 ppem = 1;
4027 return ppem;
4030 static struct font_mapping *map_font_file( const char *name )
4032 struct font_mapping *mapping;
4033 struct stat st;
4034 int fd;
4036 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
4037 if (fstat( fd, &st ) == -1) goto error;
4039 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
4041 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
4043 mapping->refcount++;
4044 close( fd );
4045 return mapping;
4048 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
4049 goto error;
4051 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
4052 close( fd );
4054 if (mapping->data == MAP_FAILED)
4056 HeapFree( GetProcessHeap(), 0, mapping );
4057 return NULL;
4059 mapping->refcount = 1;
4060 mapping->dev = st.st_dev;
4061 mapping->ino = st.st_ino;
4062 mapping->size = st.st_size;
4063 list_add_tail( &mappings_list, &mapping->entry );
4064 return mapping;
4066 error:
4067 close( fd );
4068 return NULL;
4071 static void unmap_font_file( struct font_mapping *mapping )
4073 if (!--mapping->refcount)
4075 list_remove( &mapping->entry );
4076 munmap( mapping->data, mapping->size );
4077 HeapFree( GetProcessHeap(), 0, mapping );
4081 static LONG load_VDMX(GdiFont*, LONG);
4083 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
4085 FT_Error err;
4086 FT_Face ft_face;
4087 void *data_ptr;
4088 DWORD data_size;
4090 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
4092 if (face->file)
4094 char *filename = strWtoA( CP_UNIXCP, face->file );
4095 font->mapping = map_font_file( filename );
4096 HeapFree( GetProcessHeap(), 0, filename );
4097 if (!font->mapping)
4099 WARN("failed to map %s\n", debugstr_w(face->file));
4100 return 0;
4102 data_ptr = font->mapping->data;
4103 data_size = font->mapping->size;
4105 else
4107 data_ptr = face->font_data_ptr;
4108 data_size = face->font_data_size;
4111 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
4112 if(err) {
4113 ERR("FT_New_Face rets %d\n", err);
4114 return 0;
4117 /* set it here, as load_VDMX needs it */
4118 font->ft_face = ft_face;
4120 if(FT_IS_SCALABLE(ft_face)) {
4121 /* load the VDMX table if we have one */
4122 font->ppem = load_VDMX(font, height);
4123 if(font->ppem == 0)
4124 font->ppem = calc_ppem_for_height(ft_face, height);
4125 TRACE("height %d => ppem %d\n", height, font->ppem);
4127 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
4128 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
4129 } else {
4130 font->ppem = height;
4131 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
4132 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
4134 return ft_face;
4138 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
4140 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4141 a single face with the requested charset. The idea is to check if
4142 the selected font supports the current ANSI codepage, if it does
4143 return the corresponding charset, else return the first charset */
4145 CHARSETINFO csi;
4146 int acp = GetACP(), i;
4147 DWORD fs0;
4149 *cp = acp;
4150 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
4152 const SYSTEM_LINKS *font_link;
4154 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4155 return csi.ciCharset;
4157 font_link = find_font_link(family_name);
4158 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4159 return csi.ciCharset;
4162 for(i = 0; i < 32; i++) {
4163 fs0 = 1L << i;
4164 if(face->fs.fsCsb[0] & fs0) {
4165 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4166 *cp = csi.ciACP;
4167 return csi.ciCharset;
4169 else
4170 FIXME("TCI failing on %x\n", fs0);
4174 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4175 face->fs.fsCsb[0], debugstr_w(face->file));
4176 *cp = acp;
4177 return DEFAULT_CHARSET;
4180 static GdiFont *alloc_font(void)
4182 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4183 ret->refcount = 1;
4184 ret->gmsize = 1;
4185 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4186 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4187 ret->potm = NULL;
4188 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4189 ret->total_kern_pairs = (DWORD)-1;
4190 ret->kern_pairs = NULL;
4191 list_init(&ret->child_fonts);
4192 return ret;
4195 static void free_font(GdiFont *font)
4197 CHILD_FONT *child, *child_next;
4198 DWORD i;
4200 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
4202 list_remove(&child->entry);
4203 if(child->font)
4204 free_font(child->font);
4205 release_face( child->face );
4206 HeapFree(GetProcessHeap(), 0, child);
4209 if (font->ft_face) pFT_Done_Face(font->ft_face);
4210 if (font->mapping) unmap_font_file( font->mapping );
4211 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4212 HeapFree(GetProcessHeap(), 0, font->potm);
4213 HeapFree(GetProcessHeap(), 0, font->name);
4214 for (i = 0; i < font->gmsize; i++)
4215 HeapFree(GetProcessHeap(),0,font->gm[i]);
4216 HeapFree(GetProcessHeap(), 0, font->gm);
4217 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4218 HeapFree(GetProcessHeap(), 0, font);
4222 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4224 FT_Face ft_face = font->ft_face;
4225 FT_ULong len;
4226 FT_Error err;
4228 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4230 if(!buf)
4231 len = 0;
4232 else
4233 len = cbData;
4235 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4237 /* make sure value of len is the value freetype says it needs */
4238 if (buf && len)
4240 FT_ULong needed = 0;
4241 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4242 if( !err && needed < len) len = needed;
4244 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4245 if (err)
4247 TRACE("Can't find table %c%c%c%c\n",
4248 /* bytes were reversed */
4249 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4250 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4251 return GDI_ERROR;
4253 return len;
4256 /*************************************************************
4257 * load_VDMX
4259 * load the vdmx entry for the specified height
4262 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4263 ( ( (FT_ULong)_x4 << 24 ) | \
4264 ( (FT_ULong)_x3 << 16 ) | \
4265 ( (FT_ULong)_x2 << 8 ) | \
4266 (FT_ULong)_x1 )
4268 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4270 typedef struct {
4271 BYTE bCharSet;
4272 BYTE xRatio;
4273 BYTE yStartRatio;
4274 BYTE yEndRatio;
4275 } Ratios;
4277 typedef struct {
4278 WORD recs;
4279 BYTE startsz;
4280 BYTE endsz;
4281 } VDMX_group;
4283 static LONG load_VDMX(GdiFont *font, LONG height)
4285 WORD hdr[3], tmp;
4286 VDMX_group group;
4287 BYTE devXRatio, devYRatio;
4288 USHORT numRecs, numRatios;
4289 DWORD result, offset = -1;
4290 LONG ppem = 0;
4291 int i;
4293 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
4295 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4296 return ppem;
4298 /* FIXME: need the real device aspect ratio */
4299 devXRatio = 1;
4300 devYRatio = 1;
4302 numRecs = GET_BE_WORD(hdr[1]);
4303 numRatios = GET_BE_WORD(hdr[2]);
4305 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4306 for(i = 0; i < numRatios; i++) {
4307 Ratios ratio;
4309 offset = (3 * 2) + (i * sizeof(Ratios));
4310 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4311 offset = -1;
4313 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4315 if((ratio.xRatio == 0 &&
4316 ratio.yStartRatio == 0 &&
4317 ratio.yEndRatio == 0) ||
4318 (devXRatio == ratio.xRatio &&
4319 devYRatio >= ratio.yStartRatio &&
4320 devYRatio <= ratio.yEndRatio))
4322 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4323 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4324 offset = GET_BE_WORD(tmp);
4325 break;
4329 if(offset == -1) {
4330 FIXME("No suitable ratio found\n");
4331 return ppem;
4334 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4335 USHORT recs;
4336 BYTE startsz, endsz;
4337 WORD *vTable;
4339 recs = GET_BE_WORD(group.recs);
4340 startsz = group.startsz;
4341 endsz = group.endsz;
4343 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4345 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4346 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4347 if(result == GDI_ERROR) {
4348 FIXME("Failed to retrieve vTable\n");
4349 goto end;
4352 if(height > 0) {
4353 for(i = 0; i < recs; i++) {
4354 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4355 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4356 ppem = GET_BE_WORD(vTable[i * 3]);
4358 if(yMax + -yMin == height) {
4359 font->yMax = yMax;
4360 font->yMin = yMin;
4361 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4362 break;
4364 if(yMax + -yMin > height) {
4365 if(--i < 0) {
4366 ppem = 0;
4367 goto end; /* failed */
4369 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4370 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4371 ppem = GET_BE_WORD(vTable[i * 3]);
4372 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4373 break;
4376 if(!font->yMax) {
4377 ppem = 0;
4378 TRACE("ppem not found for height %d\n", height);
4381 end:
4382 HeapFree(GetProcessHeap(), 0, vTable);
4385 return ppem;
4388 static void dump_gdi_font_list(void)
4390 GdiFont *font;
4392 TRACE("---------- Font Cache ----------\n");
4393 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct tagGdiFont, entry )
4394 TRACE("font=%p ref=%u %s %d\n", font, font->refcount,
4395 debugstr_w(font->font_desc.lf.lfFaceName), font->font_desc.lf.lfHeight);
4398 static void grab_font( GdiFont *font )
4400 if (!font->refcount++)
4402 list_remove( &font->unused_entry );
4403 unused_font_count--;
4407 static void release_font( GdiFont *font )
4409 if (!font) return;
4410 if (!--font->refcount)
4412 TRACE( "font %p\n", font );
4414 /* add it to the unused list */
4415 list_add_head( &unused_gdi_font_list, &font->unused_entry );
4416 if (unused_font_count > UNUSED_CACHE_SIZE)
4418 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct tagGdiFont, unused_entry );
4419 TRACE( "freeing %p\n", font );
4420 list_remove( &font->entry );
4421 list_remove( &font->unused_entry );
4422 free_font( font );
4424 else unused_font_count++;
4426 if (TRACE_ON(font)) dump_gdi_font_list();
4430 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4432 if(font->font_desc.hash != fd->hash) return TRUE;
4433 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4434 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4435 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4436 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4439 static void calc_hash(FONT_DESC *pfd)
4441 DWORD hash = 0, *ptr, two_chars;
4442 WORD *pwc;
4443 unsigned int i;
4445 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4446 hash ^= *ptr;
4447 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4448 hash ^= *ptr;
4449 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4450 two_chars = *ptr;
4451 pwc = (WCHAR *)&two_chars;
4452 if(!*pwc) break;
4453 *pwc = toupperW(*pwc);
4454 pwc++;
4455 *pwc = toupperW(*pwc);
4456 hash ^= two_chars;
4457 if(!*pwc) break;
4459 hash ^= !pfd->can_use_bitmap;
4460 pfd->hash = hash;
4461 return;
4464 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4466 GdiFont *ret;
4467 FONT_DESC fd;
4469 fd.lf = *plf;
4470 fd.matrix = *pmat;
4471 fd.can_use_bitmap = can_use_bitmap;
4472 calc_hash(&fd);
4474 /* try the in-use list */
4475 LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
4477 if(fontcmp(ret, &fd)) continue;
4478 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4479 list_remove( &ret->entry );
4480 list_add_head( &gdi_font_list, &ret->entry );
4481 grab_font( ret );
4482 return ret;
4484 return NULL;
4487 static void add_to_cache(GdiFont *font)
4489 static DWORD cache_num = 1;
4491 font->cache_num = cache_num++;
4492 list_add_head(&gdi_font_list, &font->entry);
4493 TRACE( "font %p\n", font );
4496 /*************************************************************
4497 * create_child_font_list
4499 static BOOL create_child_font_list(GdiFont *font)
4501 BOOL ret = FALSE;
4502 SYSTEM_LINKS *font_link;
4503 CHILD_FONT *font_link_entry, *new_child;
4504 FontSubst *psub;
4505 WCHAR* font_name;
4507 psub = get_font_subst(&font_subst_list, font->name, -1);
4508 font_name = psub ? psub->to.name : font->name;
4509 font_link = find_font_link(font_name);
4510 if (font_link != NULL)
4512 TRACE("found entry in system list\n");
4513 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4515 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4516 new_child->face = font_link_entry->face;
4517 new_child->font = NULL;
4518 new_child->face->refcount++;
4519 list_add_tail(&font->child_fonts, &new_child->entry);
4520 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4522 ret = TRUE;
4525 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4526 * Sans Serif. This is how asian windows get default fallbacks for fonts
4528 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4529 font->charset != OEM_CHARSET &&
4530 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4532 font_link = find_font_link(szDefaultFallbackLink);
4533 if (font_link != NULL)
4535 TRACE("found entry in default fallback list\n");
4536 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4538 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4539 new_child->face = font_link_entry->face;
4540 new_child->font = NULL;
4541 new_child->face->refcount++;
4542 list_add_tail(&font->child_fonts, &new_child->entry);
4543 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4545 ret = TRUE;
4549 return ret;
4552 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4554 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4556 if (pFT_Set_Charmap)
4558 FT_Int i;
4559 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4561 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4563 for (i = 0; i < ft_face->num_charmaps; i++)
4565 if (ft_face->charmaps[i]->encoding == encoding)
4567 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4568 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4570 switch (ft_face->charmaps[i]->platform_id)
4572 default:
4573 cmap_def = ft_face->charmaps[i];
4574 break;
4575 case 0: /* Apple Unicode */
4576 cmap0 = ft_face->charmaps[i];
4577 break;
4578 case 1: /* Macintosh */
4579 cmap1 = ft_face->charmaps[i];
4580 break;
4581 case 2: /* ISO */
4582 cmap2 = ft_face->charmaps[i];
4583 break;
4584 case 3: /* Microsoft */
4585 cmap3 = ft_face->charmaps[i];
4586 break;
4590 if (cmap3) /* prefer Microsoft cmap table */
4591 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4592 else if (cmap1)
4593 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4594 else if (cmap2)
4595 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4596 else if (cmap0)
4597 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4598 else if (cmap_def)
4599 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4601 return ft_err == FT_Err_Ok;
4604 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4608 /*************************************************************
4609 * freetype_CreateDC
4611 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4612 LPCWSTR output, const DEVMODEW *devmode )
4614 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4616 if (!physdev) return FALSE;
4617 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4618 return TRUE;
4622 /*************************************************************
4623 * freetype_DeleteDC
4625 static BOOL freetype_DeleteDC( PHYSDEV dev )
4627 struct freetype_physdev *physdev = get_freetype_dev( dev );
4628 release_font( physdev->font );
4629 HeapFree( GetProcessHeap(), 0, physdev );
4630 return TRUE;
4633 static FT_Encoding pick_charmap( FT_Face face, int charset )
4635 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
4636 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
4637 const FT_Encoding *encs = regular_order;
4639 if (charset == SYMBOL_CHARSET) encs = symbol_order;
4641 while (*encs != 0)
4643 if (select_charmap( face, *encs )) break;
4644 encs++;
4646 return *encs;
4649 #define GASP_GRIDFIT 0x01
4650 #define GASP_DOGRAY 0x02
4651 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4653 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
4655 DWORD size;
4656 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
4657 WORD *alloced = NULL, *ptr = buf;
4658 WORD num_recs, version;
4659 BOOL ret = FALSE;
4661 *flags = 0;
4662 size = get_font_data( font, GASP_TAG, 0, NULL, 0 );
4663 if (size == GDI_ERROR) return FALSE;
4664 if (size < 4 * sizeof(WORD)) return FALSE;
4665 if (size > sizeof(buf))
4667 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
4668 if (!ptr) return FALSE;
4671 get_font_data( font, GASP_TAG, 0, ptr, size );
4673 version = GET_BE_WORD( *ptr++ );
4674 num_recs = GET_BE_WORD( *ptr++ );
4676 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
4678 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
4679 goto done;
4682 while (num_recs--)
4684 *flags = GET_BE_WORD( *(ptr + 1) );
4685 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
4686 ptr += 2;
4688 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
4689 ret = TRUE;
4691 done:
4692 HeapFree( GetProcessHeap(), 0, alloced );
4693 return ret;
4696 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4698 const GSUB_ScriptList *script;
4699 const GSUB_Script *deflt = NULL;
4700 int i;
4701 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4703 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4704 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4706 const GSUB_Script *scr;
4707 int offset;
4709 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4710 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4712 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4713 return scr;
4714 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4715 deflt = scr;
4717 return deflt;
4720 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4722 int i;
4723 int offset;
4724 const GSUB_LangSys *Lang;
4726 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4728 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4730 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4731 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4733 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4734 return Lang;
4736 offset = GET_BE_WORD(script->DefaultLangSys);
4737 if (offset)
4739 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4740 return Lang;
4742 return NULL;
4745 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4747 int i;
4748 const GSUB_FeatureList *feature;
4749 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4751 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4752 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4754 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4755 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4757 const GSUB_Feature *feat;
4758 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4759 return feat;
4762 return NULL;
4765 static const char* get_opentype_script(const GdiFont *font)
4768 * I am not sure if this is the correct way to generate our script tag
4771 switch (font->charset)
4773 case ANSI_CHARSET: return "latn";
4774 case BALTIC_CHARSET: return "latn"; /* ?? */
4775 case CHINESEBIG5_CHARSET: return "hani";
4776 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4777 case GB2312_CHARSET: return "hani";
4778 case GREEK_CHARSET: return "grek";
4779 case HANGUL_CHARSET: return "hang";
4780 case RUSSIAN_CHARSET: return "cyrl";
4781 case SHIFTJIS_CHARSET: return "kana";
4782 case TURKISH_CHARSET: return "latn"; /* ?? */
4783 case VIETNAMESE_CHARSET: return "latn";
4784 case JOHAB_CHARSET: return "latn"; /* ?? */
4785 case ARABIC_CHARSET: return "arab";
4786 case HEBREW_CHARSET: return "hebr";
4787 case THAI_CHARSET: return "thai";
4788 default: return "latn";
4792 static const VOID * get_GSUB_vert_feature(const GdiFont *font)
4794 const GSUB_Header *header;
4795 const GSUB_Script *script;
4796 const GSUB_LangSys *language;
4797 const GSUB_Feature *feature;
4799 if (!font->GSUB_Table)
4800 return NULL;
4802 header = font->GSUB_Table;
4804 script = GSUB_get_script_table(header, get_opentype_script(font));
4805 if (!script)
4807 TRACE("Script not found\n");
4808 return NULL;
4810 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4811 if (!language)
4813 TRACE("Language not found\n");
4814 return NULL;
4816 feature = GSUB_get_feature(header, language, "vrt2");
4817 if (!feature)
4818 feature = GSUB_get_feature(header, language, "vert");
4819 if (!feature)
4821 TRACE("vrt2/vert feature not found\n");
4822 return NULL;
4824 return feature;
4827 /*************************************************************
4828 * freetype_SelectFont
4830 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
4832 struct freetype_physdev *physdev = get_freetype_dev( dev );
4833 GdiFont *ret;
4834 Face *face, *best, *best_bitmap;
4835 Family *family, *last_resort_family;
4836 const struct list *face_list;
4837 INT height, width = 0;
4838 unsigned int score = 0, new_score;
4839 signed int diff = 0, newdiff;
4840 BOOL bd, it, can_use_bitmap, want_vertical;
4841 LOGFONTW lf;
4842 CHARSETINFO csi;
4843 FMAT2 dcmat;
4844 FontSubst *psub = NULL;
4845 DC *dc = get_dc_ptr( dev->hdc );
4846 const SYSTEM_LINKS *font_link;
4848 if (!hfont) /* notification that the font has been changed by another driver */
4850 release_font( physdev->font );
4851 physdev->font = NULL;
4852 release_dc_ptr( dc );
4853 return 0;
4856 GetObjectW( hfont, sizeof(lf), &lf );
4857 lf.lfWidth = abs(lf.lfWidth);
4859 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4861 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4862 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4863 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4864 lf.lfEscapement);
4866 if(dc->GraphicsMode == GM_ADVANCED)
4868 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4869 /* Try to avoid not necessary glyph transformations */
4870 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4872 lf.lfHeight *= fabs(dcmat.eM11);
4873 lf.lfWidth *= fabs(dcmat.eM11);
4874 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
4877 else
4879 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4880 font scaling abilities. */
4881 dcmat.eM11 = dcmat.eM22 = 1.0;
4882 dcmat.eM21 = dcmat.eM12 = 0;
4883 lf.lfOrientation = lf.lfEscapement;
4884 if (dc->vport2WorldValid)
4886 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4887 lf.lfOrientation = -lf.lfOrientation;
4888 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4889 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4893 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4894 dcmat.eM21, dcmat.eM22);
4896 GDI_CheckNotLock();
4897 EnterCriticalSection( &freetype_cs );
4899 /* check the cache first */
4900 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4901 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4902 goto done;
4905 TRACE("not in cache\n");
4906 ret = alloc_font();
4908 ret->font_desc.matrix = dcmat;
4909 ret->font_desc.lf = lf;
4910 ret->font_desc.can_use_bitmap = can_use_bitmap;
4911 calc_hash(&ret->font_desc);
4913 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4914 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4915 original value lfCharSet. Note this is a special case for
4916 Symbol and doesn't happen at least for "Wingdings*" */
4918 if(!strcmpiW(lf.lfFaceName, SymbolW))
4919 lf.lfCharSet = SYMBOL_CHARSET;
4921 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4922 switch(lf.lfCharSet) {
4923 case DEFAULT_CHARSET:
4924 csi.fs.fsCsb[0] = 0;
4925 break;
4926 default:
4927 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4928 csi.fs.fsCsb[0] = 0;
4929 break;
4933 family = NULL;
4934 if(lf.lfFaceName[0] != '\0') {
4935 CHILD_FONT *font_link_entry;
4936 LPWSTR FaceName = lf.lfFaceName;
4938 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4940 if(psub) {
4941 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4942 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4943 if (psub->to.charset != -1)
4944 lf.lfCharSet = psub->to.charset;
4947 /* We want a match on name and charset or just name if
4948 charset was DEFAULT_CHARSET. If the latter then
4949 we fixup the returned charset later in get_nearest_charset
4950 where we'll either use the charset of the current ansi codepage
4951 or if that's unavailable the first charset that the font supports.
4953 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4954 if (!strcmpiW(family->FamilyName, FaceName) ||
4955 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4957 font_link = find_font_link(family->FamilyName);
4958 face_list = get_face_list_from_family(family);
4959 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4960 if (!(face->scalable || can_use_bitmap))
4961 continue;
4962 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4963 goto found;
4964 if (font_link != NULL &&
4965 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4966 goto found;
4967 if (!csi.fs.fsCsb[0])
4968 goto found;
4973 /* Search by full face name. */
4974 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4975 face_list = get_face_list_from_family(family);
4976 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4977 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4978 (face->scalable || can_use_bitmap))
4980 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4981 goto found_face;
4982 font_link = find_font_link(family->FamilyName);
4983 if (font_link != NULL &&
4984 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4985 goto found_face;
4991 * Try check the SystemLink list first for a replacement font.
4992 * We may find good replacements there.
4994 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4996 if(!strcmpiW(font_link->font_name, FaceName) ||
4997 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4999 TRACE("found entry in system list\n");
5000 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5002 const SYSTEM_LINKS *links;
5004 face = font_link_entry->face;
5005 if (!(face->scalable || can_use_bitmap))
5006 continue;
5007 family = face->family;
5008 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5009 goto found;
5010 links = find_font_link(family->FamilyName);
5011 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
5012 goto found;
5018 psub = NULL; /* substitution is no more relevant */
5020 /* If requested charset was DEFAULT_CHARSET then try using charset
5021 corresponding to the current ansi codepage */
5022 if (!csi.fs.fsCsb[0])
5024 INT acp = GetACP();
5025 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
5026 FIXME("TCI failed on codepage %d\n", acp);
5027 csi.fs.fsCsb[0] = 0;
5028 } else
5029 lf.lfCharSet = csi.ciCharset;
5032 want_vertical = (lf.lfFaceName[0] == '@');
5034 /* Face families are in the top 4 bits of lfPitchAndFamily,
5035 so mask with 0xF0 before testing */
5037 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
5038 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
5039 strcpyW(lf.lfFaceName, defFixed);
5040 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
5041 strcpyW(lf.lfFaceName, defSerif);
5042 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
5043 strcpyW(lf.lfFaceName, defSans);
5044 else
5045 strcpyW(lf.lfFaceName, defSans);
5046 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5047 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
5048 font_link = find_font_link(family->FamilyName);
5049 face_list = get_face_list_from_family(family);
5050 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5051 if (!(face->scalable || can_use_bitmap))
5052 continue;
5053 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5054 goto found;
5055 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5056 goto found;
5061 last_resort_family = NULL;
5062 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5063 font_link = find_font_link(family->FamilyName);
5064 face_list = get_face_list_from_family(family);
5065 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5066 if(!(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical &&
5067 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5068 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
5069 if(face->scalable)
5070 goto found;
5071 if(can_use_bitmap && !last_resort_family)
5072 last_resort_family = family;
5077 if(last_resort_family) {
5078 family = last_resort_family;
5079 csi.fs.fsCsb[0] = 0;
5080 goto found;
5083 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5084 face_list = get_face_list_from_family(family);
5085 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5086 if(face->scalable && !(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical) {
5087 csi.fs.fsCsb[0] = 0;
5088 WARN("just using first face for now\n");
5089 goto found;
5091 if(can_use_bitmap && !last_resort_family)
5092 last_resort_family = family;
5095 if(!last_resort_family) {
5096 FIXME("can't find a single appropriate font - bailing\n");
5097 free_font(ret);
5098 ret = NULL;
5099 goto done;
5102 WARN("could only find a bitmap font - this will probably look awful!\n");
5103 family = last_resort_family;
5104 csi.fs.fsCsb[0] = 0;
5106 found:
5107 it = lf.lfItalic ? 1 : 0;
5108 bd = lf.lfWeight > 550 ? 1 : 0;
5110 height = lf.lfHeight;
5112 face = best = best_bitmap = NULL;
5113 font_link = find_font_link(family->FamilyName);
5114 face_list = get_face_list_from_family(family);
5115 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5117 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5118 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
5119 !csi.fs.fsCsb[0])
5121 BOOL italic, bold;
5123 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
5124 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
5125 new_score = (italic ^ it) + (bold ^ bd);
5126 if(!best || new_score <= score)
5128 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5129 italic, bold, it, bd);
5130 score = new_score;
5131 best = face;
5132 if(best->scalable && score == 0) break;
5133 if(!best->scalable)
5135 if(height > 0)
5136 newdiff = height - (signed int)(best->size.height);
5137 else
5138 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
5139 if(!best_bitmap || new_score < score ||
5140 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
5142 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
5143 diff = newdiff;
5144 best_bitmap = best;
5145 if(score == 0 && diff == 0) break;
5151 if(best)
5152 face = best->scalable ? best : best_bitmap;
5153 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
5154 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
5156 found_face:
5157 height = lf.lfHeight;
5159 ret->fs = face->fs;
5161 if(csi.fs.fsCsb[0]) {
5162 ret->charset = lf.lfCharSet;
5163 ret->codepage = csi.ciACP;
5165 else
5166 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
5168 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
5169 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
5171 ret->aveWidth = height ? lf.lfWidth : 0;
5173 if(!face->scalable) {
5174 /* Windows uses integer scaling factors for bitmap fonts */
5175 INT scale, scaled_height;
5176 GdiFont *cachedfont;
5178 /* FIXME: rotation of bitmap fonts is ignored */
5179 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
5180 if (ret->aveWidth)
5181 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
5182 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
5183 dcmat.eM11 = dcmat.eM22 = 1.0;
5184 /* As we changed the matrix, we need to search the cache for the font again,
5185 * otherwise we might explode the cache. */
5186 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5187 TRACE("Found cached font after non-scalable matrix rescale!\n");
5188 free_font( ret );
5189 ret = cachedfont;
5190 goto done;
5192 calc_hash(&ret->font_desc);
5194 if (height != 0) height = diff;
5195 height += face->size.height;
5197 scale = (height + face->size.height - 1) / face->size.height;
5198 scaled_height = scale * face->size.height;
5199 /* Only jump to the next height if the difference <= 25% original height */
5200 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
5201 /* The jump between unscaled and doubled is delayed by 1 */
5202 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
5203 ret->scale_y = scale;
5205 width = face->size.x_ppem >> 6;
5206 height = face->size.y_ppem >> 6;
5208 else
5209 ret->scale_y = 1.0;
5210 TRACE("font scale y: %f\n", ret->scale_y);
5212 ret->ft_face = OpenFontFace(ret, face, width, height);
5214 if (!ret->ft_face)
5216 free_font( ret );
5217 ret = NULL;
5218 goto done;
5221 ret->ntmFlags = face->ntmFlags;
5223 pick_charmap( ret->ft_face, ret->charset );
5225 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
5226 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
5227 ret->underline = lf.lfUnderline ? 0xff : 0;
5228 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
5229 create_child_font_list(ret);
5231 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
5233 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
5234 if (length != GDI_ERROR)
5236 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
5237 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
5238 TRACE("Loaded GSUB table of %i bytes\n",length);
5239 ret->vert_feature = get_GSUB_vert_feature(ret);
5240 if (!ret->vert_feature)
5242 TRACE("Vertical feature not found\n");
5243 HeapFree(GetProcessHeap(), 0, ret->GSUB_Table);
5244 ret->GSUB_Table = NULL;
5248 ret->aa_flags = HIWORD( face->flags );
5250 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
5252 add_to_cache(ret);
5253 done:
5254 if (ret)
5256 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
5258 switch (lf.lfQuality)
5260 case NONANTIALIASED_QUALITY:
5261 case ANTIALIASED_QUALITY:
5262 next->funcs->pSelectFont( dev, hfont, aa_flags );
5263 break;
5264 case CLEARTYPE_QUALITY:
5265 case CLEARTYPE_NATURAL_QUALITY:
5266 default:
5267 if (!*aa_flags) *aa_flags = ret->aa_flags;
5268 next->funcs->pSelectFont( dev, hfont, aa_flags );
5270 /* fixup the antialiasing flags for that font */
5271 switch (*aa_flags)
5273 case WINE_GGO_HRGB_BITMAP:
5274 case WINE_GGO_HBGR_BITMAP:
5275 case WINE_GGO_VRGB_BITMAP:
5276 case WINE_GGO_VBGR_BITMAP:
5277 if (is_subpixel_rendering_enabled()) break;
5278 *aa_flags = GGO_GRAY4_BITMAP;
5279 /* fall through */
5280 case GGO_GRAY2_BITMAP:
5281 case GGO_GRAY4_BITMAP:
5282 case GGO_GRAY8_BITMAP:
5283 case WINE_GGO_GRAY16_BITMAP:
5284 if (is_hinting_enabled())
5286 WORD gasp_flags;
5287 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
5289 TRACE( "font %s %d aa disabled by GASP\n",
5290 debugstr_w(lf.lfFaceName), lf.lfHeight );
5291 *aa_flags = GGO_BITMAP;
5296 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5297 release_font( physdev->font );
5298 physdev->font = ret;
5300 LeaveCriticalSection( &freetype_cs );
5301 release_dc_ptr( dc );
5302 return ret ? hfont : 0;
5305 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5307 HRSRC rsrc;
5308 HGLOBAL hMem;
5309 WCHAR *p;
5310 int i;
5312 id += IDS_FIRST_SCRIPT;
5313 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5314 if (!rsrc) return 0;
5315 hMem = LoadResource( gdi32_module, rsrc );
5316 if (!hMem) return 0;
5318 p = LockResource( hMem );
5319 id &= 0x000f;
5320 while (id--) p += *p + 1;
5322 i = min(LF_FACESIZE - 1, *p);
5323 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5324 buffer[i] = 0;
5325 return i;
5329 /***************************************************
5330 * create_enum_charset_list
5332 * This function creates charset enumeration list because in DEFAULT_CHARSET
5333 * case, the ANSI codepage's charset takes precedence over other charsets.
5334 * This function works as a filter other than DEFAULT_CHARSET case.
5336 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5338 CHARSETINFO csi;
5339 DWORD n = 0;
5341 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5342 csi.fs.fsCsb[0] != 0) {
5343 list->element[n].mask = csi.fs.fsCsb[0];
5344 list->element[n].charset = csi.ciCharset;
5345 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5346 n++;
5348 else { /* charset is DEFAULT_CHARSET or invalid. */
5349 INT acp, i;
5350 DWORD mask = 0;
5352 /* Set the current codepage's charset as the first element. */
5353 acp = GetACP();
5354 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5355 csi.fs.fsCsb[0] != 0) {
5356 list->element[n].mask = csi.fs.fsCsb[0];
5357 list->element[n].charset = csi.ciCharset;
5358 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5359 mask |= csi.fs.fsCsb[0];
5360 n++;
5363 /* Fill out left elements. */
5364 for (i = 0; i < 32; i++) {
5365 FONTSIGNATURE fs;
5366 fs.fsCsb[0] = 1L << i;
5367 fs.fsCsb[1] = 0;
5368 if (fs.fsCsb[0] & mask)
5369 continue; /* skip, already added. */
5370 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5371 continue; /* skip, this is an invalid fsCsb bit. */
5373 list->element[n].mask = fs.fsCsb[0];
5374 list->element[n].charset = csi.ciCharset;
5375 load_script_name( i, list->element[n].name );
5376 mask |= fs.fsCsb[0];
5377 n++;
5380 /* add catch all mask for remaining bits */
5381 if (~mask)
5383 list->element[n].mask = ~mask;
5384 list->element[n].charset = DEFAULT_CHARSET;
5385 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5386 n++;
5389 list->total = n;
5391 return n;
5394 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
5395 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5397 GdiFont *font;
5398 LONG width, height;
5400 if (face->cached_enum_data)
5402 TRACE("Cached\n");
5403 *pelf = face->cached_enum_data->elf;
5404 *pntm = face->cached_enum_data->ntm;
5405 *ptype = face->cached_enum_data->type;
5406 return;
5409 font = alloc_font();
5411 if(face->scalable) {
5412 height = 100;
5413 width = 0;
5414 } else {
5415 height = face->size.y_ppem >> 6;
5416 width = face->size.x_ppem >> 6;
5418 font->scale_y = 1.0;
5420 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5422 free_font(font);
5423 return;
5426 font->name = strdupW( family_name );
5427 font->ntmFlags = face->ntmFlags;
5429 if (get_outline_text_metrics(font))
5431 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5433 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5434 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5435 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5437 lstrcpynW(pelf->elfLogFont.lfFaceName,
5438 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5439 LF_FACESIZE);
5440 lstrcpynW(pelf->elfFullName,
5441 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5442 LF_FULLFACESIZE);
5443 lstrcpynW(pelf->elfStyle,
5444 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5445 LF_FACESIZE);
5447 else
5449 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5451 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5452 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5453 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5455 lstrcpynW(pelf->elfLogFont.lfFaceName, family_name, LF_FACESIZE);
5456 if (face->FullName)
5457 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5458 else
5459 lstrcpynW(pelf->elfFullName, family_name, LF_FULLFACESIZE);
5460 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5463 pntm->ntmTm.ntmFlags = face->ntmFlags;
5464 pntm->ntmFontSig = face->fs;
5466 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5468 pelf->elfLogFont.lfEscapement = 0;
5469 pelf->elfLogFont.lfOrientation = 0;
5470 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5471 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5472 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5473 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5474 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5475 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5476 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5477 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5478 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5479 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5480 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5482 *ptype = 0;
5483 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5484 *ptype |= TRUETYPE_FONTTYPE;
5485 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5486 *ptype |= DEVICE_FONTTYPE;
5487 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5488 *ptype |= RASTER_FONTTYPE;
5490 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5491 if (face->cached_enum_data)
5493 face->cached_enum_data->elf = *pelf;
5494 face->cached_enum_data->ntm = *pntm;
5495 face->cached_enum_data->type = *ptype;
5498 free_font(font);
5501 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5503 Face *face;
5504 const struct list *face_list;
5506 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5508 face_list = get_face_list_from_family(family);
5509 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5510 if (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName)) return TRUE;
5512 return FALSE;
5515 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5517 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5519 return (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName));
5522 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5523 FONTENUMPROCW proc, LPARAM lparam)
5525 ENUMLOGFONTEXW elf;
5526 NEWTEXTMETRICEXW ntm;
5527 DWORD type = 0;
5528 DWORD i;
5530 GetEnumStructs(face, face->family->FamilyName, &elf, &ntm, &type);
5531 for(i = 0; i < list->total; i++) {
5532 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5533 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5534 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
5535 i = list->total; /* break out of loop after enumeration */
5537 else
5539 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
5540 /* use the DEFAULT_CHARSET case only if no other charset is present */
5541 if (list->element[i].charset == DEFAULT_CHARSET &&
5542 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
5543 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5544 strcpyW(elf.elfScript, list->element[i].name);
5545 if (!elf.elfScript[0])
5546 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5548 /* Font Replacement */
5549 if (family != face->family)
5551 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5552 if (face->FullName)
5553 strcpyW(elf.elfFullName, face->FullName);
5554 else
5555 strcpyW(elf.elfFullName, family->FamilyName);
5557 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5558 debugstr_w(elf.elfLogFont.lfFaceName),
5559 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5560 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5561 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5562 ntm.ntmTm.ntmFlags);
5563 /* release section before callback (FIXME) */
5564 LeaveCriticalSection( &freetype_cs );
5565 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5566 EnterCriticalSection( &freetype_cs );
5568 return TRUE;
5571 /*************************************************************
5572 * freetype_EnumFonts
5574 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5576 Family *family;
5577 Face *face;
5578 const struct list *face_list;
5579 LOGFONTW lf;
5580 struct enum_charset_list enum_charsets;
5582 if (!plf)
5584 lf.lfCharSet = DEFAULT_CHARSET;
5585 lf.lfPitchAndFamily = 0;
5586 lf.lfFaceName[0] = 0;
5587 plf = &lf;
5590 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5592 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5594 GDI_CheckNotLock();
5595 EnterCriticalSection( &freetype_cs );
5596 if(plf->lfFaceName[0]) {
5597 FontSubst *psub;
5598 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5600 if(psub) {
5601 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5602 debugstr_w(psub->to.name));
5603 lf = *plf;
5604 strcpyW(lf.lfFaceName, psub->to.name);
5605 plf = &lf;
5608 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5609 if (!family_matches(family, plf)) continue;
5610 face_list = get_face_list_from_family(family);
5611 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5612 if (!face_matches(family->FamilyName, face, plf)) continue;
5613 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5616 } else {
5617 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5618 face_list = get_face_list_from_family(family);
5619 face = LIST_ENTRY(list_head(face_list), Face, entry);
5620 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5623 LeaveCriticalSection( &freetype_cs );
5624 return TRUE;
5627 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5629 pt->x.value = vec->x >> 6;
5630 pt->x.fract = (vec->x & 0x3f) << 10;
5631 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5632 pt->y.value = vec->y >> 6;
5633 pt->y.fract = (vec->y & 0x3f) << 10;
5634 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5635 return;
5638 /***************************************************
5639 * According to the MSDN documentation on WideCharToMultiByte,
5640 * certain codepages cannot set the default_used parameter.
5641 * This returns TRUE if the codepage can set that parameter, false else
5642 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5644 static BOOL codepage_sets_default_used(UINT codepage)
5646 switch (codepage)
5648 case CP_UTF7:
5649 case CP_UTF8:
5650 case CP_SYMBOL:
5651 return FALSE;
5652 default:
5653 return TRUE;
5658 * GSUB Table handling functions
5661 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5663 const GSUB_CoverageFormat1* cf1;
5665 cf1 = table;
5667 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5669 int count = GET_BE_WORD(cf1->GlyphCount);
5670 int i;
5671 TRACE("Coverage Format 1, %i glyphs\n",count);
5672 for (i = 0; i < count; i++)
5673 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5674 return i;
5675 return -1;
5677 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5679 const GSUB_CoverageFormat2* cf2;
5680 int i;
5681 int count;
5682 cf2 = (const GSUB_CoverageFormat2*)cf1;
5684 count = GET_BE_WORD(cf2->RangeCount);
5685 TRACE("Coverage Format 2, %i ranges\n",count);
5686 for (i = 0; i < count; i++)
5688 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5689 return -1;
5690 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5691 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5693 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5694 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5697 return -1;
5699 else
5700 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5702 return -1;
5705 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5707 int i;
5708 int offset;
5709 const GSUB_LookupList *lookup;
5710 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5712 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5713 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5715 const GSUB_LookupTable *look;
5716 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5717 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5718 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5719 if (GET_BE_WORD(look->LookupType) != 1)
5720 FIXME("We only handle SubType 1\n");
5721 else
5723 int j;
5725 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5727 const GSUB_SingleSubstFormat1 *ssf1;
5728 offset = GET_BE_WORD(look->SubTable[j]);
5729 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5730 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5732 int offset = GET_BE_WORD(ssf1->Coverage);
5733 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5734 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5736 TRACE(" Glyph 0x%x ->",glyph);
5737 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5738 TRACE(" 0x%x\n",glyph);
5741 else
5743 const GSUB_SingleSubstFormat2 *ssf2;
5744 INT index;
5745 INT offset;
5747 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5748 offset = GET_BE_WORD(ssf1->Coverage);
5749 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5750 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5751 TRACE(" Coverage index %i\n",index);
5752 if (index != -1)
5754 TRACE(" Glyph is 0x%x ->",glyph);
5755 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5756 TRACE("0x%x\n",glyph);
5762 return glyph;
5766 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5768 const GSUB_Header *header;
5769 const GSUB_Feature *feature;
5771 if (!font->GSUB_Table)
5772 return glyph;
5774 header = font->GSUB_Table;
5775 feature = font->vert_feature;
5777 return GSUB_apply_feature(header, feature, glyph);
5780 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5782 FT_UInt glyphId;
5784 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5785 WCHAR wc = (WCHAR)glyph;
5786 BOOL default_used;
5787 BOOL *default_used_pointer;
5788 FT_UInt ret;
5789 char buf;
5790 default_used_pointer = NULL;
5791 default_used = FALSE;
5792 if (codepage_sets_default_used(font->codepage))
5793 default_used_pointer = &default_used;
5794 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5796 if (font->codepage == CP_SYMBOL && wc < 0x100)
5797 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
5798 else
5799 ret = 0;
5801 else
5802 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5803 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5804 return ret;
5807 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5809 if (glyph < 0x100) glyph += 0xf000;
5810 /* there is a number of old pre-Unicode "broken" TTFs, which
5811 do have symbols at U+00XX instead of U+f0XX */
5812 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5813 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5815 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5817 return glyphId;
5820 /*************************************************************
5821 * freetype_GetGlyphIndices
5823 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5825 struct freetype_physdev *physdev = get_freetype_dev( dev );
5826 int i;
5827 WORD default_char;
5828 BOOL got_default = FALSE;
5830 if (!physdev->font)
5832 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5833 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5836 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5838 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5839 got_default = TRUE;
5842 GDI_CheckNotLock();
5843 EnterCriticalSection( &freetype_cs );
5845 for(i = 0; i < count; i++)
5847 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5848 if (pgi[i] == 0)
5850 if (!got_default)
5852 if (FT_IS_SFNT(physdev->font->ft_face))
5854 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5855 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5857 else
5859 TEXTMETRICW textm;
5860 get_text_metrics(physdev->font, &textm);
5861 default_char = textm.tmDefaultChar;
5863 got_default = TRUE;
5865 pgi[i] = default_char;
5867 else
5868 pgi[i] = get_GSUB_vert_glyph(physdev->font, pgi[i]);
5870 LeaveCriticalSection( &freetype_cs );
5871 return count;
5874 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5876 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5877 return !memcmp(matrix, &identity, sizeof(FMAT2));
5880 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5882 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5883 return !memcmp(matrix, &identity, sizeof(MAT2));
5886 static inline BYTE get_max_level( UINT format )
5888 switch( format )
5890 case GGO_GRAY2_BITMAP: return 4;
5891 case GGO_GRAY4_BITMAP: return 16;
5892 case GGO_GRAY8_BITMAP: return 64;
5894 return 255;
5897 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5899 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5900 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
5901 const MAT2* lpmat)
5903 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5904 FT_Face ft_face = incoming_font->ft_face;
5905 GdiFont *font = incoming_font;
5906 FT_Glyph_Metrics metrics;
5907 FT_UInt glyph_index;
5908 DWORD width, height, pitch, needed = 0;
5909 FT_Bitmap ft_bitmap;
5910 FT_Error err;
5911 INT left, right, top = 0, bottom = 0, adv;
5912 FT_Angle angle = 0;
5913 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5914 double widthRatio = 1.0;
5915 FT_Matrix transMat = identityMat;
5916 FT_Matrix transMatUnrotated;
5917 BOOL needsTransform = FALSE;
5918 BOOL tategaki = (font->name[0] == '@');
5919 UINT original_index;
5920 LONG avgAdvance = 0;
5921 FT_Fixed em_scale;
5923 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5924 buflen, buf, lpmat);
5926 TRACE("font transform %f %f %f %f\n",
5927 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5928 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5930 if(format & GGO_GLYPH_INDEX) {
5931 glyph_index = glyph;
5932 original_index = glyph;
5933 format &= ~GGO_GLYPH_INDEX;
5934 } else {
5935 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5936 ft_face = font->ft_face;
5937 original_index = glyph_index;
5940 if(format & GGO_UNHINTED) {
5941 load_flags |= FT_LOAD_NO_HINTING;
5942 format &= ~GGO_UNHINTED;
5945 /* tategaki never appears to happen to lower glyph index */
5946 if (glyph_index < TATEGAKI_LOWER_BOUND )
5947 tategaki = FALSE;
5949 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5950 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5951 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5952 font->gmsize * sizeof(GM*));
5953 } else {
5954 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5955 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5957 *lpgm = FONT_GM(font,original_index)->gm;
5958 *abc = FONT_GM(font,original_index)->abc;
5959 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5960 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5961 lpgm->gmCellIncX, lpgm->gmCellIncY);
5962 return 1; /* FIXME */
5966 if (!font->gm[original_index / GM_BLOCK_SIZE])
5967 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5969 /* Scaling factor */
5970 if (font->aveWidth)
5972 TEXTMETRICW tm;
5974 get_text_metrics(font, &tm);
5976 widthRatio = (double)font->aveWidth;
5977 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5979 else
5980 widthRatio = font->scale_y;
5982 /* Scaling transform */
5983 if (widthRatio != 1.0 || font->scale_y != 1.0)
5985 FT_Matrix scaleMat;
5986 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5987 scaleMat.xy = 0;
5988 scaleMat.yx = 0;
5989 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5991 pFT_Matrix_Multiply(&scaleMat, &transMat);
5992 needsTransform = TRUE;
5995 /* Slant transform */
5996 if (font->fake_italic) {
5997 FT_Matrix slantMat;
5999 slantMat.xx = (1 << 16);
6000 slantMat.xy = ((1 << 16) >> 2);
6001 slantMat.yx = 0;
6002 slantMat.yy = (1 << 16);
6003 pFT_Matrix_Multiply(&slantMat, &transMat);
6004 needsTransform = TRUE;
6007 /* Rotation transform */
6008 transMatUnrotated = transMat;
6009 if(font->orientation && !tategaki) {
6010 FT_Matrix rotationMat;
6011 FT_Vector vecAngle;
6012 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
6013 pFT_Vector_Unit(&vecAngle, angle);
6014 rotationMat.xx = vecAngle.x;
6015 rotationMat.xy = -vecAngle.y;
6016 rotationMat.yx = -rotationMat.xy;
6017 rotationMat.yy = rotationMat.xx;
6019 pFT_Matrix_Multiply(&rotationMat, &transMat);
6020 needsTransform = TRUE;
6023 /* World transform */
6024 if (!is_identity_FMAT2(&font->font_desc.matrix))
6026 FT_Matrix worldMat;
6027 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
6028 worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21);
6029 worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12);
6030 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
6031 pFT_Matrix_Multiply(&worldMat, &transMat);
6032 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
6033 needsTransform = TRUE;
6036 /* Extra transformation specified by caller */
6037 if (!is_identity_MAT2(lpmat))
6039 FT_Matrix extraMat;
6040 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
6041 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
6042 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
6043 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
6044 pFT_Matrix_Multiply(&extraMat, &transMat);
6045 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
6046 needsTransform = TRUE;
6049 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
6051 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
6053 if(err) {
6054 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
6055 return GDI_ERROR;
6058 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6059 * by the text metrics. The proper behavior is to clip the glyph metrics to
6060 * fit within the maximums specified in the text metrics. */
6061 metrics = ft_face->glyph->metrics;
6062 if(incoming_font->potm || get_outline_text_metrics(incoming_font) ||
6063 get_bitmap_text_metrics(incoming_font)) {
6064 TEXTMETRICW *ptm = &incoming_font->potm->otmTextMetrics;
6065 top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
6066 bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
6067 metrics.horiBearingY = top;
6068 metrics.height = top - bottom;
6070 /* TODO: Are we supposed to clip the width as well...? */
6071 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6074 if(FT_IS_SCALABLE(incoming_font->ft_face)) {
6075 TEXTMETRICW tm;
6076 if (get_text_metrics(incoming_font, &tm) &&
6077 !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
6078 em_scale = MulDiv(incoming_font->ppem, 1 << 16, incoming_font->ft_face->units_per_EM);
6079 avgAdvance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
6080 if (avgAdvance &&
6081 (metrics.horiAdvance+63) >> 6 == pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale))
6082 TRACE("Fixed-pitch full-width character detected\n");
6083 else
6084 avgAdvance = 0; /* cancel this feature */
6088 if(!needsTransform) {
6089 left = (INT)(metrics.horiBearingX) & -64;
6090 right = (INT)((metrics.horiBearingX + metrics.width) + 63) & -64;
6091 if (!avgAdvance)
6092 adv = (INT)(metrics.horiAdvance + 63) >> 6;
6093 else
6094 adv = (INT)avgAdvance * 2;
6096 top = (metrics.horiBearingY + 63) & -64;
6097 bottom = (metrics.horiBearingY - metrics.height) & -64;
6098 lpgm->gmCellIncX = adv;
6099 lpgm->gmCellIncY = 0;
6100 } else {
6101 INT xc, yc;
6102 FT_Vector vec;
6104 left = right = 0;
6106 for(xc = 0; xc < 2; xc++) {
6107 for(yc = 0; yc < 2; yc++) {
6108 vec.x = metrics.horiBearingX + xc * metrics.width;
6109 vec.y = metrics.horiBearingY - yc * metrics.height;
6110 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
6111 pFT_Vector_Transform(&vec, &transMat);
6112 if(xc == 0 && yc == 0) {
6113 left = right = vec.x;
6114 top = bottom = vec.y;
6115 } else {
6116 if(vec.x < left) left = vec.x;
6117 else if(vec.x > right) right = vec.x;
6118 if(vec.y < bottom) bottom = vec.y;
6119 else if(vec.y > top) top = vec.y;
6123 left = left & -64;
6124 right = (right + 63) & -64;
6125 bottom = bottom & -64;
6126 top = (top + 63) & -64;
6128 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
6129 vec.x = metrics.horiAdvance;
6130 vec.y = 0;
6131 pFT_Vector_Transform(&vec, &transMat);
6132 lpgm->gmCellIncY = -((vec.y+63) >> 6);
6133 if (!avgAdvance || vec.y)
6134 lpgm->gmCellIncX = (vec.x+63) >> 6;
6135 else {
6136 vec.x = incoming_font->ntmAvgWidth;
6137 vec.y = 0;
6138 pFT_Vector_Transform(&vec, &transMat);
6139 lpgm->gmCellIncX = pFT_MulFix(vec.x, em_scale) * 2;
6142 vec.x = metrics.horiAdvance;
6143 vec.y = 0;
6144 pFT_Vector_Transform(&vec, &transMatUnrotated);
6145 if (!avgAdvance || vec.y)
6146 adv = (vec.x+63) >> 6;
6147 else {
6148 vec.x = incoming_font->ntmAvgWidth;
6149 vec.y = 0;
6150 pFT_Vector_Transform(&vec, &transMatUnrotated);
6151 adv = pFT_MulFix(vec.x, em_scale) * 2;
6155 lpgm->gmBlackBoxX = (right - left) >> 6;
6156 lpgm->gmBlackBoxY = (top - bottom) >> 6;
6157 lpgm->gmptGlyphOrigin.x = left >> 6;
6158 lpgm->gmptGlyphOrigin.y = top >> 6;
6159 abc->abcA = left >> 6;
6160 abc->abcB = (right - left) >> 6;
6161 abc->abcC = adv - abc->abcA - abc->abcB;
6163 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6164 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6165 lpgm->gmCellIncX, lpgm->gmCellIncY);
6167 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
6168 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
6170 FONT_GM(font,original_index)->gm = *lpgm;
6171 FONT_GM(font,original_index)->abc = *abc;
6172 FONT_GM(font,original_index)->init = TRUE;
6175 if(format == GGO_METRICS)
6177 return 1; /* FIXME */
6180 if(ft_face->glyph->format != ft_glyph_format_outline &&
6181 (format == GGO_NATIVE || format == GGO_BEZIER))
6183 TRACE("loaded a bitmap\n");
6184 return GDI_ERROR;
6187 switch(format) {
6188 case GGO_BITMAP:
6189 width = lpgm->gmBlackBoxX;
6190 height = lpgm->gmBlackBoxY;
6191 pitch = ((width + 31) >> 5) << 2;
6192 needed = pitch * height;
6194 if(!buf || !buflen) break;
6196 switch(ft_face->glyph->format) {
6197 case ft_glyph_format_bitmap:
6199 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6200 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
6201 INT h = min( height, ft_face->glyph->bitmap.rows );
6202 while(h--) {
6203 memcpy(dst, src, w);
6204 src += ft_face->glyph->bitmap.pitch;
6205 dst += pitch;
6207 break;
6210 case ft_glyph_format_outline:
6211 ft_bitmap.width = width;
6212 ft_bitmap.rows = height;
6213 ft_bitmap.pitch = pitch;
6214 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
6215 ft_bitmap.buffer = buf;
6217 if(needsTransform)
6218 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6220 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6222 /* Note: FreeType will only set 'black' bits for us. */
6223 memset(buf, 0, needed);
6224 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6225 break;
6227 default:
6228 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6229 return GDI_ERROR;
6231 break;
6233 case GGO_GRAY2_BITMAP:
6234 case GGO_GRAY4_BITMAP:
6235 case GGO_GRAY8_BITMAP:
6236 case WINE_GGO_GRAY16_BITMAP:
6238 unsigned int max_level, row, col;
6239 BYTE *start, *ptr;
6241 width = lpgm->gmBlackBoxX;
6242 height = lpgm->gmBlackBoxY;
6243 pitch = (width + 3) / 4 * 4;
6244 needed = pitch * height;
6246 if(!buf || !buflen) break;
6248 max_level = get_max_level( format );
6250 switch(ft_face->glyph->format) {
6251 case ft_glyph_format_bitmap:
6253 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6254 INT h = min( height, ft_face->glyph->bitmap.rows );
6255 INT x;
6256 memset( buf, 0, needed );
6257 while(h--) {
6258 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
6259 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
6260 src += ft_face->glyph->bitmap.pitch;
6261 dst += pitch;
6263 return needed;
6265 case ft_glyph_format_outline:
6267 ft_bitmap.width = width;
6268 ft_bitmap.rows = height;
6269 ft_bitmap.pitch = pitch;
6270 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6271 ft_bitmap.buffer = buf;
6273 if(needsTransform)
6274 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6276 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6278 memset(ft_bitmap.buffer, 0, buflen);
6280 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6282 if (max_level != 255)
6284 for (row = 0, start = buf; row < height; row++)
6286 for (col = 0, ptr = start; col < width; col++, ptr++)
6287 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6288 start += pitch;
6291 return needed;
6294 default:
6295 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6296 return GDI_ERROR;
6298 break;
6301 case WINE_GGO_HRGB_BITMAP:
6302 case WINE_GGO_HBGR_BITMAP:
6303 case WINE_GGO_VRGB_BITMAP:
6304 case WINE_GGO_VBGR_BITMAP:
6305 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6307 switch (ft_face->glyph->format)
6309 case FT_GLYPH_FORMAT_BITMAP:
6311 BYTE *src, *dst;
6312 INT src_pitch, x;
6314 width = lpgm->gmBlackBoxX;
6315 height = lpgm->gmBlackBoxY;
6316 pitch = width * 4;
6317 needed = pitch * height;
6319 if (!buf || !buflen) break;
6321 memset(buf, 0, buflen);
6322 dst = buf;
6323 src = ft_face->glyph->bitmap.buffer;
6324 src_pitch = ft_face->glyph->bitmap.pitch;
6326 height = min( height, ft_face->glyph->bitmap.rows );
6327 while ( height-- )
6329 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6331 if ( src[x / 8] & masks[x % 8] )
6332 ((unsigned int *)dst)[x] = ~0u;
6334 src += src_pitch;
6335 dst += pitch;
6338 break;
6341 case FT_GLYPH_FORMAT_OUTLINE:
6343 unsigned int *dst;
6344 BYTE *src;
6345 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6346 INT x_shift, y_shift;
6347 BOOL rgb;
6348 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6349 FT_Render_Mode render_mode =
6350 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6351 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6353 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6355 if ( render_mode == FT_RENDER_MODE_LCD)
6357 lpgm->gmBlackBoxX += 2;
6358 lpgm->gmptGlyphOrigin.x -= 1;
6360 else
6362 lpgm->gmBlackBoxY += 2;
6363 lpgm->gmptGlyphOrigin.y += 1;
6367 width = lpgm->gmBlackBoxX;
6368 height = lpgm->gmBlackBoxY;
6369 pitch = width * 4;
6370 needed = pitch * height;
6372 if (!buf || !buflen) break;
6374 memset(buf, 0, buflen);
6375 dst = buf;
6376 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6378 if ( needsTransform )
6379 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
6381 if ( pFT_Library_SetLcdFilter )
6382 pFT_Library_SetLcdFilter( library, lcdfilter );
6383 pFT_Render_Glyph (ft_face->glyph, render_mode);
6385 src = ft_face->glyph->bitmap.buffer;
6386 src_pitch = ft_face->glyph->bitmap.pitch;
6387 src_width = ft_face->glyph->bitmap.width;
6388 src_height = ft_face->glyph->bitmap.rows;
6390 if ( render_mode == FT_RENDER_MODE_LCD)
6392 rgb_interval = 1;
6393 hmul = 3;
6394 vmul = 1;
6396 else
6398 rgb_interval = src_pitch;
6399 hmul = 1;
6400 vmul = 3;
6403 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6404 if ( x_shift < 0 )
6406 src += hmul * -x_shift;
6407 src_width -= hmul * -x_shift;
6409 else if ( x_shift > 0 )
6411 dst += x_shift;
6412 width -= x_shift;
6415 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6416 if ( y_shift < 0 )
6418 src += src_pitch * vmul * -y_shift;
6419 src_height -= vmul * -y_shift;
6421 else if ( y_shift > 0 )
6423 dst += y_shift * ( pitch / sizeof(*dst) );
6424 height -= y_shift;
6427 width = min( width, src_width / hmul );
6428 height = min( height, src_height / vmul );
6430 while ( height-- )
6432 for ( x = 0; x < width; x++ )
6434 if ( rgb )
6436 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6437 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6438 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6439 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6441 else
6443 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6444 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6445 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6446 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6449 src += src_pitch * vmul;
6450 dst += pitch / sizeof(*dst);
6453 break;
6456 default:
6457 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6458 return GDI_ERROR;
6461 break;
6463 #else
6464 return GDI_ERROR;
6465 #endif
6467 case GGO_NATIVE:
6469 int contour, point = 0, first_pt;
6470 FT_Outline *outline = &ft_face->glyph->outline;
6471 TTPOLYGONHEADER *pph;
6472 TTPOLYCURVE *ppc;
6473 DWORD pph_start, cpfx, type;
6475 if(buflen == 0) buf = NULL;
6477 if (needsTransform && buf) {
6478 pFT_Outline_Transform(outline, &transMat);
6481 for(contour = 0; contour < outline->n_contours; contour++) {
6482 /* Ignore contours containing one point */
6483 if(point == outline->contours[contour]) {
6484 point++;
6485 continue;
6488 pph_start = needed;
6489 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6490 first_pt = point;
6491 if(buf) {
6492 pph->dwType = TT_POLYGON_TYPE;
6493 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6495 needed += sizeof(*pph);
6496 point++;
6497 while(point <= outline->contours[contour]) {
6498 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6499 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6500 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6501 cpfx = 0;
6502 do {
6503 if(buf)
6504 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6505 cpfx++;
6506 point++;
6507 } while(point <= outline->contours[contour] &&
6508 (outline->tags[point] & FT_Curve_Tag_On) ==
6509 (outline->tags[point-1] & FT_Curve_Tag_On));
6510 /* At the end of a contour Windows adds the start point, but
6511 only for Beziers */
6512 if(point > outline->contours[contour] &&
6513 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6514 if(buf)
6515 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6516 cpfx++;
6517 } else if(point <= outline->contours[contour] &&
6518 outline->tags[point] & FT_Curve_Tag_On) {
6519 /* add closing pt for bezier */
6520 if(buf)
6521 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6522 cpfx++;
6523 point++;
6525 if(buf) {
6526 ppc->wType = type;
6527 ppc->cpfx = cpfx;
6529 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6531 if(buf)
6532 pph->cb = needed - pph_start;
6534 break;
6536 case GGO_BEZIER:
6538 /* Convert the quadratic Beziers to cubic Beziers.
6539 The parametric eqn for a cubic Bezier is, from PLRM:
6540 r(t) = at^3 + bt^2 + ct + r0
6541 with the control points:
6542 r1 = r0 + c/3
6543 r2 = r1 + (c + b)/3
6544 r3 = r0 + c + b + a
6546 A quadratic Bezier has the form:
6547 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6549 So equating powers of t leads to:
6550 r1 = 2/3 p1 + 1/3 p0
6551 r2 = 2/3 p1 + 1/3 p2
6552 and of course r0 = p0, r3 = p2
6555 int contour, point = 0, first_pt;
6556 FT_Outline *outline = &ft_face->glyph->outline;
6557 TTPOLYGONHEADER *pph;
6558 TTPOLYCURVE *ppc;
6559 DWORD pph_start, cpfx, type;
6560 FT_Vector cubic_control[4];
6561 if(buflen == 0) buf = NULL;
6563 if (needsTransform && buf) {
6564 pFT_Outline_Transform(outline, &transMat);
6567 for(contour = 0; contour < outline->n_contours; contour++) {
6568 pph_start = needed;
6569 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6570 first_pt = point;
6571 if(buf) {
6572 pph->dwType = TT_POLYGON_TYPE;
6573 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6575 needed += sizeof(*pph);
6576 point++;
6577 while(point <= outline->contours[contour]) {
6578 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6579 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6580 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6581 cpfx = 0;
6582 do {
6583 if(type == TT_PRIM_LINE) {
6584 if(buf)
6585 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6586 cpfx++;
6587 point++;
6588 } else {
6589 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6590 so cpfx = 3n */
6592 /* FIXME: Possible optimization in endpoint calculation
6593 if there are two consecutive curves */
6594 cubic_control[0] = outline->points[point-1];
6595 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6596 cubic_control[0].x += outline->points[point].x + 1;
6597 cubic_control[0].y += outline->points[point].y + 1;
6598 cubic_control[0].x >>= 1;
6599 cubic_control[0].y >>= 1;
6601 if(point+1 > outline->contours[contour])
6602 cubic_control[3] = outline->points[first_pt];
6603 else {
6604 cubic_control[3] = outline->points[point+1];
6605 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6606 cubic_control[3].x += outline->points[point].x + 1;
6607 cubic_control[3].y += outline->points[point].y + 1;
6608 cubic_control[3].x >>= 1;
6609 cubic_control[3].y >>= 1;
6612 /* r1 = 1/3 p0 + 2/3 p1
6613 r2 = 1/3 p2 + 2/3 p1 */
6614 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6615 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6616 cubic_control[2] = cubic_control[1];
6617 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6618 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6619 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6620 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6621 if(buf) {
6622 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6623 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6624 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6626 cpfx += 3;
6627 point++;
6629 } while(point <= outline->contours[contour] &&
6630 (outline->tags[point] & FT_Curve_Tag_On) ==
6631 (outline->tags[point-1] & FT_Curve_Tag_On));
6632 /* At the end of a contour Windows adds the start point,
6633 but only for Beziers and we've already done that.
6635 if(point <= outline->contours[contour] &&
6636 outline->tags[point] & FT_Curve_Tag_On) {
6637 /* This is the closing pt of a bezier, but we've already
6638 added it, so just inc point and carry on */
6639 point++;
6641 if(buf) {
6642 ppc->wType = type;
6643 ppc->cpfx = cpfx;
6645 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6647 if(buf)
6648 pph->cb = needed - pph_start;
6650 break;
6653 default:
6654 FIXME("Unsupported format %d\n", format);
6655 return GDI_ERROR;
6657 return needed;
6660 static BOOL get_bitmap_text_metrics(GdiFont *font)
6662 FT_Face ft_face = font->ft_face;
6663 FT_WinFNT_HeaderRec winfnt_header;
6664 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6665 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6666 font->potm->otmSize = size;
6668 #define TM font->potm->otmTextMetrics
6669 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6671 TM.tmHeight = winfnt_header.pixel_height;
6672 TM.tmAscent = winfnt_header.ascent;
6673 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6674 TM.tmInternalLeading = winfnt_header.internal_leading;
6675 TM.tmExternalLeading = winfnt_header.external_leading;
6676 TM.tmAveCharWidth = winfnt_header.avg_width;
6677 TM.tmMaxCharWidth = winfnt_header.max_width;
6678 TM.tmWeight = winfnt_header.weight;
6679 TM.tmOverhang = 0;
6680 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6681 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6682 TM.tmFirstChar = winfnt_header.first_char;
6683 TM.tmLastChar = winfnt_header.last_char;
6684 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6685 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6686 TM.tmItalic = winfnt_header.italic;
6687 TM.tmUnderlined = font->underline;
6688 TM.tmStruckOut = font->strikeout;
6689 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6690 TM.tmCharSet = winfnt_header.charset;
6692 else
6694 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6695 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6696 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6697 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6698 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6699 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6700 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6701 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6702 TM.tmOverhang = 0;
6703 TM.tmDigitizedAspectX = 96; /* FIXME */
6704 TM.tmDigitizedAspectY = 96; /* FIXME */
6705 TM.tmFirstChar = 1;
6706 TM.tmLastChar = 255;
6707 TM.tmDefaultChar = 32;
6708 TM.tmBreakChar = 32;
6709 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6710 TM.tmUnderlined = font->underline;
6711 TM.tmStruckOut = font->strikeout;
6712 /* NB inverted meaning of TMPF_FIXED_PITCH */
6713 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6714 TM.tmCharSet = font->charset;
6716 #undef TM
6718 return TRUE;
6722 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6724 double scale_x, scale_y;
6726 if (font->aveWidth)
6728 scale_x = (double)font->aveWidth;
6729 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6731 else
6732 scale_x = font->scale_y;
6734 scale_x *= fabs(font->font_desc.matrix.eM11);
6735 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6737 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6738 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6740 SCALE_Y(ptm->tmHeight);
6741 SCALE_Y(ptm->tmAscent);
6742 SCALE_Y(ptm->tmDescent);
6743 SCALE_Y(ptm->tmInternalLeading);
6744 SCALE_Y(ptm->tmExternalLeading);
6745 SCALE_Y(ptm->tmOverhang);
6747 SCALE_X(ptm->tmAveCharWidth);
6748 SCALE_X(ptm->tmMaxCharWidth);
6750 #undef SCALE_X
6751 #undef SCALE_Y
6754 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6756 double scale_x, scale_y;
6758 if (font->aveWidth)
6760 scale_x = (double)font->aveWidth;
6761 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6763 else
6764 scale_x = font->scale_y;
6766 scale_x *= fabs(font->font_desc.matrix.eM11);
6767 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6769 scale_font_metrics(font, &potm->otmTextMetrics);
6771 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6772 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6774 SCALE_Y(potm->otmAscent);
6775 SCALE_Y(potm->otmDescent);
6776 SCALE_Y(potm->otmLineGap);
6777 SCALE_Y(potm->otmsCapEmHeight);
6778 SCALE_Y(potm->otmsXHeight);
6779 SCALE_Y(potm->otmrcFontBox.top);
6780 SCALE_Y(potm->otmrcFontBox.bottom);
6781 SCALE_X(potm->otmrcFontBox.left);
6782 SCALE_X(potm->otmrcFontBox.right);
6783 SCALE_Y(potm->otmMacAscent);
6784 SCALE_Y(potm->otmMacDescent);
6785 SCALE_Y(potm->otmMacLineGap);
6786 SCALE_X(potm->otmptSubscriptSize.x);
6787 SCALE_Y(potm->otmptSubscriptSize.y);
6788 SCALE_X(potm->otmptSubscriptOffset.x);
6789 SCALE_Y(potm->otmptSubscriptOffset.y);
6790 SCALE_X(potm->otmptSuperscriptSize.x);
6791 SCALE_Y(potm->otmptSuperscriptSize.y);
6792 SCALE_X(potm->otmptSuperscriptOffset.x);
6793 SCALE_Y(potm->otmptSuperscriptOffset.y);
6794 SCALE_Y(potm->otmsStrikeoutSize);
6795 SCALE_Y(potm->otmsStrikeoutPosition);
6796 SCALE_Y(potm->otmsUnderscoreSize);
6797 SCALE_Y(potm->otmsUnderscorePosition);
6799 #undef SCALE_X
6800 #undef SCALE_Y
6803 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6805 if(!font->potm)
6807 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6809 /* Make sure that the font has sane width/height ratio */
6810 if (font->aveWidth)
6812 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6814 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6815 font->aveWidth = 0;
6819 *ptm = font->potm->otmTextMetrics;
6820 scale_font_metrics(font, ptm);
6821 return TRUE;
6824 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6826 int i;
6828 for(i = 0; i < ft_face->num_charmaps; i++)
6830 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6831 return TRUE;
6833 return FALSE;
6836 static BOOL get_outline_text_metrics(GdiFont *font)
6838 BOOL ret = FALSE;
6839 FT_Face ft_face = font->ft_face;
6840 UINT needed, lenfam, lensty, lenface, lenfull;
6841 TT_OS2 *pOS2;
6842 TT_HoriHeader *pHori;
6843 TT_Postscript *pPost;
6844 FT_Fixed em_scale;
6845 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
6846 char *cp;
6847 INT ascent, descent;
6849 TRACE("font=%p\n", font);
6851 if(!FT_IS_SCALABLE(ft_face))
6852 return FALSE;
6854 needed = sizeof(*font->potm);
6856 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6857 family_nameW = strdupW(font->name);
6859 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
6860 if (!style_nameW)
6861 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6862 if (!style_nameW)
6864 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
6865 style_nameW = towstr( CP_ACP, ft_face->style_name );
6867 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
6869 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
6870 if (!face_nameW)
6871 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6872 if (!face_nameW)
6874 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
6875 face_nameW = strdupW(font->name);
6877 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
6878 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
6880 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
6881 if (!full_nameW)
6882 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6883 if (!full_nameW)
6885 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
6886 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
6887 full_nameW = strdupW(fake_nameW);
6889 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
6891 /* These names should be read from the TT name table */
6893 /* length of otmpFamilyName */
6894 needed += lenfam;
6896 /* length of otmpFaceName */
6897 needed += lenface;
6899 /* length of otmpStyleName */
6900 needed += lensty;
6902 /* length of otmpFullName */
6903 needed += lenfull;
6906 em_scale = (FT_Fixed)MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
6908 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6909 if(!pOS2) {
6910 FIXME("Can't find OS/2 table - not TT font?\n");
6911 goto end;
6914 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6915 if(!pHori) {
6916 FIXME("Can't find HHEA table - not TT font?\n");
6917 goto end;
6920 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6922 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",
6923 pOS2->usWinAscent, pOS2->usWinDescent,
6924 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6925 pOS2->xAvgCharWidth,
6926 ft_face->ascender, ft_face->descender, ft_face->height,
6927 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6928 ft_face->bbox.yMax, ft_face->bbox.yMin);
6930 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6931 font->potm->otmSize = needed;
6933 #define TM font->potm->otmTextMetrics
6935 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6936 ascent = pHori->Ascender;
6937 descent = -pHori->Descender;
6938 } else {
6939 ascent = pOS2->usWinAscent;
6940 descent = pOS2->usWinDescent;
6943 font->ntmCellHeight = ascent + descent;
6944 font->ntmAvgWidth = pOS2->xAvgCharWidth;
6946 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
6947 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
6949 if(font->yMax) {
6950 TM.tmAscent = font->yMax;
6951 TM.tmDescent = -font->yMin;
6952 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6953 } else {
6954 TM.tmAscent = SCALE_Y(ascent);
6955 TM.tmDescent = SCALE_Y(descent);
6956 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
6959 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6961 /* MSDN says:
6962 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6964 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
6965 ((ascent + descent) -
6966 (pHori->Ascender - pHori->Descender))));
6968 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
6969 if (TM.tmAveCharWidth == 0) {
6970 TM.tmAveCharWidth = 1;
6972 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
6973 TM.tmWeight = FW_REGULAR;
6974 if (font->fake_bold)
6975 TM.tmWeight = FW_BOLD;
6976 else
6978 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6980 if (pOS2->usWeightClass > FW_MEDIUM)
6981 TM.tmWeight = pOS2->usWeightClass;
6983 else if (pOS2->usWeightClass <= FW_MEDIUM)
6984 TM.tmWeight = pOS2->usWeightClass;
6986 TM.tmOverhang = 0;
6987 TM.tmDigitizedAspectX = 96; /* FIXME */
6988 TM.tmDigitizedAspectY = 96; /* FIXME */
6989 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6990 * symbol range to 0 - f0ff
6993 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6995 TM.tmFirstChar = 0;
6996 switch(GetACP())
6998 case 1257: /* Baltic */
6999 TM.tmLastChar = 0xf8fd;
7000 break;
7001 default:
7002 TM.tmLastChar = 0xf0ff;
7004 TM.tmBreakChar = 0x20;
7005 TM.tmDefaultChar = 0x1f;
7007 else
7009 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
7010 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
7012 if(pOS2->usFirstCharIndex <= 1)
7013 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
7014 else if (pOS2->usFirstCharIndex > 0xff)
7015 TM.tmBreakChar = 0x20;
7016 else
7017 TM.tmBreakChar = pOS2->usFirstCharIndex;
7018 TM.tmDefaultChar = TM.tmBreakChar - 1;
7020 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
7021 TM.tmUnderlined = font->underline;
7022 TM.tmStruckOut = font->strikeout;
7024 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7025 if(!FT_IS_FIXED_WIDTH(ft_face) &&
7026 (pOS2->version == 0xFFFFU ||
7027 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
7028 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
7029 else
7030 TM.tmPitchAndFamily = 0;
7032 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
7034 case PAN_FAMILY_SCRIPT:
7035 TM.tmPitchAndFamily |= FF_SCRIPT;
7036 break;
7038 case PAN_FAMILY_DECORATIVE:
7039 TM.tmPitchAndFamily |= FF_DECORATIVE;
7040 break;
7042 case PAN_ANY:
7043 case PAN_NO_FIT:
7044 case PAN_FAMILY_TEXT_DISPLAY:
7045 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
7046 /* which is clearly not what the panose spec says. */
7047 default:
7048 if(TM.tmPitchAndFamily == 0 || /* fixed */
7049 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
7050 TM.tmPitchAndFamily = FF_MODERN;
7051 else
7053 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
7055 case PAN_ANY:
7056 case PAN_NO_FIT:
7057 default:
7058 TM.tmPitchAndFamily |= FF_DONTCARE;
7059 break;
7061 case PAN_SERIF_COVE:
7062 case PAN_SERIF_OBTUSE_COVE:
7063 case PAN_SERIF_SQUARE_COVE:
7064 case PAN_SERIF_OBTUSE_SQUARE_COVE:
7065 case PAN_SERIF_SQUARE:
7066 case PAN_SERIF_THIN:
7067 case PAN_SERIF_BONE:
7068 case PAN_SERIF_EXAGGERATED:
7069 case PAN_SERIF_TRIANGLE:
7070 TM.tmPitchAndFamily |= FF_ROMAN;
7071 break;
7073 case PAN_SERIF_NORMAL_SANS:
7074 case PAN_SERIF_OBTUSE_SANS:
7075 case PAN_SERIF_PERP_SANS:
7076 case PAN_SERIF_FLARED:
7077 case PAN_SERIF_ROUNDED:
7078 TM.tmPitchAndFamily |= FF_SWISS;
7079 break;
7082 break;
7085 if(FT_IS_SCALABLE(ft_face))
7086 TM.tmPitchAndFamily |= TMPF_VECTOR;
7088 if(FT_IS_SFNT(ft_face))
7090 if (font->ntmFlags & NTM_PS_OPENTYPE)
7091 TM.tmPitchAndFamily |= TMPF_DEVICE;
7092 else
7093 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
7096 TM.tmCharSet = font->charset;
7098 font->potm->otmFiller = 0;
7099 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
7100 font->potm->otmfsSelection = pOS2->fsSelection;
7101 font->potm->otmfsType = pOS2->fsType;
7102 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
7103 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
7104 font->potm->otmItalicAngle = 0; /* POST table */
7105 font->potm->otmEMSquare = ft_face->units_per_EM;
7106 font->potm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
7107 font->potm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
7108 font->potm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
7109 font->potm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
7110 font->potm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
7111 font->potm->otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
7112 font->potm->otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
7113 font->potm->otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
7114 font->potm->otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
7115 font->potm->otmMacAscent = TM.tmAscent;
7116 font->potm->otmMacDescent = -TM.tmDescent;
7117 font->potm->otmMacLineGap = font->potm->otmLineGap;
7118 font->potm->otmusMinimumPPEM = 0; /* TT Header */
7119 font->potm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
7120 font->potm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
7121 font->potm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
7122 font->potm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
7123 font->potm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
7124 font->potm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
7125 font->potm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
7126 font->potm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
7127 font->potm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
7128 font->potm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
7129 if(!pPost) {
7130 font->potm->otmsUnderscoreSize = 0;
7131 font->potm->otmsUnderscorePosition = 0;
7132 } else {
7133 font->potm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
7134 font->potm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
7136 #undef SCALE_X
7137 #undef SCALE_Y
7138 #undef TM
7140 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7141 cp = (char*)font->potm + sizeof(*font->potm);
7142 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
7143 strcpyW((WCHAR*)cp, family_nameW);
7144 cp += lenfam;
7145 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
7146 strcpyW((WCHAR*)cp, style_nameW);
7147 cp += lensty;
7148 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7149 strcpyW((WCHAR*)cp, face_nameW);
7150 cp += lenface;
7151 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
7152 strcpyW((WCHAR*)cp, full_nameW);
7153 ret = TRUE;
7155 end:
7156 HeapFree(GetProcessHeap(), 0, style_nameW);
7157 HeapFree(GetProcessHeap(), 0, family_nameW);
7158 HeapFree(GetProcessHeap(), 0, face_nameW);
7159 HeapFree(GetProcessHeap(), 0, full_nameW);
7160 return ret;
7163 /*************************************************************
7164 * freetype_GetGlyphOutline
7166 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
7167 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7169 struct freetype_physdev *physdev = get_freetype_dev( dev );
7170 DWORD ret;
7171 ABC abc;
7173 if (!physdev->font)
7175 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
7176 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
7179 GDI_CheckNotLock();
7180 EnterCriticalSection( &freetype_cs );
7181 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
7182 LeaveCriticalSection( &freetype_cs );
7183 return ret;
7186 /*************************************************************
7187 * freetype_GetTextMetrics
7189 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
7191 struct freetype_physdev *physdev = get_freetype_dev( dev );
7192 BOOL ret;
7194 if (!physdev->font)
7196 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
7197 return dev->funcs->pGetTextMetrics( dev, metrics );
7200 GDI_CheckNotLock();
7201 EnterCriticalSection( &freetype_cs );
7202 ret = get_text_metrics( physdev->font, metrics );
7203 LeaveCriticalSection( &freetype_cs );
7204 return ret;
7207 /*************************************************************
7208 * freetype_GetOutlineTextMetrics
7210 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
7212 struct freetype_physdev *physdev = get_freetype_dev( dev );
7213 UINT ret = 0;
7215 if (!physdev->font)
7217 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
7218 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
7221 TRACE("font=%p\n", physdev->font);
7223 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
7225 GDI_CheckNotLock();
7226 EnterCriticalSection( &freetype_cs );
7228 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
7230 if(cbSize >= physdev->font->potm->otmSize)
7232 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
7233 scale_outline_font_metrics(physdev->font, potm);
7235 ret = physdev->font->potm->otmSize;
7237 LeaveCriticalSection( &freetype_cs );
7238 return ret;
7241 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
7243 child->font = alloc_font();
7244 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
7245 if(!child->font->ft_face)
7247 free_font(child->font);
7248 child->font = NULL;
7249 return FALSE;
7252 child->font->font_desc = font->font_desc;
7253 child->font->ntmFlags = child->face->ntmFlags;
7254 child->font->orientation = font->orientation;
7255 child->font->scale_y = font->scale_y;
7256 child->font->name = strdupW(child->face->family->FamilyName);
7257 child->font->base_font = font;
7258 TRACE("created child font %p for base %p\n", child->font, font);
7259 return TRUE;
7262 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
7264 FT_UInt g;
7265 CHILD_FONT *child_font;
7267 if(font->base_font)
7268 font = font->base_font;
7270 *linked_font = font;
7272 if((*glyph = get_glyph_index(font, c)))
7274 *glyph = get_GSUB_vert_glyph(font, *glyph);
7275 return TRUE;
7278 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7280 if(!child_font->font)
7281 if(!load_child_font(font, child_font))
7282 continue;
7284 if(!child_font->font->ft_face)
7285 continue;
7286 g = get_glyph_index(child_font->font, c);
7287 g = get_GSUB_vert_glyph(child_font->font, g);
7288 if(g)
7290 *glyph = g;
7291 *linked_font = child_font->font;
7292 return TRUE;
7295 return FALSE;
7298 /*************************************************************
7299 * freetype_GetCharWidth
7301 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7303 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7304 UINT c;
7305 GLYPHMETRICS gm;
7306 ABC abc;
7307 struct freetype_physdev *physdev = get_freetype_dev( dev );
7309 if (!physdev->font)
7311 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7312 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7315 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7317 GDI_CheckNotLock();
7318 EnterCriticalSection( &freetype_cs );
7319 for(c = firstChar; c <= lastChar; c++) {
7320 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7321 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
7323 LeaveCriticalSection( &freetype_cs );
7324 return TRUE;
7327 /*************************************************************
7328 * freetype_GetCharABCWidths
7330 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7332 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7333 UINT c;
7334 GLYPHMETRICS gm;
7335 struct freetype_physdev *physdev = get_freetype_dev( dev );
7337 if (!physdev->font)
7339 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7340 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7343 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7345 GDI_CheckNotLock();
7346 EnterCriticalSection( &freetype_cs );
7348 for(c = firstChar; c <= lastChar; c++, buffer++)
7349 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
7351 LeaveCriticalSection( &freetype_cs );
7352 return TRUE;
7355 /*************************************************************
7356 * freetype_GetCharABCWidthsI
7358 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7360 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7361 UINT c;
7362 GLYPHMETRICS gm;
7363 struct freetype_physdev *physdev = get_freetype_dev( dev );
7365 if (!physdev->font)
7367 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7368 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7371 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7372 return FALSE;
7374 GDI_CheckNotLock();
7375 EnterCriticalSection( &freetype_cs );
7377 for(c = 0; c < count; c++, buffer++)
7378 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
7379 &gm, buffer, 0, NULL, &identity );
7381 LeaveCriticalSection( &freetype_cs );
7382 return TRUE;
7385 /*************************************************************
7386 * freetype_GetTextExtentExPoint
7388 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
7390 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7391 INT idx, pos;
7392 ABC abc;
7393 GLYPHMETRICS gm;
7394 struct freetype_physdev *physdev = get_freetype_dev( dev );
7396 if (!physdev->font)
7398 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7399 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
7402 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
7404 GDI_CheckNotLock();
7405 EnterCriticalSection( &freetype_cs );
7407 for (idx = pos = 0; idx < count; idx++)
7409 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7410 pos += abc.abcA + abc.abcB + abc.abcC;
7411 dxs[idx] = pos;
7414 LeaveCriticalSection( &freetype_cs );
7415 return TRUE;
7418 /*************************************************************
7419 * freetype_GetTextExtentExPointI
7421 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
7423 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7424 INT idx, pos;
7425 ABC abc;
7426 GLYPHMETRICS gm;
7427 struct freetype_physdev *physdev = get_freetype_dev( dev );
7429 if (!physdev->font)
7431 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7432 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
7435 TRACE("%p, %p, %d\n", physdev->font, indices, count);
7437 GDI_CheckNotLock();
7438 EnterCriticalSection( &freetype_cs );
7440 for (idx = pos = 0; idx < count; idx++)
7442 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
7443 &gm, &abc, 0, NULL, &identity );
7444 pos += abc.abcA + abc.abcB + abc.abcC;
7445 dxs[idx] = pos;
7448 LeaveCriticalSection( &freetype_cs );
7449 return TRUE;
7452 /*************************************************************
7453 * freetype_GetFontData
7455 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7457 struct freetype_physdev *physdev = get_freetype_dev( dev );
7459 if (!physdev->font)
7461 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7462 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7465 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7466 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7467 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7469 return get_font_data( physdev->font, table, offset, buf, cbData );
7472 /*************************************************************
7473 * freetype_GetTextFace
7475 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7477 INT n;
7478 struct freetype_physdev *physdev = get_freetype_dev( dev );
7480 if (!physdev->font)
7482 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7483 return dev->funcs->pGetTextFace( dev, count, str );
7486 n = strlenW(physdev->font->name) + 1;
7487 if (str)
7489 lstrcpynW(str, physdev->font->name, count);
7490 n = min(count, n);
7492 return n;
7495 /*************************************************************
7496 * freetype_GetTextCharsetInfo
7498 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7500 struct freetype_physdev *physdev = get_freetype_dev( dev );
7502 if (!physdev->font)
7504 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7505 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7507 if (fs) *fs = physdev->font->fs;
7508 return physdev->font->charset;
7511 /* Retrieve a list of supported Unicode ranges for a given font.
7512 * Can be called with NULL gs to calculate the buffer size. Returns
7513 * the number of ranges found.
7515 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7517 DWORD num_ranges = 0;
7519 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7521 FT_UInt glyph_code;
7522 FT_ULong char_code, char_code_prev;
7524 glyph_code = 0;
7525 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7527 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7528 face->num_glyphs, glyph_code, char_code);
7530 if (!glyph_code) return 0;
7532 if (gs)
7534 gs->ranges[0].wcLow = (USHORT)char_code;
7535 gs->ranges[0].cGlyphs = 0;
7536 gs->cGlyphsSupported = 0;
7539 num_ranges = 1;
7540 while (glyph_code)
7542 if (char_code < char_code_prev)
7544 ERR("expected increasing char code from FT_Get_Next_Char\n");
7545 return 0;
7547 if (char_code - char_code_prev > 1)
7549 num_ranges++;
7550 if (gs)
7552 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7553 gs->ranges[num_ranges - 1].cGlyphs = 1;
7554 gs->cGlyphsSupported++;
7557 else if (gs)
7559 gs->ranges[num_ranges - 1].cGlyphs++;
7560 gs->cGlyphsSupported++;
7562 char_code_prev = char_code;
7563 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7566 else
7567 FIXME("encoding %u not supported\n", face->charmap->encoding);
7569 return num_ranges;
7572 /*************************************************************
7573 * freetype_GetFontUnicodeRanges
7575 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7577 struct freetype_physdev *physdev = get_freetype_dev( dev );
7578 DWORD size, num_ranges;
7580 if (!physdev->font)
7582 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7583 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7586 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7587 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7588 if (glyphset)
7590 glyphset->cbThis = size;
7591 glyphset->cRanges = num_ranges;
7592 glyphset->flAccel = 0;
7594 return size;
7597 /*************************************************************
7598 * freetype_FontIsLinked
7600 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7602 struct freetype_physdev *physdev = get_freetype_dev( dev );
7603 BOOL ret;
7605 if (!physdev->font)
7607 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7608 return dev->funcs->pFontIsLinked( dev );
7611 GDI_CheckNotLock();
7612 EnterCriticalSection( &freetype_cs );
7613 ret = !list_empty(&physdev->font->child_fonts);
7614 LeaveCriticalSection( &freetype_cs );
7615 return ret;
7618 /*************************************************************************
7619 * GetRasterizerCaps (GDI32.@)
7621 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7623 lprs->nSize = sizeof(RASTERIZER_STATUS);
7624 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
7625 lprs->nLanguageID = 0;
7626 return TRUE;
7629 /*************************************************************
7630 * freetype_GdiRealizationInfo
7632 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7634 struct freetype_physdev *physdev = get_freetype_dev( dev );
7635 realization_info_t *info = ptr;
7637 if (!physdev->font)
7639 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7640 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7643 FIXME("(%p, %p): stub!\n", physdev->font, info);
7645 info->flags = 1;
7646 if(FT_IS_SCALABLE(physdev->font->ft_face))
7647 info->flags |= 2;
7649 info->cache_num = physdev->font->cache_num;
7650 info->unknown2 = -1;
7651 return TRUE;
7654 /*************************************************************************
7655 * Kerning support for TrueType fonts
7657 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7659 struct TT_kern_table
7661 USHORT version;
7662 USHORT nTables;
7665 struct TT_kern_subtable
7667 USHORT version;
7668 USHORT length;
7669 union
7671 USHORT word;
7672 struct
7674 USHORT horizontal : 1;
7675 USHORT minimum : 1;
7676 USHORT cross_stream: 1;
7677 USHORT override : 1;
7678 USHORT reserved1 : 4;
7679 USHORT format : 8;
7680 } bits;
7681 } coverage;
7684 struct TT_format0_kern_subtable
7686 USHORT nPairs;
7687 USHORT searchRange;
7688 USHORT entrySelector;
7689 USHORT rangeShift;
7692 struct TT_kern_pair
7694 USHORT left;
7695 USHORT right;
7696 short value;
7699 static DWORD parse_format0_kern_subtable(GdiFont *font,
7700 const struct TT_format0_kern_subtable *tt_f0_ks,
7701 const USHORT *glyph_to_char,
7702 KERNINGPAIR *kern_pair, DWORD cPairs)
7704 USHORT i, nPairs;
7705 const struct TT_kern_pair *tt_kern_pair;
7707 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7709 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7711 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7712 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7713 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7715 if (!kern_pair || !cPairs)
7716 return nPairs;
7718 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7720 nPairs = min(nPairs, cPairs);
7722 for (i = 0; i < nPairs; i++)
7724 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7725 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7726 /* this algorithm appears to better match what Windows does */
7727 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7728 if (kern_pair->iKernAmount < 0)
7730 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7731 kern_pair->iKernAmount -= font->ppem;
7733 else if (kern_pair->iKernAmount > 0)
7735 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7736 kern_pair->iKernAmount += font->ppem;
7738 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7740 TRACE("left %u right %u value %d\n",
7741 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7743 kern_pair++;
7745 TRACE("copied %u entries\n", nPairs);
7746 return nPairs;
7749 /*************************************************************
7750 * freetype_GetKerningPairs
7752 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7754 DWORD length;
7755 void *buf;
7756 const struct TT_kern_table *tt_kern_table;
7757 const struct TT_kern_subtable *tt_kern_subtable;
7758 USHORT i, nTables;
7759 USHORT *glyph_to_char;
7760 GdiFont *font;
7761 struct freetype_physdev *physdev = get_freetype_dev( dev );
7763 if (!(font = physdev->font))
7765 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7766 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7769 GDI_CheckNotLock();
7770 EnterCriticalSection( &freetype_cs );
7771 if (font->total_kern_pairs != (DWORD)-1)
7773 if (cPairs && kern_pair)
7775 cPairs = min(cPairs, font->total_kern_pairs);
7776 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7778 else cPairs = font->total_kern_pairs;
7780 LeaveCriticalSection( &freetype_cs );
7781 return cPairs;
7784 font->total_kern_pairs = 0;
7786 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7788 if (length == GDI_ERROR)
7790 TRACE("no kerning data in the font\n");
7791 LeaveCriticalSection( &freetype_cs );
7792 return 0;
7795 buf = HeapAlloc(GetProcessHeap(), 0, length);
7796 if (!buf)
7798 WARN("Out of memory\n");
7799 LeaveCriticalSection( &freetype_cs );
7800 return 0;
7803 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7805 /* build a glyph index to char code map */
7806 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7807 if (!glyph_to_char)
7809 WARN("Out of memory allocating a glyph index to char code map\n");
7810 HeapFree(GetProcessHeap(), 0, buf);
7811 LeaveCriticalSection( &freetype_cs );
7812 return 0;
7815 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7817 FT_UInt glyph_code;
7818 FT_ULong char_code;
7820 glyph_code = 0;
7821 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7823 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7824 font->ft_face->num_glyphs, glyph_code, char_code);
7826 while (glyph_code)
7828 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7830 /* FIXME: This doesn't match what Windows does: it does some fancy
7831 * things with duplicate glyph index to char code mappings, while
7832 * we just avoid overriding existing entries.
7834 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7835 glyph_to_char[glyph_code] = (USHORT)char_code;
7837 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7840 else
7842 ULONG n;
7844 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7845 for (n = 0; n <= 65535; n++)
7846 glyph_to_char[n] = (USHORT)n;
7849 tt_kern_table = buf;
7850 nTables = GET_BE_WORD(tt_kern_table->nTables);
7851 TRACE("version %u, nTables %u\n",
7852 GET_BE_WORD(tt_kern_table->version), nTables);
7854 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7856 for (i = 0; i < nTables; i++)
7858 struct TT_kern_subtable tt_kern_subtable_copy;
7860 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7861 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7862 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7864 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7865 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7866 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7868 /* According to the TrueType specification this is the only format
7869 * that will be properly interpreted by Windows and OS/2
7871 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7873 DWORD new_chunk, old_total = font->total_kern_pairs;
7875 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7876 glyph_to_char, NULL, 0);
7877 font->total_kern_pairs += new_chunk;
7879 if (!font->kern_pairs)
7880 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7881 font->total_kern_pairs * sizeof(*font->kern_pairs));
7882 else
7883 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7884 font->total_kern_pairs * sizeof(*font->kern_pairs));
7886 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7887 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7889 else
7890 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7892 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7895 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7896 HeapFree(GetProcessHeap(), 0, buf);
7898 if (cPairs && kern_pair)
7900 cPairs = min(cPairs, font->total_kern_pairs);
7901 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7903 else cPairs = font->total_kern_pairs;
7905 LeaveCriticalSection( &freetype_cs );
7906 return cPairs;
7909 static const struct gdi_dc_funcs freetype_funcs =
7911 NULL, /* pAbortDoc */
7912 NULL, /* pAbortPath */
7913 NULL, /* pAlphaBlend */
7914 NULL, /* pAngleArc */
7915 NULL, /* pArc */
7916 NULL, /* pArcTo */
7917 NULL, /* pBeginPath */
7918 NULL, /* pBlendImage */
7919 NULL, /* pChord */
7920 NULL, /* pCloseFigure */
7921 NULL, /* pCreateCompatibleDC */
7922 freetype_CreateDC, /* pCreateDC */
7923 freetype_DeleteDC, /* pDeleteDC */
7924 NULL, /* pDeleteObject */
7925 NULL, /* pDeviceCapabilities */
7926 NULL, /* pEllipse */
7927 NULL, /* pEndDoc */
7928 NULL, /* pEndPage */
7929 NULL, /* pEndPath */
7930 freetype_EnumFonts, /* pEnumFonts */
7931 NULL, /* pEnumICMProfiles */
7932 NULL, /* pExcludeClipRect */
7933 NULL, /* pExtDeviceMode */
7934 NULL, /* pExtEscape */
7935 NULL, /* pExtFloodFill */
7936 NULL, /* pExtSelectClipRgn */
7937 NULL, /* pExtTextOut */
7938 NULL, /* pFillPath */
7939 NULL, /* pFillRgn */
7940 NULL, /* pFlattenPath */
7941 freetype_FontIsLinked, /* pFontIsLinked */
7942 NULL, /* pFrameRgn */
7943 NULL, /* pGdiComment */
7944 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7945 NULL, /* pGetBoundsRect */
7946 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7947 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7948 freetype_GetCharWidth, /* pGetCharWidth */
7949 NULL, /* pGetDeviceCaps */
7950 NULL, /* pGetDeviceGammaRamp */
7951 freetype_GetFontData, /* pGetFontData */
7952 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7953 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7954 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7955 NULL, /* pGetICMProfile */
7956 NULL, /* pGetImage */
7957 freetype_GetKerningPairs, /* pGetKerningPairs */
7958 NULL, /* pGetNearestColor */
7959 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7960 NULL, /* pGetPixel */
7961 NULL, /* pGetSystemPaletteEntries */
7962 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7963 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7964 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7965 freetype_GetTextFace, /* pGetTextFace */
7966 freetype_GetTextMetrics, /* pGetTextMetrics */
7967 NULL, /* pGradientFill */
7968 NULL, /* pIntersectClipRect */
7969 NULL, /* pInvertRgn */
7970 NULL, /* pLineTo */
7971 NULL, /* pModifyWorldTransform */
7972 NULL, /* pMoveTo */
7973 NULL, /* pOffsetClipRgn */
7974 NULL, /* pOffsetViewportOrg */
7975 NULL, /* pOffsetWindowOrg */
7976 NULL, /* pPaintRgn */
7977 NULL, /* pPatBlt */
7978 NULL, /* pPie */
7979 NULL, /* pPolyBezier */
7980 NULL, /* pPolyBezierTo */
7981 NULL, /* pPolyDraw */
7982 NULL, /* pPolyPolygon */
7983 NULL, /* pPolyPolyline */
7984 NULL, /* pPolygon */
7985 NULL, /* pPolyline */
7986 NULL, /* pPolylineTo */
7987 NULL, /* pPutImage */
7988 NULL, /* pRealizeDefaultPalette */
7989 NULL, /* pRealizePalette */
7990 NULL, /* pRectangle */
7991 NULL, /* pResetDC */
7992 NULL, /* pRestoreDC */
7993 NULL, /* pRoundRect */
7994 NULL, /* pSaveDC */
7995 NULL, /* pScaleViewportExt */
7996 NULL, /* pScaleWindowExt */
7997 NULL, /* pSelectBitmap */
7998 NULL, /* pSelectBrush */
7999 NULL, /* pSelectClipPath */
8000 freetype_SelectFont, /* pSelectFont */
8001 NULL, /* pSelectPalette */
8002 NULL, /* pSelectPen */
8003 NULL, /* pSetArcDirection */
8004 NULL, /* pSetBkColor */
8005 NULL, /* pSetBkMode */
8006 NULL, /* pSetDCBrushColor */
8007 NULL, /* pSetDCPenColor */
8008 NULL, /* pSetDIBColorTable */
8009 NULL, /* pSetDIBitsToDevice */
8010 NULL, /* pSetDeviceClipping */
8011 NULL, /* pSetDeviceGammaRamp */
8012 NULL, /* pSetLayout */
8013 NULL, /* pSetMapMode */
8014 NULL, /* pSetMapperFlags */
8015 NULL, /* pSetPixel */
8016 NULL, /* pSetPolyFillMode */
8017 NULL, /* pSetROP2 */
8018 NULL, /* pSetRelAbs */
8019 NULL, /* pSetStretchBltMode */
8020 NULL, /* pSetTextAlign */
8021 NULL, /* pSetTextCharacterExtra */
8022 NULL, /* pSetTextColor */
8023 NULL, /* pSetTextJustification */
8024 NULL, /* pSetViewportExt */
8025 NULL, /* pSetViewportOrg */
8026 NULL, /* pSetWindowExt */
8027 NULL, /* pSetWindowOrg */
8028 NULL, /* pSetWorldTransform */
8029 NULL, /* pStartDoc */
8030 NULL, /* pStartPage */
8031 NULL, /* pStretchBlt */
8032 NULL, /* pStretchDIBits */
8033 NULL, /* pStrokeAndFillPath */
8034 NULL, /* pStrokePath */
8035 NULL, /* pUnrealizePalette */
8036 NULL, /* pWidenPath */
8037 NULL, /* wine_get_wgl_driver */
8038 GDI_PRIORITY_FONT_DRV /* priority */
8041 #else /* HAVE_FREETYPE */
8043 /*************************************************************************/
8045 BOOL WineEngInit(void)
8047 return FALSE;
8050 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8052 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8053 return 1;
8056 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8058 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8059 return TRUE;
8062 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
8064 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
8065 return NULL;
8068 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
8069 LPCWSTR font_file, LPCWSTR font_path )
8071 FIXME("stub\n");
8072 return FALSE;
8075 /*************************************************************************
8076 * GetRasterizerCaps (GDI32.@)
8078 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8080 lprs->nSize = sizeof(RASTERIZER_STATUS);
8081 lprs->wFlags = 0;
8082 lprs->nLanguageID = 0;
8083 return TRUE;
8086 #endif /* HAVE_FREETYPE */