gdi32: Fix Tategaki rotation.
[wine.git] / dlls / gdi32 / freetype.c
blob459f49a6d5e9e6a5bfa0d8b638af0b55ffb6d620
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 static FT_UInt get_default_char_index(GdiFont *font)
5822 FT_UInt default_char;
5824 if (FT_IS_SFNT(font->ft_face))
5826 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
5827 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
5829 else
5831 TEXTMETRICW textm;
5832 get_text_metrics(font, &textm);
5833 default_char = textm.tmDefaultChar;
5836 return default_char;
5839 /*************************************************************
5840 * freetype_GetGlyphIndices
5842 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5844 struct freetype_physdev *physdev = get_freetype_dev( dev );
5845 int i;
5846 WORD default_char;
5847 BOOL got_default = FALSE;
5849 if (!physdev->font)
5851 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5852 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5855 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5857 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5858 got_default = TRUE;
5861 GDI_CheckNotLock();
5862 EnterCriticalSection( &freetype_cs );
5864 for(i = 0; i < count; i++)
5866 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5867 if (pgi[i] == 0)
5869 if (!got_default)
5871 default_char = get_default_char_index(physdev->font);
5872 got_default = TRUE;
5874 pgi[i] = default_char;
5876 else
5877 pgi[i] = get_GSUB_vert_glyph(physdev->font, pgi[i]);
5879 LeaveCriticalSection( &freetype_cs );
5880 return count;
5883 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5885 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5886 return !memcmp(matrix, &identity, sizeof(FMAT2));
5889 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5891 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5892 return !memcmp(matrix, &identity, sizeof(MAT2));
5895 static inline BYTE get_max_level( UINT format )
5897 switch( format )
5899 case GGO_GRAY2_BITMAP: return 4;
5900 case GGO_GRAY4_BITMAP: return 16;
5901 case GGO_GRAY8_BITMAP: return 64;
5903 return 255;
5906 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5908 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5909 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
5910 const MAT2* lpmat)
5912 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5913 FT_Face ft_face = incoming_font->ft_face;
5914 GdiFont *font = incoming_font;
5915 FT_Glyph_Metrics metrics;
5916 FT_UInt glyph_index;
5917 DWORD width, height, pitch, needed = 0;
5918 FT_Bitmap ft_bitmap;
5919 FT_Error err;
5920 INT left, right, top = 0, bottom = 0, adv;
5921 FT_Angle angle = 0;
5922 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5923 double widthRatio = 1.0;
5924 FT_Matrix transMat = identityMat;
5925 FT_Matrix transMatUnrotated;
5926 FT_Matrix transMatTategaki;
5927 BOOL needsTransform = FALSE;
5928 BOOL tategaki = (font->name[0] == '@');
5929 UINT original_index;
5930 LONG avgAdvance = 0;
5931 FT_Fixed em_scale;
5933 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5934 buflen, buf, lpmat);
5936 TRACE("font transform %f %f %f %f\n",
5937 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5938 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5940 if(format & GGO_GLYPH_INDEX) {
5941 glyph_index = glyph;
5942 original_index = glyph;
5943 format &= ~GGO_GLYPH_INDEX;
5944 } else {
5945 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5946 ft_face = font->ft_face;
5947 original_index = glyph_index;
5950 if(format & GGO_UNHINTED) {
5951 load_flags |= FT_LOAD_NO_HINTING;
5952 format &= ~GGO_UNHINTED;
5955 /* tategaki never appears to happen to lower glyph index */
5956 if (glyph_index < TATEGAKI_LOWER_BOUND )
5957 tategaki = FALSE;
5959 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5960 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5961 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5962 font->gmsize * sizeof(GM*));
5963 } else {
5964 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5965 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5967 *lpgm = FONT_GM(font,original_index)->gm;
5968 *abc = FONT_GM(font,original_index)->abc;
5969 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5970 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5971 lpgm->gmCellIncX, lpgm->gmCellIncY);
5972 return 1; /* FIXME */
5976 if (!font->gm[original_index / GM_BLOCK_SIZE])
5977 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5979 /* Scaling factor */
5980 if (font->aveWidth)
5982 TEXTMETRICW tm;
5984 get_text_metrics(font, &tm);
5986 widthRatio = (double)font->aveWidth;
5987 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5989 else
5990 widthRatio = font->scale_y;
5992 /* Scaling transform */
5993 if (widthRatio != 1.0 || font->scale_y != 1.0)
5995 FT_Matrix scaleMat;
5996 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5997 scaleMat.xy = 0;
5998 scaleMat.yx = 0;
5999 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
6001 pFT_Matrix_Multiply(&scaleMat, &transMat);
6002 needsTransform = TRUE;
6005 /* Slant transform */
6006 if (font->fake_italic) {
6007 FT_Matrix slantMat;
6009 slantMat.xx = (1 << 16);
6010 slantMat.xy = ((1 << 16) >> 2);
6011 slantMat.yx = 0;
6012 slantMat.yy = (1 << 16);
6013 pFT_Matrix_Multiply(&slantMat, &transMat);
6014 needsTransform = TRUE;
6017 /* Rotation transform */
6018 transMatUnrotated = transMat;
6019 transMatTategaki = transMat;
6020 if(font->orientation || tategaki) {
6021 FT_Matrix rotationMat;
6022 FT_Matrix taterotationMat;
6023 FT_Vector vecAngle;
6025 double orient = font->orientation / 10.0;
6026 double tate_orient = 0.f;
6028 if (tategaki)
6029 tate_orient = ((font->orientation+900)%3600)/10.0;
6030 else
6031 tate_orient = font->orientation/10.0;
6033 if (orient)
6035 angle = FT_FixedFromFloat(orient);
6036 pFT_Vector_Unit(&vecAngle, angle);
6037 rotationMat.xx = vecAngle.x;
6038 rotationMat.xy = -vecAngle.y;
6039 rotationMat.yx = -rotationMat.xy;
6040 rotationMat.yy = rotationMat.xx;
6042 pFT_Matrix_Multiply(&rotationMat, &transMat);
6045 if (tate_orient)
6047 angle = FT_FixedFromFloat(tate_orient);
6048 pFT_Vector_Unit(&vecAngle, angle);
6049 taterotationMat.xx = vecAngle.x;
6050 taterotationMat.xy = -vecAngle.y;
6051 taterotationMat.yx = -taterotationMat.xy;
6052 taterotationMat.yy = taterotationMat.xx;
6053 pFT_Matrix_Multiply(&taterotationMat, &transMatTategaki);
6056 needsTransform = TRUE;
6059 /* World transform */
6060 if (!is_identity_FMAT2(&font->font_desc.matrix))
6062 FT_Matrix worldMat;
6063 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
6064 worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21);
6065 worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12);
6066 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
6067 pFT_Matrix_Multiply(&worldMat, &transMat);
6068 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
6069 pFT_Matrix_Multiply(&worldMat, &transMatTategaki);
6070 needsTransform = TRUE;
6073 /* Extra transformation specified by caller */
6074 if (!is_identity_MAT2(lpmat))
6076 FT_Matrix extraMat;
6077 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
6078 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
6079 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
6080 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
6081 pFT_Matrix_Multiply(&extraMat, &transMat);
6082 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
6083 pFT_Matrix_Multiply(&extraMat, &transMatTategaki);
6084 needsTransform = TRUE;
6087 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
6089 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
6091 if(err) {
6092 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
6093 return GDI_ERROR;
6096 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6097 * by the text metrics. The proper behavior is to clip the glyph metrics to
6098 * fit within the maximums specified in the text metrics. */
6099 metrics = ft_face->glyph->metrics;
6100 if(incoming_font->potm || get_outline_text_metrics(incoming_font) ||
6101 get_bitmap_text_metrics(incoming_font)) {
6102 TEXTMETRICW *ptm = &incoming_font->potm->otmTextMetrics;
6103 top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
6104 bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
6105 metrics.horiBearingY = top;
6106 metrics.height = top - bottom;
6108 /* TODO: Are we supposed to clip the width as well...? */
6109 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6112 if(FT_IS_SCALABLE(incoming_font->ft_face)) {
6113 TEXTMETRICW tm;
6114 if (get_text_metrics(incoming_font, &tm) &&
6115 !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
6116 em_scale = MulDiv(incoming_font->ppem, 1 << 16, incoming_font->ft_face->units_per_EM);
6117 avgAdvance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
6118 if (avgAdvance &&
6119 (metrics.horiAdvance+63) >> 6 == pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale))
6120 TRACE("Fixed-pitch full-width character detected\n");
6121 else
6122 avgAdvance = 0; /* cancel this feature */
6126 if(!needsTransform) {
6127 left = (INT)(metrics.horiBearingX) & -64;
6128 right = (INT)((metrics.horiBearingX + metrics.width) + 63) & -64;
6129 if (!avgAdvance)
6130 adv = (INT)(metrics.horiAdvance + 63) >> 6;
6131 else
6132 adv = (INT)avgAdvance * 2;
6134 top = (metrics.horiBearingY + 63) & -64;
6135 bottom = (metrics.horiBearingY - metrics.height) & -64;
6136 lpgm->gmCellIncX = adv;
6137 lpgm->gmCellIncY = 0;
6138 } else {
6139 INT xc, yc;
6140 FT_Vector vec;
6142 left = right = 0;
6144 for(xc = 0; xc < 2; xc++) {
6145 for(yc = 0; yc < 2; yc++) {
6146 vec.x = metrics.horiBearingX + xc * metrics.width;
6147 vec.y = metrics.horiBearingY - yc * metrics.height;
6148 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
6149 pFT_Vector_Transform(&vec, &transMatTategaki);
6150 if(xc == 0 && yc == 0) {
6151 left = right = vec.x;
6152 top = bottom = vec.y;
6153 } else {
6154 if(vec.x < left) left = vec.x;
6155 else if(vec.x > right) right = vec.x;
6156 if(vec.y < bottom) bottom = vec.y;
6157 else if(vec.y > top) top = vec.y;
6161 left = left & -64;
6162 right = (right + 63) & -64;
6163 bottom = bottom & -64;
6164 top = (top + 63) & -64;
6166 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
6167 vec.x = metrics.horiAdvance;
6168 vec.y = 0;
6169 pFT_Vector_Transform(&vec, &transMat);
6170 lpgm->gmCellIncY = -((vec.y+63) >> 6);
6171 if (!avgAdvance || vec.y)
6172 lpgm->gmCellIncX = (vec.x+63) >> 6;
6173 else {
6174 vec.x = incoming_font->ntmAvgWidth;
6175 vec.y = 0;
6176 pFT_Vector_Transform(&vec, &transMat);
6177 lpgm->gmCellIncX = pFT_MulFix(vec.x, em_scale) * 2;
6180 vec.x = metrics.horiAdvance;
6181 vec.y = 0;
6182 pFT_Vector_Transform(&vec, &transMatUnrotated);
6183 if (!avgAdvance || vec.y)
6184 adv = (vec.x+63) >> 6;
6185 else {
6186 vec.x = incoming_font->ntmAvgWidth;
6187 vec.y = 0;
6188 pFT_Vector_Transform(&vec, &transMatUnrotated);
6189 adv = pFT_MulFix(vec.x, em_scale) * 2;
6193 lpgm->gmBlackBoxX = (right - left) >> 6;
6194 lpgm->gmBlackBoxY = (top - bottom) >> 6;
6195 lpgm->gmptGlyphOrigin.x = left >> 6;
6196 lpgm->gmptGlyphOrigin.y = top >> 6;
6197 abc->abcA = left >> 6;
6198 abc->abcB = (right - left) >> 6;
6199 abc->abcC = adv - abc->abcA - abc->abcB;
6201 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6202 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6203 lpgm->gmCellIncX, lpgm->gmCellIncY);
6205 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
6206 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
6208 FONT_GM(font,original_index)->gm = *lpgm;
6209 FONT_GM(font,original_index)->abc = *abc;
6210 FONT_GM(font,original_index)->init = TRUE;
6213 if(format == GGO_METRICS)
6215 return 1; /* FIXME */
6218 if(ft_face->glyph->format != ft_glyph_format_outline &&
6219 (format == GGO_NATIVE || format == GGO_BEZIER))
6221 TRACE("loaded a bitmap\n");
6222 return GDI_ERROR;
6225 switch(format) {
6226 case GGO_BITMAP:
6227 width = lpgm->gmBlackBoxX;
6228 height = lpgm->gmBlackBoxY;
6229 pitch = ((width + 31) >> 5) << 2;
6230 needed = pitch * height;
6232 if(!buf || !buflen) break;
6234 switch(ft_face->glyph->format) {
6235 case ft_glyph_format_bitmap:
6237 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6238 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
6239 INT h = min( height, ft_face->glyph->bitmap.rows );
6240 while(h--) {
6241 memcpy(dst, src, w);
6242 src += ft_face->glyph->bitmap.pitch;
6243 dst += pitch;
6245 break;
6248 case ft_glyph_format_outline:
6249 ft_bitmap.width = width;
6250 ft_bitmap.rows = height;
6251 ft_bitmap.pitch = pitch;
6252 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
6253 ft_bitmap.buffer = buf;
6255 if(needsTransform)
6256 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
6258 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6260 /* Note: FreeType will only set 'black' bits for us. */
6261 memset(buf, 0, needed);
6262 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6263 break;
6265 default:
6266 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6267 return GDI_ERROR;
6269 break;
6271 case GGO_GRAY2_BITMAP:
6272 case GGO_GRAY4_BITMAP:
6273 case GGO_GRAY8_BITMAP:
6274 case WINE_GGO_GRAY16_BITMAP:
6276 unsigned int max_level, row, col;
6277 BYTE *start, *ptr;
6279 width = lpgm->gmBlackBoxX;
6280 height = lpgm->gmBlackBoxY;
6281 pitch = (width + 3) / 4 * 4;
6282 needed = pitch * height;
6284 if(!buf || !buflen) break;
6286 max_level = get_max_level( format );
6288 switch(ft_face->glyph->format) {
6289 case ft_glyph_format_bitmap:
6291 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6292 INT h = min( height, ft_face->glyph->bitmap.rows );
6293 INT x;
6294 memset( buf, 0, needed );
6295 while(h--) {
6296 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
6297 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
6298 src += ft_face->glyph->bitmap.pitch;
6299 dst += pitch;
6301 return needed;
6303 case ft_glyph_format_outline:
6305 ft_bitmap.width = width;
6306 ft_bitmap.rows = height;
6307 ft_bitmap.pitch = pitch;
6308 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6309 ft_bitmap.buffer = buf;
6311 if(needsTransform)
6312 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
6314 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6316 memset(ft_bitmap.buffer, 0, buflen);
6318 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6320 if (max_level != 255)
6322 for (row = 0, start = buf; row < height; row++)
6324 for (col = 0, ptr = start; col < width; col++, ptr++)
6325 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6326 start += pitch;
6329 return needed;
6332 default:
6333 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6334 return GDI_ERROR;
6336 break;
6339 case WINE_GGO_HRGB_BITMAP:
6340 case WINE_GGO_HBGR_BITMAP:
6341 case WINE_GGO_VRGB_BITMAP:
6342 case WINE_GGO_VBGR_BITMAP:
6343 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6345 switch (ft_face->glyph->format)
6347 case FT_GLYPH_FORMAT_BITMAP:
6349 BYTE *src, *dst;
6350 INT src_pitch, x;
6352 width = lpgm->gmBlackBoxX;
6353 height = lpgm->gmBlackBoxY;
6354 pitch = width * 4;
6355 needed = pitch * height;
6357 if (!buf || !buflen) break;
6359 memset(buf, 0, buflen);
6360 dst = buf;
6361 src = ft_face->glyph->bitmap.buffer;
6362 src_pitch = ft_face->glyph->bitmap.pitch;
6364 height = min( height, ft_face->glyph->bitmap.rows );
6365 while ( height-- )
6367 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6369 if ( src[x / 8] & masks[x % 8] )
6370 ((unsigned int *)dst)[x] = ~0u;
6372 src += src_pitch;
6373 dst += pitch;
6376 break;
6379 case FT_GLYPH_FORMAT_OUTLINE:
6381 unsigned int *dst;
6382 BYTE *src;
6383 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6384 INT x_shift, y_shift;
6385 BOOL rgb;
6386 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6387 FT_Render_Mode render_mode =
6388 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6389 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6391 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6393 if ( render_mode == FT_RENDER_MODE_LCD)
6395 lpgm->gmBlackBoxX += 2;
6396 lpgm->gmptGlyphOrigin.x -= 1;
6398 else
6400 lpgm->gmBlackBoxY += 2;
6401 lpgm->gmptGlyphOrigin.y += 1;
6405 width = lpgm->gmBlackBoxX;
6406 height = lpgm->gmBlackBoxY;
6407 pitch = width * 4;
6408 needed = pitch * height;
6410 if (!buf || !buflen) break;
6412 memset(buf, 0, buflen);
6413 dst = buf;
6414 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6416 if ( needsTransform )
6417 pFT_Outline_Transform (&ft_face->glyph->outline, &transMatTategaki);
6419 if ( pFT_Library_SetLcdFilter )
6420 pFT_Library_SetLcdFilter( library, lcdfilter );
6421 pFT_Render_Glyph (ft_face->glyph, render_mode);
6423 src = ft_face->glyph->bitmap.buffer;
6424 src_pitch = ft_face->glyph->bitmap.pitch;
6425 src_width = ft_face->glyph->bitmap.width;
6426 src_height = ft_face->glyph->bitmap.rows;
6428 if ( render_mode == FT_RENDER_MODE_LCD)
6430 rgb_interval = 1;
6431 hmul = 3;
6432 vmul = 1;
6434 else
6436 rgb_interval = src_pitch;
6437 hmul = 1;
6438 vmul = 3;
6441 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6442 if ( x_shift < 0 )
6444 src += hmul * -x_shift;
6445 src_width -= hmul * -x_shift;
6447 else if ( x_shift > 0 )
6449 dst += x_shift;
6450 width -= x_shift;
6453 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6454 if ( y_shift < 0 )
6456 src += src_pitch * vmul * -y_shift;
6457 src_height -= vmul * -y_shift;
6459 else if ( y_shift > 0 )
6461 dst += y_shift * ( pitch / sizeof(*dst) );
6462 height -= y_shift;
6465 width = min( width, src_width / hmul );
6466 height = min( height, src_height / vmul );
6468 while ( height-- )
6470 for ( x = 0; x < width; x++ )
6472 if ( rgb )
6474 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6475 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6476 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6477 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6479 else
6481 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6482 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6483 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6484 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6487 src += src_pitch * vmul;
6488 dst += pitch / sizeof(*dst);
6491 break;
6494 default:
6495 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6496 return GDI_ERROR;
6499 break;
6501 #else
6502 return GDI_ERROR;
6503 #endif
6505 case GGO_NATIVE:
6507 int contour, point = 0, first_pt;
6508 FT_Outline *outline = &ft_face->glyph->outline;
6509 TTPOLYGONHEADER *pph;
6510 TTPOLYCURVE *ppc;
6511 DWORD pph_start, cpfx, type;
6513 if(buflen == 0) buf = NULL;
6515 if (needsTransform && buf) {
6516 pFT_Outline_Transform(outline, &transMatTategaki);
6519 for(contour = 0; contour < outline->n_contours; contour++) {
6520 /* Ignore contours containing one point */
6521 if(point == outline->contours[contour]) {
6522 point++;
6523 continue;
6526 pph_start = needed;
6527 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6528 first_pt = point;
6529 if(buf) {
6530 pph->dwType = TT_POLYGON_TYPE;
6531 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6533 needed += sizeof(*pph);
6534 point++;
6535 while(point <= outline->contours[contour]) {
6536 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6537 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6538 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6539 cpfx = 0;
6540 do {
6541 if(buf)
6542 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6543 cpfx++;
6544 point++;
6545 } while(point <= outline->contours[contour] &&
6546 (outline->tags[point] & FT_Curve_Tag_On) ==
6547 (outline->tags[point-1] & FT_Curve_Tag_On));
6548 /* At the end of a contour Windows adds the start point, but
6549 only for Beziers */
6550 if(point > outline->contours[contour] &&
6551 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6552 if(buf)
6553 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6554 cpfx++;
6555 } else if(point <= outline->contours[contour] &&
6556 outline->tags[point] & FT_Curve_Tag_On) {
6557 /* add closing pt for bezier */
6558 if(buf)
6559 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6560 cpfx++;
6561 point++;
6563 if(buf) {
6564 ppc->wType = type;
6565 ppc->cpfx = cpfx;
6567 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6569 if(buf)
6570 pph->cb = needed - pph_start;
6572 break;
6574 case GGO_BEZIER:
6576 /* Convert the quadratic Beziers to cubic Beziers.
6577 The parametric eqn for a cubic Bezier is, from PLRM:
6578 r(t) = at^3 + bt^2 + ct + r0
6579 with the control points:
6580 r1 = r0 + c/3
6581 r2 = r1 + (c + b)/3
6582 r3 = r0 + c + b + a
6584 A quadratic Bezier has the form:
6585 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6587 So equating powers of t leads to:
6588 r1 = 2/3 p1 + 1/3 p0
6589 r2 = 2/3 p1 + 1/3 p2
6590 and of course r0 = p0, r3 = p2
6593 int contour, point = 0, first_pt;
6594 FT_Outline *outline = &ft_face->glyph->outline;
6595 TTPOLYGONHEADER *pph;
6596 TTPOLYCURVE *ppc;
6597 DWORD pph_start, cpfx, type;
6598 FT_Vector cubic_control[4];
6599 if(buflen == 0) buf = NULL;
6601 if (needsTransform && buf) {
6602 pFT_Outline_Transform(outline, &transMat);
6605 for(contour = 0; contour < outline->n_contours; contour++) {
6606 pph_start = needed;
6607 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6608 first_pt = point;
6609 if(buf) {
6610 pph->dwType = TT_POLYGON_TYPE;
6611 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6613 needed += sizeof(*pph);
6614 point++;
6615 while(point <= outline->contours[contour]) {
6616 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6617 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6618 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6619 cpfx = 0;
6620 do {
6621 if(type == TT_PRIM_LINE) {
6622 if(buf)
6623 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6624 cpfx++;
6625 point++;
6626 } else {
6627 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6628 so cpfx = 3n */
6630 /* FIXME: Possible optimization in endpoint calculation
6631 if there are two consecutive curves */
6632 cubic_control[0] = outline->points[point-1];
6633 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6634 cubic_control[0].x += outline->points[point].x + 1;
6635 cubic_control[0].y += outline->points[point].y + 1;
6636 cubic_control[0].x >>= 1;
6637 cubic_control[0].y >>= 1;
6639 if(point+1 > outline->contours[contour])
6640 cubic_control[3] = outline->points[first_pt];
6641 else {
6642 cubic_control[3] = outline->points[point+1];
6643 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6644 cubic_control[3].x += outline->points[point].x + 1;
6645 cubic_control[3].y += outline->points[point].y + 1;
6646 cubic_control[3].x >>= 1;
6647 cubic_control[3].y >>= 1;
6650 /* r1 = 1/3 p0 + 2/3 p1
6651 r2 = 1/3 p2 + 2/3 p1 */
6652 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6653 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6654 cubic_control[2] = cubic_control[1];
6655 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6656 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6657 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6658 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6659 if(buf) {
6660 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6661 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6662 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6664 cpfx += 3;
6665 point++;
6667 } while(point <= outline->contours[contour] &&
6668 (outline->tags[point] & FT_Curve_Tag_On) ==
6669 (outline->tags[point-1] & FT_Curve_Tag_On));
6670 /* At the end of a contour Windows adds the start point,
6671 but only for Beziers and we've already done that.
6673 if(point <= outline->contours[contour] &&
6674 outline->tags[point] & FT_Curve_Tag_On) {
6675 /* This is the closing pt of a bezier, but we've already
6676 added it, so just inc point and carry on */
6677 point++;
6679 if(buf) {
6680 ppc->wType = type;
6681 ppc->cpfx = cpfx;
6683 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6685 if(buf)
6686 pph->cb = needed - pph_start;
6688 break;
6691 default:
6692 FIXME("Unsupported format %d\n", format);
6693 return GDI_ERROR;
6695 return needed;
6698 static BOOL get_bitmap_text_metrics(GdiFont *font)
6700 FT_Face ft_face = font->ft_face;
6701 FT_WinFNT_HeaderRec winfnt_header;
6702 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6703 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6704 font->potm->otmSize = size;
6706 #define TM font->potm->otmTextMetrics
6707 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6709 TM.tmHeight = winfnt_header.pixel_height;
6710 TM.tmAscent = winfnt_header.ascent;
6711 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6712 TM.tmInternalLeading = winfnt_header.internal_leading;
6713 TM.tmExternalLeading = winfnt_header.external_leading;
6714 TM.tmAveCharWidth = winfnt_header.avg_width;
6715 TM.tmMaxCharWidth = winfnt_header.max_width;
6716 TM.tmWeight = winfnt_header.weight;
6717 TM.tmOverhang = 0;
6718 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6719 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6720 TM.tmFirstChar = winfnt_header.first_char;
6721 TM.tmLastChar = winfnt_header.last_char;
6722 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6723 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6724 TM.tmItalic = winfnt_header.italic;
6725 TM.tmUnderlined = font->underline;
6726 TM.tmStruckOut = font->strikeout;
6727 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6728 TM.tmCharSet = winfnt_header.charset;
6730 else
6732 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6733 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6734 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6735 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6736 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6737 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6738 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6739 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6740 TM.tmOverhang = 0;
6741 TM.tmDigitizedAspectX = 96; /* FIXME */
6742 TM.tmDigitizedAspectY = 96; /* FIXME */
6743 TM.tmFirstChar = 1;
6744 TM.tmLastChar = 255;
6745 TM.tmDefaultChar = 32;
6746 TM.tmBreakChar = 32;
6747 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6748 TM.tmUnderlined = font->underline;
6749 TM.tmStruckOut = font->strikeout;
6750 /* NB inverted meaning of TMPF_FIXED_PITCH */
6751 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6752 TM.tmCharSet = font->charset;
6754 #undef TM
6756 return TRUE;
6760 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6762 double scale_x, scale_y;
6764 if (font->aveWidth)
6766 scale_x = (double)font->aveWidth;
6767 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6769 else
6770 scale_x = font->scale_y;
6772 scale_x *= fabs(font->font_desc.matrix.eM11);
6773 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6775 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6776 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6778 SCALE_Y(ptm->tmHeight);
6779 SCALE_Y(ptm->tmAscent);
6780 SCALE_Y(ptm->tmDescent);
6781 SCALE_Y(ptm->tmInternalLeading);
6782 SCALE_Y(ptm->tmExternalLeading);
6783 SCALE_Y(ptm->tmOverhang);
6785 SCALE_X(ptm->tmAveCharWidth);
6786 SCALE_X(ptm->tmMaxCharWidth);
6788 #undef SCALE_X
6789 #undef SCALE_Y
6792 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6794 double scale_x, scale_y;
6796 if (font->aveWidth)
6798 scale_x = (double)font->aveWidth;
6799 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6801 else
6802 scale_x = font->scale_y;
6804 scale_x *= fabs(font->font_desc.matrix.eM11);
6805 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6807 scale_font_metrics(font, &potm->otmTextMetrics);
6809 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6810 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6812 SCALE_Y(potm->otmAscent);
6813 SCALE_Y(potm->otmDescent);
6814 SCALE_Y(potm->otmLineGap);
6815 SCALE_Y(potm->otmsCapEmHeight);
6816 SCALE_Y(potm->otmsXHeight);
6817 SCALE_Y(potm->otmrcFontBox.top);
6818 SCALE_Y(potm->otmrcFontBox.bottom);
6819 SCALE_X(potm->otmrcFontBox.left);
6820 SCALE_X(potm->otmrcFontBox.right);
6821 SCALE_Y(potm->otmMacAscent);
6822 SCALE_Y(potm->otmMacDescent);
6823 SCALE_Y(potm->otmMacLineGap);
6824 SCALE_X(potm->otmptSubscriptSize.x);
6825 SCALE_Y(potm->otmptSubscriptSize.y);
6826 SCALE_X(potm->otmptSubscriptOffset.x);
6827 SCALE_Y(potm->otmptSubscriptOffset.y);
6828 SCALE_X(potm->otmptSuperscriptSize.x);
6829 SCALE_Y(potm->otmptSuperscriptSize.y);
6830 SCALE_X(potm->otmptSuperscriptOffset.x);
6831 SCALE_Y(potm->otmptSuperscriptOffset.y);
6832 SCALE_Y(potm->otmsStrikeoutSize);
6833 SCALE_Y(potm->otmsStrikeoutPosition);
6834 SCALE_Y(potm->otmsUnderscoreSize);
6835 SCALE_Y(potm->otmsUnderscorePosition);
6837 #undef SCALE_X
6838 #undef SCALE_Y
6841 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6843 if(!font->potm)
6845 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6847 /* Make sure that the font has sane width/height ratio */
6848 if (font->aveWidth)
6850 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6852 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6853 font->aveWidth = 0;
6857 *ptm = font->potm->otmTextMetrics;
6858 scale_font_metrics(font, ptm);
6859 return TRUE;
6862 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6864 int i;
6866 for(i = 0; i < ft_face->num_charmaps; i++)
6868 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6869 return TRUE;
6871 return FALSE;
6874 static BOOL get_outline_text_metrics(GdiFont *font)
6876 BOOL ret = FALSE;
6877 FT_Face ft_face = font->ft_face;
6878 UINT needed, lenfam, lensty, lenface, lenfull;
6879 TT_OS2 *pOS2;
6880 TT_HoriHeader *pHori;
6881 TT_Postscript *pPost;
6882 FT_Fixed em_scale;
6883 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
6884 char *cp;
6885 INT ascent, descent;
6887 TRACE("font=%p\n", font);
6889 if(!FT_IS_SCALABLE(ft_face))
6890 return FALSE;
6892 needed = sizeof(*font->potm);
6894 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6895 family_nameW = strdupW(font->name);
6897 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
6898 if (!style_nameW)
6899 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6900 if (!style_nameW)
6902 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
6903 style_nameW = towstr( CP_ACP, ft_face->style_name );
6905 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
6907 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
6908 if (!face_nameW)
6909 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6910 if (!face_nameW)
6912 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
6913 face_nameW = strdupW(font->name);
6915 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
6916 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
6918 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
6919 if (!full_nameW)
6920 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6921 if (!full_nameW)
6923 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
6924 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
6925 full_nameW = strdupW(fake_nameW);
6927 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
6929 /* These names should be read from the TT name table */
6931 /* length of otmpFamilyName */
6932 needed += lenfam;
6934 /* length of otmpFaceName */
6935 needed += lenface;
6937 /* length of otmpStyleName */
6938 needed += lensty;
6940 /* length of otmpFullName */
6941 needed += lenfull;
6944 em_scale = (FT_Fixed)MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
6946 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6947 if(!pOS2) {
6948 FIXME("Can't find OS/2 table - not TT font?\n");
6949 goto end;
6952 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6953 if(!pHori) {
6954 FIXME("Can't find HHEA table - not TT font?\n");
6955 goto end;
6958 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6960 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",
6961 pOS2->usWinAscent, pOS2->usWinDescent,
6962 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6963 pOS2->xAvgCharWidth,
6964 ft_face->ascender, ft_face->descender, ft_face->height,
6965 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6966 ft_face->bbox.yMax, ft_face->bbox.yMin);
6968 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6969 font->potm->otmSize = needed;
6971 #define TM font->potm->otmTextMetrics
6973 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6974 ascent = pHori->Ascender;
6975 descent = -pHori->Descender;
6976 } else {
6977 ascent = pOS2->usWinAscent;
6978 descent = pOS2->usWinDescent;
6981 font->ntmCellHeight = ascent + descent;
6982 font->ntmAvgWidth = pOS2->xAvgCharWidth;
6984 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
6985 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
6987 if(font->yMax) {
6988 TM.tmAscent = font->yMax;
6989 TM.tmDescent = -font->yMin;
6990 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6991 } else {
6992 TM.tmAscent = SCALE_Y(ascent);
6993 TM.tmDescent = SCALE_Y(descent);
6994 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
6997 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6999 /* MSDN says:
7000 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7002 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
7003 ((ascent + descent) -
7004 (pHori->Ascender - pHori->Descender))));
7006 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
7007 if (TM.tmAveCharWidth == 0) {
7008 TM.tmAveCharWidth = 1;
7010 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
7011 TM.tmWeight = FW_REGULAR;
7012 if (font->fake_bold)
7013 TM.tmWeight = FW_BOLD;
7014 else
7016 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
7018 if (pOS2->usWeightClass > FW_MEDIUM)
7019 TM.tmWeight = pOS2->usWeightClass;
7021 else if (pOS2->usWeightClass <= FW_MEDIUM)
7022 TM.tmWeight = pOS2->usWeightClass;
7024 TM.tmOverhang = 0;
7025 TM.tmDigitizedAspectX = 96; /* FIXME */
7026 TM.tmDigitizedAspectY = 96; /* FIXME */
7027 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7028 * symbol range to 0 - f0ff
7031 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
7033 TM.tmFirstChar = 0;
7034 switch(GetACP())
7036 case 1257: /* Baltic */
7037 TM.tmLastChar = 0xf8fd;
7038 break;
7039 default:
7040 TM.tmLastChar = 0xf0ff;
7042 TM.tmBreakChar = 0x20;
7043 TM.tmDefaultChar = 0x1f;
7045 else
7047 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
7048 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
7050 if(pOS2->usFirstCharIndex <= 1)
7051 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
7052 else if (pOS2->usFirstCharIndex > 0xff)
7053 TM.tmBreakChar = 0x20;
7054 else
7055 TM.tmBreakChar = pOS2->usFirstCharIndex;
7056 TM.tmDefaultChar = TM.tmBreakChar - 1;
7058 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
7059 TM.tmUnderlined = font->underline;
7060 TM.tmStruckOut = font->strikeout;
7062 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7063 if(!FT_IS_FIXED_WIDTH(ft_face) &&
7064 (pOS2->version == 0xFFFFU ||
7065 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
7066 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
7067 else
7068 TM.tmPitchAndFamily = 0;
7070 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
7072 case PAN_FAMILY_SCRIPT:
7073 TM.tmPitchAndFamily |= FF_SCRIPT;
7074 break;
7076 case PAN_FAMILY_DECORATIVE:
7077 TM.tmPitchAndFamily |= FF_DECORATIVE;
7078 break;
7080 case PAN_ANY:
7081 case PAN_NO_FIT:
7082 case PAN_FAMILY_TEXT_DISPLAY:
7083 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
7084 /* which is clearly not what the panose spec says. */
7085 default:
7086 if(TM.tmPitchAndFamily == 0 || /* fixed */
7087 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
7088 TM.tmPitchAndFamily = FF_MODERN;
7089 else
7091 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
7093 case PAN_ANY:
7094 case PAN_NO_FIT:
7095 default:
7096 TM.tmPitchAndFamily |= FF_DONTCARE;
7097 break;
7099 case PAN_SERIF_COVE:
7100 case PAN_SERIF_OBTUSE_COVE:
7101 case PAN_SERIF_SQUARE_COVE:
7102 case PAN_SERIF_OBTUSE_SQUARE_COVE:
7103 case PAN_SERIF_SQUARE:
7104 case PAN_SERIF_THIN:
7105 case PAN_SERIF_BONE:
7106 case PAN_SERIF_EXAGGERATED:
7107 case PAN_SERIF_TRIANGLE:
7108 TM.tmPitchAndFamily |= FF_ROMAN;
7109 break;
7111 case PAN_SERIF_NORMAL_SANS:
7112 case PAN_SERIF_OBTUSE_SANS:
7113 case PAN_SERIF_PERP_SANS:
7114 case PAN_SERIF_FLARED:
7115 case PAN_SERIF_ROUNDED:
7116 TM.tmPitchAndFamily |= FF_SWISS;
7117 break;
7120 break;
7123 if(FT_IS_SCALABLE(ft_face))
7124 TM.tmPitchAndFamily |= TMPF_VECTOR;
7126 if(FT_IS_SFNT(ft_face))
7128 if (font->ntmFlags & NTM_PS_OPENTYPE)
7129 TM.tmPitchAndFamily |= TMPF_DEVICE;
7130 else
7131 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
7134 TM.tmCharSet = font->charset;
7136 font->potm->otmFiller = 0;
7137 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
7138 font->potm->otmfsSelection = pOS2->fsSelection;
7139 font->potm->otmfsType = pOS2->fsType;
7140 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
7141 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
7142 font->potm->otmItalicAngle = 0; /* POST table */
7143 font->potm->otmEMSquare = ft_face->units_per_EM;
7144 font->potm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
7145 font->potm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
7146 font->potm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
7147 font->potm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
7148 font->potm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
7149 font->potm->otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
7150 font->potm->otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
7151 font->potm->otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
7152 font->potm->otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
7153 font->potm->otmMacAscent = TM.tmAscent;
7154 font->potm->otmMacDescent = -TM.tmDescent;
7155 font->potm->otmMacLineGap = font->potm->otmLineGap;
7156 font->potm->otmusMinimumPPEM = 0; /* TT Header */
7157 font->potm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
7158 font->potm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
7159 font->potm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
7160 font->potm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
7161 font->potm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
7162 font->potm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
7163 font->potm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
7164 font->potm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
7165 font->potm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
7166 font->potm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
7167 if(!pPost) {
7168 font->potm->otmsUnderscoreSize = 0;
7169 font->potm->otmsUnderscorePosition = 0;
7170 } else {
7171 font->potm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
7172 font->potm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
7174 #undef SCALE_X
7175 #undef SCALE_Y
7176 #undef TM
7178 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7179 cp = (char*)font->potm + sizeof(*font->potm);
7180 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
7181 strcpyW((WCHAR*)cp, family_nameW);
7182 cp += lenfam;
7183 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
7184 strcpyW((WCHAR*)cp, style_nameW);
7185 cp += lensty;
7186 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7187 strcpyW((WCHAR*)cp, face_nameW);
7188 cp += lenface;
7189 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
7190 strcpyW((WCHAR*)cp, full_nameW);
7191 ret = TRUE;
7193 end:
7194 HeapFree(GetProcessHeap(), 0, style_nameW);
7195 HeapFree(GetProcessHeap(), 0, family_nameW);
7196 HeapFree(GetProcessHeap(), 0, face_nameW);
7197 HeapFree(GetProcessHeap(), 0, full_nameW);
7198 return ret;
7201 /*************************************************************
7202 * freetype_GetGlyphOutline
7204 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
7205 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7207 struct freetype_physdev *physdev = get_freetype_dev( dev );
7208 DWORD ret;
7209 ABC abc;
7211 if (!physdev->font)
7213 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
7214 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
7217 GDI_CheckNotLock();
7218 EnterCriticalSection( &freetype_cs );
7219 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
7220 LeaveCriticalSection( &freetype_cs );
7221 return ret;
7224 /*************************************************************
7225 * freetype_GetTextMetrics
7227 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
7229 struct freetype_physdev *physdev = get_freetype_dev( dev );
7230 BOOL ret;
7232 if (!physdev->font)
7234 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
7235 return dev->funcs->pGetTextMetrics( dev, metrics );
7238 GDI_CheckNotLock();
7239 EnterCriticalSection( &freetype_cs );
7240 ret = get_text_metrics( physdev->font, metrics );
7241 LeaveCriticalSection( &freetype_cs );
7242 return ret;
7245 /*************************************************************
7246 * freetype_GetOutlineTextMetrics
7248 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
7250 struct freetype_physdev *physdev = get_freetype_dev( dev );
7251 UINT ret = 0;
7253 if (!physdev->font)
7255 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
7256 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
7259 TRACE("font=%p\n", physdev->font);
7261 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
7263 GDI_CheckNotLock();
7264 EnterCriticalSection( &freetype_cs );
7266 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
7268 if(cbSize >= physdev->font->potm->otmSize)
7270 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
7271 scale_outline_font_metrics(physdev->font, potm);
7273 ret = physdev->font->potm->otmSize;
7275 LeaveCriticalSection( &freetype_cs );
7276 return ret;
7279 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
7281 child->font = alloc_font();
7282 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
7283 if(!child->font->ft_face)
7285 free_font(child->font);
7286 child->font = NULL;
7287 return FALSE;
7290 child->font->font_desc = font->font_desc;
7291 child->font->ntmFlags = child->face->ntmFlags;
7292 child->font->orientation = font->orientation;
7293 child->font->scale_y = font->scale_y;
7294 child->font->name = strdupW(child->face->family->FamilyName);
7295 child->font->base_font = font;
7296 TRACE("created child font %p for base %p\n", child->font, font);
7297 return TRUE;
7300 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
7302 FT_UInt g;
7303 CHILD_FONT *child_font;
7305 if(font->base_font)
7306 font = font->base_font;
7308 *linked_font = font;
7310 if((*glyph = get_glyph_index(font, c)))
7312 *glyph = get_GSUB_vert_glyph(font, *glyph);
7313 return TRUE;
7316 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7318 if(!child_font->font)
7319 if(!load_child_font(font, child_font))
7320 continue;
7322 if(!child_font->font->ft_face)
7323 continue;
7324 g = get_glyph_index(child_font->font, c);
7325 g = get_GSUB_vert_glyph(child_font->font, g);
7326 if(g)
7328 *glyph = g;
7329 *linked_font = child_font->font;
7330 return TRUE;
7333 *glyph = get_default_char_index(font);
7334 return FALSE;
7337 /*************************************************************
7338 * freetype_GetCharWidth
7340 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7342 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7343 UINT c;
7344 GLYPHMETRICS gm;
7345 ABC abc;
7346 struct freetype_physdev *physdev = get_freetype_dev( dev );
7348 if (!physdev->font)
7350 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7351 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7354 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7356 GDI_CheckNotLock();
7357 EnterCriticalSection( &freetype_cs );
7358 for(c = firstChar; c <= lastChar; c++) {
7359 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7360 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
7362 LeaveCriticalSection( &freetype_cs );
7363 return TRUE;
7366 /*************************************************************
7367 * freetype_GetCharABCWidths
7369 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7371 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7372 UINT c;
7373 GLYPHMETRICS gm;
7374 struct freetype_physdev *physdev = get_freetype_dev( dev );
7376 if (!physdev->font)
7378 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7379 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7382 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7384 GDI_CheckNotLock();
7385 EnterCriticalSection( &freetype_cs );
7387 for(c = firstChar; c <= lastChar; c++, buffer++)
7388 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
7390 LeaveCriticalSection( &freetype_cs );
7391 return TRUE;
7394 /*************************************************************
7395 * freetype_GetCharABCWidthsI
7397 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7399 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7400 UINT c;
7401 GLYPHMETRICS gm;
7402 struct freetype_physdev *physdev = get_freetype_dev( dev );
7404 if (!physdev->font)
7406 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7407 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7410 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7411 return FALSE;
7413 GDI_CheckNotLock();
7414 EnterCriticalSection( &freetype_cs );
7416 for(c = 0; c < count; c++, buffer++)
7417 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
7418 &gm, buffer, 0, NULL, &identity );
7420 LeaveCriticalSection( &freetype_cs );
7421 return TRUE;
7424 /*************************************************************
7425 * freetype_GetTextExtentExPoint
7427 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
7429 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7430 INT idx, pos;
7431 ABC abc;
7432 GLYPHMETRICS gm;
7433 struct freetype_physdev *physdev = get_freetype_dev( dev );
7435 if (!physdev->font)
7437 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7438 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
7441 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
7443 GDI_CheckNotLock();
7444 EnterCriticalSection( &freetype_cs );
7446 for (idx = pos = 0; idx < count; idx++)
7448 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7449 pos += abc.abcA + abc.abcB + abc.abcC;
7450 dxs[idx] = pos;
7453 LeaveCriticalSection( &freetype_cs );
7454 return TRUE;
7457 /*************************************************************
7458 * freetype_GetTextExtentExPointI
7460 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
7462 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7463 INT idx, pos;
7464 ABC abc;
7465 GLYPHMETRICS gm;
7466 struct freetype_physdev *physdev = get_freetype_dev( dev );
7468 if (!physdev->font)
7470 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7471 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
7474 TRACE("%p, %p, %d\n", physdev->font, indices, count);
7476 GDI_CheckNotLock();
7477 EnterCriticalSection( &freetype_cs );
7479 for (idx = pos = 0; idx < count; idx++)
7481 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
7482 &gm, &abc, 0, NULL, &identity );
7483 pos += abc.abcA + abc.abcB + abc.abcC;
7484 dxs[idx] = pos;
7487 LeaveCriticalSection( &freetype_cs );
7488 return TRUE;
7491 /*************************************************************
7492 * freetype_GetFontData
7494 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7496 struct freetype_physdev *physdev = get_freetype_dev( dev );
7498 if (!physdev->font)
7500 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7501 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7504 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7505 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7506 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7508 return get_font_data( physdev->font, table, offset, buf, cbData );
7511 /*************************************************************
7512 * freetype_GetTextFace
7514 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7516 INT n;
7517 struct freetype_physdev *physdev = get_freetype_dev( dev );
7519 if (!physdev->font)
7521 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7522 return dev->funcs->pGetTextFace( dev, count, str );
7525 n = strlenW(physdev->font->name) + 1;
7526 if (str)
7528 lstrcpynW(str, physdev->font->name, count);
7529 n = min(count, n);
7531 return n;
7534 /*************************************************************
7535 * freetype_GetTextCharsetInfo
7537 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7539 struct freetype_physdev *physdev = get_freetype_dev( dev );
7541 if (!physdev->font)
7543 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7544 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7546 if (fs) *fs = physdev->font->fs;
7547 return physdev->font->charset;
7550 /* Retrieve a list of supported Unicode ranges for a given font.
7551 * Can be called with NULL gs to calculate the buffer size. Returns
7552 * the number of ranges found.
7554 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7556 DWORD num_ranges = 0;
7558 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7560 FT_UInt glyph_code;
7561 FT_ULong char_code, char_code_prev;
7563 glyph_code = 0;
7564 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7566 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7567 face->num_glyphs, glyph_code, char_code);
7569 if (!glyph_code) return 0;
7571 if (gs)
7573 gs->ranges[0].wcLow = (USHORT)char_code;
7574 gs->ranges[0].cGlyphs = 0;
7575 gs->cGlyphsSupported = 0;
7578 num_ranges = 1;
7579 while (glyph_code)
7581 if (char_code < char_code_prev)
7583 ERR("expected increasing char code from FT_Get_Next_Char\n");
7584 return 0;
7586 if (char_code - char_code_prev > 1)
7588 num_ranges++;
7589 if (gs)
7591 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7592 gs->ranges[num_ranges - 1].cGlyphs = 1;
7593 gs->cGlyphsSupported++;
7596 else if (gs)
7598 gs->ranges[num_ranges - 1].cGlyphs++;
7599 gs->cGlyphsSupported++;
7601 char_code_prev = char_code;
7602 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7605 else
7606 FIXME("encoding %u not supported\n", face->charmap->encoding);
7608 return num_ranges;
7611 /*************************************************************
7612 * freetype_GetFontUnicodeRanges
7614 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7616 struct freetype_physdev *physdev = get_freetype_dev( dev );
7617 DWORD size, num_ranges;
7619 if (!physdev->font)
7621 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7622 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7625 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7626 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7627 if (glyphset)
7629 glyphset->cbThis = size;
7630 glyphset->cRanges = num_ranges;
7631 glyphset->flAccel = 0;
7633 return size;
7636 /*************************************************************
7637 * freetype_FontIsLinked
7639 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7641 struct freetype_physdev *physdev = get_freetype_dev( dev );
7642 BOOL ret;
7644 if (!physdev->font)
7646 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7647 return dev->funcs->pFontIsLinked( dev );
7650 GDI_CheckNotLock();
7651 EnterCriticalSection( &freetype_cs );
7652 ret = !list_empty(&physdev->font->child_fonts);
7653 LeaveCriticalSection( &freetype_cs );
7654 return ret;
7657 /*************************************************************************
7658 * GetRasterizerCaps (GDI32.@)
7660 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7662 lprs->nSize = sizeof(RASTERIZER_STATUS);
7663 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
7664 lprs->nLanguageID = 0;
7665 return TRUE;
7668 /*************************************************************
7669 * freetype_GdiRealizationInfo
7671 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7673 struct freetype_physdev *physdev = get_freetype_dev( dev );
7674 realization_info_t *info = ptr;
7676 if (!physdev->font)
7678 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7679 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7682 FIXME("(%p, %p): stub!\n", physdev->font, info);
7684 info->flags = 1;
7685 if(FT_IS_SCALABLE(physdev->font->ft_face))
7686 info->flags |= 2;
7688 info->cache_num = physdev->font->cache_num;
7689 info->unknown2 = -1;
7690 return TRUE;
7693 /*************************************************************************
7694 * Kerning support for TrueType fonts
7696 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7698 struct TT_kern_table
7700 USHORT version;
7701 USHORT nTables;
7704 struct TT_kern_subtable
7706 USHORT version;
7707 USHORT length;
7708 union
7710 USHORT word;
7711 struct
7713 USHORT horizontal : 1;
7714 USHORT minimum : 1;
7715 USHORT cross_stream: 1;
7716 USHORT override : 1;
7717 USHORT reserved1 : 4;
7718 USHORT format : 8;
7719 } bits;
7720 } coverage;
7723 struct TT_format0_kern_subtable
7725 USHORT nPairs;
7726 USHORT searchRange;
7727 USHORT entrySelector;
7728 USHORT rangeShift;
7731 struct TT_kern_pair
7733 USHORT left;
7734 USHORT right;
7735 short value;
7738 static DWORD parse_format0_kern_subtable(GdiFont *font,
7739 const struct TT_format0_kern_subtable *tt_f0_ks,
7740 const USHORT *glyph_to_char,
7741 KERNINGPAIR *kern_pair, DWORD cPairs)
7743 USHORT i, nPairs;
7744 const struct TT_kern_pair *tt_kern_pair;
7746 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7748 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7750 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7751 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7752 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7754 if (!kern_pair || !cPairs)
7755 return nPairs;
7757 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7759 nPairs = min(nPairs, cPairs);
7761 for (i = 0; i < nPairs; i++)
7763 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7764 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7765 /* this algorithm appears to better match what Windows does */
7766 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7767 if (kern_pair->iKernAmount < 0)
7769 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7770 kern_pair->iKernAmount -= font->ppem;
7772 else if (kern_pair->iKernAmount > 0)
7774 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7775 kern_pair->iKernAmount += font->ppem;
7777 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7779 TRACE("left %u right %u value %d\n",
7780 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7782 kern_pair++;
7784 TRACE("copied %u entries\n", nPairs);
7785 return nPairs;
7788 /*************************************************************
7789 * freetype_GetKerningPairs
7791 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7793 DWORD length;
7794 void *buf;
7795 const struct TT_kern_table *tt_kern_table;
7796 const struct TT_kern_subtable *tt_kern_subtable;
7797 USHORT i, nTables;
7798 USHORT *glyph_to_char;
7799 GdiFont *font;
7800 struct freetype_physdev *physdev = get_freetype_dev( dev );
7802 if (!(font = physdev->font))
7804 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7805 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7808 GDI_CheckNotLock();
7809 EnterCriticalSection( &freetype_cs );
7810 if (font->total_kern_pairs != (DWORD)-1)
7812 if (cPairs && kern_pair)
7814 cPairs = min(cPairs, font->total_kern_pairs);
7815 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7817 else cPairs = font->total_kern_pairs;
7819 LeaveCriticalSection( &freetype_cs );
7820 return cPairs;
7823 font->total_kern_pairs = 0;
7825 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7827 if (length == GDI_ERROR)
7829 TRACE("no kerning data in the font\n");
7830 LeaveCriticalSection( &freetype_cs );
7831 return 0;
7834 buf = HeapAlloc(GetProcessHeap(), 0, length);
7835 if (!buf)
7837 WARN("Out of memory\n");
7838 LeaveCriticalSection( &freetype_cs );
7839 return 0;
7842 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7844 /* build a glyph index to char code map */
7845 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7846 if (!glyph_to_char)
7848 WARN("Out of memory allocating a glyph index to char code map\n");
7849 HeapFree(GetProcessHeap(), 0, buf);
7850 LeaveCriticalSection( &freetype_cs );
7851 return 0;
7854 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7856 FT_UInt glyph_code;
7857 FT_ULong char_code;
7859 glyph_code = 0;
7860 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7862 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7863 font->ft_face->num_glyphs, glyph_code, char_code);
7865 while (glyph_code)
7867 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7869 /* FIXME: This doesn't match what Windows does: it does some fancy
7870 * things with duplicate glyph index to char code mappings, while
7871 * we just avoid overriding existing entries.
7873 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7874 glyph_to_char[glyph_code] = (USHORT)char_code;
7876 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7879 else
7881 ULONG n;
7883 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7884 for (n = 0; n <= 65535; n++)
7885 glyph_to_char[n] = (USHORT)n;
7888 tt_kern_table = buf;
7889 nTables = GET_BE_WORD(tt_kern_table->nTables);
7890 TRACE("version %u, nTables %u\n",
7891 GET_BE_WORD(tt_kern_table->version), nTables);
7893 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7895 for (i = 0; i < nTables; i++)
7897 struct TT_kern_subtable tt_kern_subtable_copy;
7899 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7900 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7901 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7903 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7904 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7905 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7907 /* According to the TrueType specification this is the only format
7908 * that will be properly interpreted by Windows and OS/2
7910 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7912 DWORD new_chunk, old_total = font->total_kern_pairs;
7914 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7915 glyph_to_char, NULL, 0);
7916 font->total_kern_pairs += new_chunk;
7918 if (!font->kern_pairs)
7919 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7920 font->total_kern_pairs * sizeof(*font->kern_pairs));
7921 else
7922 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7923 font->total_kern_pairs * sizeof(*font->kern_pairs));
7925 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7926 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7928 else
7929 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7931 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7934 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7935 HeapFree(GetProcessHeap(), 0, buf);
7937 if (cPairs && kern_pair)
7939 cPairs = min(cPairs, font->total_kern_pairs);
7940 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7942 else cPairs = font->total_kern_pairs;
7944 LeaveCriticalSection( &freetype_cs );
7945 return cPairs;
7948 static const struct gdi_dc_funcs freetype_funcs =
7950 NULL, /* pAbortDoc */
7951 NULL, /* pAbortPath */
7952 NULL, /* pAlphaBlend */
7953 NULL, /* pAngleArc */
7954 NULL, /* pArc */
7955 NULL, /* pArcTo */
7956 NULL, /* pBeginPath */
7957 NULL, /* pBlendImage */
7958 NULL, /* pChord */
7959 NULL, /* pCloseFigure */
7960 NULL, /* pCreateCompatibleDC */
7961 freetype_CreateDC, /* pCreateDC */
7962 freetype_DeleteDC, /* pDeleteDC */
7963 NULL, /* pDeleteObject */
7964 NULL, /* pDeviceCapabilities */
7965 NULL, /* pEllipse */
7966 NULL, /* pEndDoc */
7967 NULL, /* pEndPage */
7968 NULL, /* pEndPath */
7969 freetype_EnumFonts, /* pEnumFonts */
7970 NULL, /* pEnumICMProfiles */
7971 NULL, /* pExcludeClipRect */
7972 NULL, /* pExtDeviceMode */
7973 NULL, /* pExtEscape */
7974 NULL, /* pExtFloodFill */
7975 NULL, /* pExtSelectClipRgn */
7976 NULL, /* pExtTextOut */
7977 NULL, /* pFillPath */
7978 NULL, /* pFillRgn */
7979 NULL, /* pFlattenPath */
7980 freetype_FontIsLinked, /* pFontIsLinked */
7981 NULL, /* pFrameRgn */
7982 NULL, /* pGdiComment */
7983 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7984 NULL, /* pGetBoundsRect */
7985 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7986 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7987 freetype_GetCharWidth, /* pGetCharWidth */
7988 NULL, /* pGetDeviceCaps */
7989 NULL, /* pGetDeviceGammaRamp */
7990 freetype_GetFontData, /* pGetFontData */
7991 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7992 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7993 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7994 NULL, /* pGetICMProfile */
7995 NULL, /* pGetImage */
7996 freetype_GetKerningPairs, /* pGetKerningPairs */
7997 NULL, /* pGetNearestColor */
7998 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7999 NULL, /* pGetPixel */
8000 NULL, /* pGetSystemPaletteEntries */
8001 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
8002 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
8003 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
8004 freetype_GetTextFace, /* pGetTextFace */
8005 freetype_GetTextMetrics, /* pGetTextMetrics */
8006 NULL, /* pGradientFill */
8007 NULL, /* pIntersectClipRect */
8008 NULL, /* pInvertRgn */
8009 NULL, /* pLineTo */
8010 NULL, /* pModifyWorldTransform */
8011 NULL, /* pMoveTo */
8012 NULL, /* pOffsetClipRgn */
8013 NULL, /* pOffsetViewportOrg */
8014 NULL, /* pOffsetWindowOrg */
8015 NULL, /* pPaintRgn */
8016 NULL, /* pPatBlt */
8017 NULL, /* pPie */
8018 NULL, /* pPolyBezier */
8019 NULL, /* pPolyBezierTo */
8020 NULL, /* pPolyDraw */
8021 NULL, /* pPolyPolygon */
8022 NULL, /* pPolyPolyline */
8023 NULL, /* pPolygon */
8024 NULL, /* pPolyline */
8025 NULL, /* pPolylineTo */
8026 NULL, /* pPutImage */
8027 NULL, /* pRealizeDefaultPalette */
8028 NULL, /* pRealizePalette */
8029 NULL, /* pRectangle */
8030 NULL, /* pResetDC */
8031 NULL, /* pRestoreDC */
8032 NULL, /* pRoundRect */
8033 NULL, /* pSaveDC */
8034 NULL, /* pScaleViewportExt */
8035 NULL, /* pScaleWindowExt */
8036 NULL, /* pSelectBitmap */
8037 NULL, /* pSelectBrush */
8038 NULL, /* pSelectClipPath */
8039 freetype_SelectFont, /* pSelectFont */
8040 NULL, /* pSelectPalette */
8041 NULL, /* pSelectPen */
8042 NULL, /* pSetArcDirection */
8043 NULL, /* pSetBkColor */
8044 NULL, /* pSetBkMode */
8045 NULL, /* pSetDCBrushColor */
8046 NULL, /* pSetDCPenColor */
8047 NULL, /* pSetDIBColorTable */
8048 NULL, /* pSetDIBitsToDevice */
8049 NULL, /* pSetDeviceClipping */
8050 NULL, /* pSetDeviceGammaRamp */
8051 NULL, /* pSetLayout */
8052 NULL, /* pSetMapMode */
8053 NULL, /* pSetMapperFlags */
8054 NULL, /* pSetPixel */
8055 NULL, /* pSetPolyFillMode */
8056 NULL, /* pSetROP2 */
8057 NULL, /* pSetRelAbs */
8058 NULL, /* pSetStretchBltMode */
8059 NULL, /* pSetTextAlign */
8060 NULL, /* pSetTextCharacterExtra */
8061 NULL, /* pSetTextColor */
8062 NULL, /* pSetTextJustification */
8063 NULL, /* pSetViewportExt */
8064 NULL, /* pSetViewportOrg */
8065 NULL, /* pSetWindowExt */
8066 NULL, /* pSetWindowOrg */
8067 NULL, /* pSetWorldTransform */
8068 NULL, /* pStartDoc */
8069 NULL, /* pStartPage */
8070 NULL, /* pStretchBlt */
8071 NULL, /* pStretchDIBits */
8072 NULL, /* pStrokeAndFillPath */
8073 NULL, /* pStrokePath */
8074 NULL, /* pUnrealizePalette */
8075 NULL, /* pWidenPath */
8076 NULL, /* wine_get_wgl_driver */
8077 GDI_PRIORITY_FONT_DRV /* priority */
8080 #else /* HAVE_FREETYPE */
8082 /*************************************************************************/
8084 BOOL WineEngInit(void)
8086 return FALSE;
8089 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8091 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8092 return 1;
8095 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8097 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8098 return TRUE;
8101 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
8103 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
8104 return NULL;
8107 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
8108 LPCWSTR font_file, LPCWSTR font_path )
8110 FIXME("stub\n");
8111 return FALSE;
8114 /*************************************************************************
8115 * GetRasterizerCaps (GDI32.@)
8117 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8119 lprs->nSize = sizeof(RASTERIZER_STATUS);
8120 lprs->wFlags = 0;
8121 lprs->nLanguageID = 0;
8122 return TRUE;
8125 #endif /* HAVE_FREETYPE */