gdi32: Store the fontconfig anti-aliasing flags for each font.
[wine.git] / dlls / gdi32 / freetype.c
blobca11968ff5575d490d1f3c6ea7888a61c22f9d08
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 MAKE_FUNCPTR(FcPatternPrint);
207 #endif
209 #undef MAKE_FUNCPTR
211 #ifndef FT_MAKE_TAG
212 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
213 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
214 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
215 #endif
217 #ifndef ft_encoding_none
218 #define FT_ENCODING_NONE ft_encoding_none
219 #endif
220 #ifndef ft_encoding_ms_symbol
221 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
222 #endif
223 #ifndef ft_encoding_unicode
224 #define FT_ENCODING_UNICODE ft_encoding_unicode
225 #endif
226 #ifndef ft_encoding_apple_roman
227 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
228 #endif
230 #ifdef WORDS_BIGENDIAN
231 #define GET_BE_WORD(x) (x)
232 #else
233 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
234 #endif
236 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
237 typedef struct {
238 FT_Short height;
239 FT_Short width;
240 FT_Pos size;
241 FT_Pos x_ppem;
242 FT_Pos y_ppem;
243 FT_Short internal_leading;
244 } Bitmap_Size;
246 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
247 So to let this compile on older versions of FreeType we'll define the
248 new structure here. */
249 typedef struct {
250 FT_Short height, width;
251 FT_Pos size, x_ppem, y_ppem;
252 } My_FT_Bitmap_Size;
254 struct enum_data
256 ENUMLOGFONTEXW elf;
257 NEWTEXTMETRICEXW ntm;
258 DWORD type;
261 typedef struct tagFace {
262 struct list entry;
263 WCHAR *StyleName;
264 WCHAR *FullName;
265 WCHAR *file;
266 void *font_data_ptr;
267 DWORD font_data_size;
268 FT_Long face_index;
269 FONTSIGNATURE fs;
270 DWORD ntmFlags;
271 FT_Fixed font_version;
272 BOOL scalable;
273 BOOL vertical;
274 Bitmap_Size size; /* set if face is a bitmap */
275 BOOL external; /* TRUE if we should manually add this font to the registry */
276 DWORD aa_flags;
277 struct tagFamily *family;
278 /* Cached data for Enum */
279 struct enum_data *cached_enum_data;
280 } Face;
282 typedef struct tagFamily {
283 struct list entry;
284 WCHAR *FamilyName;
285 WCHAR *EnglishName;
286 struct list faces;
287 struct list *replacement;
288 } Family;
290 typedef struct {
291 GLYPHMETRICS gm;
292 INT adv; /* These three hold to widths of the unrotated chars */
293 INT lsb;
294 INT bbx;
295 BOOL init;
296 } GM;
298 typedef struct {
299 FLOAT eM11, eM12;
300 FLOAT eM21, eM22;
301 } FMAT2;
303 typedef struct {
304 DWORD hash;
305 LOGFONTW lf;
306 FMAT2 matrix;
307 BOOL can_use_bitmap;
308 } FONT_DESC;
310 typedef struct tagHFONTLIST {
311 struct list entry;
312 HFONT hfont;
313 } HFONTLIST;
315 typedef struct {
316 struct list entry;
317 Face *face;
318 GdiFont *font;
319 } CHILD_FONT;
321 struct tagGdiFont {
322 struct list entry;
323 GM **gm;
324 DWORD gmsize;
325 struct list hfontlist;
326 OUTLINETEXTMETRICW *potm;
327 DWORD total_kern_pairs;
328 KERNINGPAIR *kern_pairs;
329 struct list child_fonts;
331 /* the following members can be accessed without locking, they are never modified after creation */
332 FT_Face ft_face;
333 struct font_mapping *mapping;
334 LPWSTR name;
335 int charset;
336 int codepage;
337 BOOL fake_italic;
338 BOOL fake_bold;
339 BYTE underline;
340 BYTE strikeout;
341 INT orientation;
342 FONT_DESC font_desc;
343 LONG aveWidth, ppem;
344 double scale_y;
345 SHORT yMax;
346 SHORT yMin;
347 DWORD ntmFlags;
348 UINT ntmCellHeight, ntmAvgWidth;
349 FONTSIGNATURE fs;
350 GdiFont *base_font;
351 VOID *GSUB_Table;
352 DWORD cache_num;
355 typedef struct {
356 struct list entry;
357 const WCHAR *font_name;
358 FONTSIGNATURE fs;
359 struct list links;
360 } SYSTEM_LINKS;
362 struct enum_charset_element {
363 DWORD mask;
364 DWORD charset;
365 WCHAR name[LF_FACESIZE];
368 struct enum_charset_list {
369 DWORD total;
370 struct enum_charset_element element[32];
373 #define GM_BLOCK_SIZE 128
374 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
376 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
377 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
378 #define UNUSED_CACHE_SIZE 10
379 static struct list child_font_list = LIST_INIT(child_font_list);
380 static struct list system_links = LIST_INIT(system_links);
382 static struct list font_subst_list = LIST_INIT(font_subst_list);
384 static struct list font_list = LIST_INIT(font_list);
386 struct freetype_physdev
388 struct gdi_physdev dev;
389 GdiFont *font;
392 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
394 return (struct freetype_physdev *)dev;
397 static const struct gdi_dc_funcs freetype_funcs;
399 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
400 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
401 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
403 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
404 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
405 'W','i','n','d','o','w','s','\\',
406 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
407 'F','o','n','t','s','\0'};
409 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
410 'W','i','n','d','o','w','s',' ','N','T','\\',
411 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
412 'F','o','n','t','s','\0'};
414 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
415 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
416 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
417 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
419 static const WCHAR * const SystemFontValues[] = {
420 System_Value,
421 OEMFont_Value,
422 FixedSys_Value,
423 NULL
426 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
427 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
429 /* Interesting and well-known (frequently-assumed!) font names */
430 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
431 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 };
432 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
433 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
434 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
435 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
436 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
437 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
439 static const WCHAR arial[] = {'A','r','i','a','l',0};
440 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
441 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};
442 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};
443 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
444 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
445 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
446 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
447 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
448 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
450 static const WCHAR *default_serif_list[] =
452 times_new_roman,
453 liberation_serif,
454 bitstream_vera_serif,
455 NULL
458 static const WCHAR *default_fixed_list[] =
460 courier_new,
461 liberation_mono,
462 bitstream_vera_sans_mono,
463 NULL
466 static const WCHAR *default_sans_list[] =
468 arial,
469 liberation_sans,
470 bitstream_vera_sans,
471 NULL
474 typedef struct {
475 WCHAR *name;
476 INT charset;
477 } NameCs;
479 typedef struct tagFontSubst {
480 struct list entry;
481 NameCs from;
482 NameCs to;
483 } FontSubst;
485 /* Registry font cache key and value names */
486 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
487 'F','o','n','t','s',0};
488 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
489 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
490 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
491 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
492 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
493 static const WCHAR face_vertical_value[] = {'V','e','r','t','i','c','a','l',0};
494 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
495 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
496 static const WCHAR face_size_value[] = {'S','i','z','e',0};
497 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
498 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
499 static const WCHAR face_aa_value[] = {'A','n','t','i','a','l','i','a','s','i','n','g',0};
500 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
501 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
502 static const WCHAR face_file_name_value[] = {'F','i','l','e',' ','N','a','m','e','\0'};
503 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
506 struct font_mapping
508 struct list entry;
509 int refcount;
510 dev_t dev;
511 ino_t ino;
512 void *data;
513 size_t size;
516 static struct list mappings_list = LIST_INIT( mappings_list );
518 static CRITICAL_SECTION freetype_cs;
519 static CRITICAL_SECTION_DEBUG critsect_debug =
521 0, 0, &freetype_cs,
522 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
523 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
525 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
527 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
529 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
530 static BOOL use_default_fallback = FALSE;
532 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
533 static BOOL get_outline_text_metrics(GdiFont *font);
534 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
536 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
537 'W','i','n','d','o','w','s',' ','N','T','\\',
538 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
539 'S','y','s','t','e','m','L','i','n','k',0};
541 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
542 'F','o','n','t','L','i','n','k','\\',
543 'S','y','s','t','e','m','L','i','n','k',0};
545 /****************************************
546 * Notes on .fon files
548 * The fonts System, FixedSys and Terminal are special. There are typically multiple
549 * versions installed for different resolutions and codepages. Windows stores which one to use
550 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
551 * Key Meaning
552 * FIXEDFON.FON FixedSys
553 * FONTS.FON System
554 * OEMFONT.FON Terminal
555 * LogPixels Current dpi set by the display control panel applet
556 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
557 * also has a LogPixels value that appears to mirror this)
559 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
560 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
561 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
562 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
563 * so that makes sense.
565 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
566 * to be mapped into the registry on Windows 2000 at least).
567 * I have
568 * woafont=app850.fon
569 * ega80woa.fon=ega80850.fon
570 * ega40woa.fon=ega40850.fon
571 * cga80woa.fon=cga80850.fon
572 * cga40woa.fon=cga40850.fon
575 /* These are all structures needed for the GSUB table */
577 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
578 #define TATEGAKI_LOWER_BOUND 0x02F1
580 typedef struct {
581 DWORD version;
582 WORD ScriptList;
583 WORD FeatureList;
584 WORD LookupList;
585 } GSUB_Header;
587 typedef struct {
588 CHAR ScriptTag[4];
589 WORD Script;
590 } GSUB_ScriptRecord;
592 typedef struct {
593 WORD ScriptCount;
594 GSUB_ScriptRecord ScriptRecord[1];
595 } GSUB_ScriptList;
597 typedef struct {
598 CHAR LangSysTag[4];
599 WORD LangSys;
600 } GSUB_LangSysRecord;
602 typedef struct {
603 WORD DefaultLangSys;
604 WORD LangSysCount;
605 GSUB_LangSysRecord LangSysRecord[1];
606 } GSUB_Script;
608 typedef struct {
609 WORD LookupOrder; /* Reserved */
610 WORD ReqFeatureIndex;
611 WORD FeatureCount;
612 WORD FeatureIndex[1];
613 } GSUB_LangSys;
615 typedef struct {
616 CHAR FeatureTag[4];
617 WORD Feature;
618 } GSUB_FeatureRecord;
620 typedef struct {
621 WORD FeatureCount;
622 GSUB_FeatureRecord FeatureRecord[1];
623 } GSUB_FeatureList;
625 typedef struct {
626 WORD FeatureParams; /* Reserved */
627 WORD LookupCount;
628 WORD LookupListIndex[1];
629 } GSUB_Feature;
631 typedef struct {
632 WORD LookupCount;
633 WORD Lookup[1];
634 } GSUB_LookupList;
636 typedef struct {
637 WORD LookupType;
638 WORD LookupFlag;
639 WORD SubTableCount;
640 WORD SubTable[1];
641 } GSUB_LookupTable;
643 typedef struct {
644 WORD CoverageFormat;
645 WORD GlyphCount;
646 WORD GlyphArray[1];
647 } GSUB_CoverageFormat1;
649 typedef struct {
650 WORD Start;
651 WORD End;
652 WORD StartCoverageIndex;
653 } GSUB_RangeRecord;
655 typedef struct {
656 WORD CoverageFormat;
657 WORD RangeCount;
658 GSUB_RangeRecord RangeRecord[1];
659 } GSUB_CoverageFormat2;
661 typedef struct {
662 WORD SubstFormat; /* = 1 */
663 WORD Coverage;
664 WORD DeltaGlyphID;
665 } GSUB_SingleSubstFormat1;
667 typedef struct {
668 WORD SubstFormat; /* = 2 */
669 WORD Coverage;
670 WORD GlyphCount;
671 WORD Substitute[1];
672 }GSUB_SingleSubstFormat2;
674 #ifdef HAVE_CARBON_CARBON_H
675 static char *find_cache_dir(void)
677 FSRef ref;
678 OSErr err;
679 static char cached_path[MAX_PATH];
680 static const char *wine = "/Wine", *fonts = "/Fonts";
682 if(*cached_path) return cached_path;
684 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
685 if(err != noErr)
687 WARN("can't create cached data folder\n");
688 return NULL;
690 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
691 if(err != noErr)
693 WARN("can't create cached data path\n");
694 *cached_path = '\0';
695 return NULL;
697 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
699 ERR("Could not create full path\n");
700 *cached_path = '\0';
701 return NULL;
703 strcat(cached_path, wine);
705 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
707 WARN("Couldn't mkdir %s\n", cached_path);
708 *cached_path = '\0';
709 return NULL;
711 strcat(cached_path, fonts);
712 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
714 WARN("Couldn't mkdir %s\n", cached_path);
715 *cached_path = '\0';
716 return NULL;
718 return cached_path;
721 /******************************************************************
722 * expand_mac_font
724 * Extracts individual TrueType font files from a Mac suitcase font
725 * and saves them into the user's caches directory (see
726 * find_cache_dir()).
727 * Returns a NULL terminated array of filenames.
729 * We do this because they are apps that try to read ttf files
730 * themselves and they don't like Mac suitcase files.
732 static char **expand_mac_font(const char *path)
734 FSRef ref;
735 SInt16 res_ref;
736 OSStatus s;
737 unsigned int idx;
738 const char *out_dir;
739 const char *filename;
740 int output_len;
741 struct {
742 char **array;
743 unsigned int size, max_size;
744 } ret;
746 TRACE("path %s\n", path);
748 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
749 if(s != noErr)
751 WARN("failed to get ref\n");
752 return NULL;
755 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
756 if(s != noErr)
758 TRACE("no data fork, so trying resource fork\n");
759 res_ref = FSOpenResFile(&ref, fsRdPerm);
760 if(res_ref == -1)
762 TRACE("unable to open resource fork\n");
763 return NULL;
767 ret.size = 0;
768 ret.max_size = 10;
769 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
770 if(!ret.array)
772 CloseResFile(res_ref);
773 return NULL;
776 out_dir = find_cache_dir();
778 filename = strrchr(path, '/');
779 if(!filename) filename = path;
780 else filename++;
782 /* output filename has the form out_dir/filename_%04x.ttf */
783 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
785 UseResFile(res_ref);
786 idx = 1;
787 while(1)
789 FamRec *fam_rec;
790 unsigned short *num_faces_ptr, num_faces, face;
791 AsscEntry *assoc;
792 Handle fond;
793 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
795 fond = Get1IndResource(fond_res, idx);
796 if(!fond) break;
797 TRACE("got fond resource %d\n", idx);
798 HLock(fond);
800 fam_rec = *(FamRec**)fond;
801 num_faces_ptr = (unsigned short *)(fam_rec + 1);
802 num_faces = GET_BE_WORD(*num_faces_ptr);
803 num_faces++;
804 assoc = (AsscEntry*)(num_faces_ptr + 1);
805 TRACE("num faces %04x\n", num_faces);
806 for(face = 0; face < num_faces; face++, assoc++)
808 Handle sfnt;
809 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
810 unsigned short size, font_id;
811 char *output;
813 size = GET_BE_WORD(assoc->fontSize);
814 font_id = GET_BE_WORD(assoc->fontID);
815 if(size != 0)
817 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
818 continue;
821 TRACE("trying to load sfnt id %04x\n", font_id);
822 sfnt = GetResource(sfnt_res, font_id);
823 if(!sfnt)
825 TRACE("can't get sfnt resource %04x\n", font_id);
826 continue;
829 output = HeapAlloc(GetProcessHeap(), 0, output_len);
830 if(output)
832 int fd;
834 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
836 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
837 if(fd != -1 || errno == EEXIST)
839 if(fd != -1)
841 unsigned char *sfnt_data;
843 HLock(sfnt);
844 sfnt_data = *(unsigned char**)sfnt;
845 write(fd, sfnt_data, GetHandleSize(sfnt));
846 HUnlock(sfnt);
847 close(fd);
849 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
851 ret.max_size *= 2;
852 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
854 ret.array[ret.size++] = output;
856 else
858 WARN("unable to create %s\n", output);
859 HeapFree(GetProcessHeap(), 0, output);
862 ReleaseResource(sfnt);
864 HUnlock(fond);
865 ReleaseResource(fond);
866 idx++;
868 CloseResFile(res_ref);
870 return ret.array;
873 #endif /* HAVE_CARBON_CARBON_H */
875 static inline BOOL is_win9x(void)
877 return GetVersion() & 0x80000000;
880 This function builds an FT_Fixed from a double. It fails if the absolute
881 value of the float number is greater than 32768.
883 static inline FT_Fixed FT_FixedFromFloat(double f)
885 return f * 0x10000;
889 This function builds an FT_Fixed from a FIXED. It simply put f.value
890 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
892 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
894 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
898 static const struct list *get_face_list_from_family(const Family *family)
900 if (!list_empty(&family->faces))
901 return &family->faces;
902 else
903 return family->replacement;
906 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
908 Family *family;
909 Face *face;
910 const WCHAR *file;
912 TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
914 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
916 const struct list *face_list;
917 if(face_name && strcmpiW(face_name, family->FamilyName))
918 continue;
919 face_list = get_face_list_from_family(family);
920 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
922 if (!face->file)
923 continue;
924 file = strrchrW(face->file, '/');
925 if(!file)
926 file = face->file;
927 else
928 file++;
929 if(!strcmpiW(file, file_name)) return face;
932 return NULL;
935 static Family *find_family_from_name(const WCHAR *name)
937 Family *family;
939 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
941 if(!strcmpiW(family->FamilyName, name))
942 return family;
945 return NULL;
948 static Family *find_family_from_any_name(const WCHAR *name)
950 Family *family;
952 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
954 if(!strcmpiW(family->FamilyName, name))
955 return family;
956 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
957 return family;
960 return NULL;
963 static void DumpSubstList(void)
965 FontSubst *psub;
967 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
969 if(psub->from.charset != -1 || psub->to.charset != -1)
970 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
971 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
972 else
973 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
974 debugstr_w(psub->to.name));
976 return;
979 static LPWSTR strdupW(LPCWSTR p)
981 LPWSTR ret;
982 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
983 ret = HeapAlloc(GetProcessHeap(), 0, len);
984 memcpy(ret, p, len);
985 return ret;
988 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
989 INT from_charset)
991 FontSubst *element;
993 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
995 if(!strcmpiW(element->from.name, from_name) &&
996 (element->from.charset == from_charset ||
997 element->from.charset == -1))
998 return element;
1001 return NULL;
1004 #define ADD_FONT_SUBST_FORCE 1
1006 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1008 FontSubst *from_exist, *to_exist;
1010 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1012 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1014 list_remove(&from_exist->entry);
1015 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
1016 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
1017 HeapFree(GetProcessHeap(), 0, from_exist);
1018 from_exist = NULL;
1021 if(!from_exist)
1023 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1025 if(to_exist)
1027 HeapFree(GetProcessHeap(), 0, subst->to.name);
1028 subst->to.name = strdupW(to_exist->to.name);
1031 list_add_tail(subst_list, &subst->entry);
1033 return TRUE;
1036 HeapFree(GetProcessHeap(), 0, subst->from.name);
1037 HeapFree(GetProcessHeap(), 0, subst->to.name);
1038 HeapFree(GetProcessHeap(), 0, subst);
1039 return FALSE;
1042 static WCHAR *towstr(UINT cp, const char *str)
1044 int len;
1045 WCHAR *wstr;
1047 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1048 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1049 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1050 return wstr;
1053 static char *strWtoA(UINT cp, const WCHAR *str)
1055 int len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL );
1056 char *ret = HeapAlloc( GetProcessHeap(), 0, len );
1057 WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL );
1058 return ret;
1061 static void split_subst_info(NameCs *nc, LPSTR str)
1063 CHAR *p = strrchr(str, ',');
1065 nc->charset = -1;
1066 if(p && *(p+1)) {
1067 nc->charset = strtol(p+1, NULL, 10);
1068 *p = '\0';
1070 nc->name = towstr(CP_ACP, str);
1073 static void LoadSubstList(void)
1075 FontSubst *psub;
1076 HKEY hkey;
1077 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1078 LPSTR value;
1079 LPVOID data;
1081 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1082 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1083 &hkey) == ERROR_SUCCESS) {
1085 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1086 &valuelen, &datalen, NULL, NULL);
1088 valuelen++; /* returned value doesn't include room for '\0' */
1089 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1090 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1092 dlen = datalen;
1093 vlen = valuelen;
1094 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1095 &dlen) == ERROR_SUCCESS) {
1096 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1098 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1099 split_subst_info(&psub->from, value);
1100 split_subst_info(&psub->to, data);
1102 /* Win 2000 doesn't allow mapping between different charsets
1103 or mapping of DEFAULT_CHARSET */
1104 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1105 psub->to.charset == DEFAULT_CHARSET) {
1106 HeapFree(GetProcessHeap(), 0, psub->to.name);
1107 HeapFree(GetProcessHeap(), 0, psub->from.name);
1108 HeapFree(GetProcessHeap(), 0, psub);
1109 } else {
1110 add_font_subst(&font_subst_list, psub, 0);
1112 /* reset dlen and vlen */
1113 dlen = datalen;
1114 vlen = valuelen;
1116 HeapFree(GetProcessHeap(), 0, data);
1117 HeapFree(GetProcessHeap(), 0, value);
1118 RegCloseKey(hkey);
1123 /*****************************************************************
1124 * get_name_table_entry
1126 * Supply the platform, encoding, language and name ids in req
1127 * and if the name exists the function will fill in the string
1128 * and string_len members. The string is owned by FreeType so
1129 * don't free it. Returns TRUE if the name is found else FALSE.
1131 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1133 FT_SfntName name;
1134 FT_UInt num_names, name_index;
1136 if(FT_IS_SFNT(ft_face))
1138 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1140 for(name_index = 0; name_index < num_names; name_index++)
1142 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1144 if((name.platform_id == req->platform_id) &&
1145 ((name.encoding_id == TT_MS_ID_UNICODE_CS) || (name.encoding_id == TT_MS_ID_SYMBOL_CS)) &&
1146 (name.language_id == req->language_id) &&
1147 (name.name_id == req->name_id))
1149 req->string = name.string;
1150 req->string_len = name.string_len;
1151 return TRUE;
1156 req->string = NULL;
1157 req->string_len = 0;
1158 return FALSE;
1161 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1163 WCHAR *ret = NULL;
1164 FT_SfntName name;
1166 name.platform_id = TT_PLATFORM_MICROSOFT;
1167 name.language_id = language_id;
1168 name.name_id = name_id;
1170 if(get_name_table_entry(ft_face, &name))
1172 FT_UInt i;
1174 /* String is not nul terminated and string_len is a byte length. */
1175 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1176 for(i = 0; i < name.string_len / 2; i++)
1178 WORD *tmp = (WORD *)&name.string[i * 2];
1179 ret[i] = GET_BE_WORD(*tmp);
1181 ret[i] = 0;
1182 TRACE("Got localised name %s\n", debugstr_w(ret));
1185 return ret;
1188 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1190 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1191 if (f1->scalable) return TRUE;
1192 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1193 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1196 static inline void free_face( Face *face )
1198 HeapFree( GetProcessHeap(), 0, face->file );
1199 HeapFree( GetProcessHeap(), 0, face->StyleName );
1200 HeapFree( GetProcessHeap(), 0, face->FullName );
1201 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1202 HeapFree( GetProcessHeap(), 0, face );
1205 static inline void free_family( Family *family )
1207 Face *face, *cursor2;
1209 LIST_FOR_EACH_ENTRY_SAFE( face, cursor2, &family->faces, Face, entry )
1211 list_remove( &face->entry );
1212 free_face( face );
1214 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1215 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1216 HeapFree( GetProcessHeap(), 0, family );
1219 static inline int style_order(const Face *face)
1221 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1223 case NTM_REGULAR:
1224 return 0;
1225 case NTM_BOLD:
1226 return 1;
1227 case NTM_ITALIC:
1228 return 2;
1229 case NTM_BOLD | NTM_ITALIC:
1230 return 3;
1231 default:
1232 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1233 debugstr_w(face->family->FamilyName),
1234 debugstr_w(face->StyleName),
1235 face->ntmFlags);
1236 return 9999;
1240 static BOOL insert_face_in_family_list( Face *face, Family *family )
1242 Face *cursor;
1244 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1246 if (faces_equal( face, cursor ))
1248 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1249 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1250 cursor->font_version, face->font_version);
1252 if (face->font_version <= cursor->font_version)
1254 TRACE("Original font %s is newer so skipping %s\n",
1255 debugstr_w(cursor->file), debugstr_w(face->file));
1256 return FALSE;
1258 else
1260 TRACE("Replacing original %s with %s\n",
1261 debugstr_w(cursor->file), debugstr_w(face->file));
1262 list_add_before( &cursor->entry, &face->entry );
1263 face->family = family;
1264 list_remove( &cursor->entry);
1265 free_face( cursor );
1266 return TRUE;
1269 else
1270 TRACE("Adding new %s\n", debugstr_w(face->file));
1272 if (style_order( face ) < style_order( cursor )) break;
1275 list_add_before( &cursor->entry, &face->entry );
1276 face->family = family;
1277 return TRUE;
1280 /****************************************************************
1281 * NB This function stores the ptrs to the strings to save copying.
1282 * Don't free them after calling.
1284 static Family *create_family( WCHAR *name, WCHAR *english_name )
1286 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1287 family->FamilyName = name;
1288 family->EnglishName = english_name;
1289 list_init( &family->faces );
1290 family->replacement = &family->faces;
1292 return family;
1295 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1297 DWORD type, size = sizeof(DWORD);
1299 if (RegQueryValueExW(hkey, value, NULL, &type, (BYTE *)data, &size) ||
1300 type != REG_DWORD || size != sizeof(DWORD))
1302 *data = 0;
1303 return ERROR_BAD_CONFIGURATION;
1305 return ERROR_SUCCESS;
1308 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1310 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1313 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1315 DWORD needed, strike_index = 0;
1316 HKEY hkey_strike;
1318 /* If we have a File Name key then this is a real font, not just the parent
1319 key of a bunch of non-scalable strikes */
1320 needed = buffer_size;
1321 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1323 Face *face;
1324 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1325 face->cached_enum_data = NULL;
1327 face->file = strdupW( buffer );
1328 face->StyleName = strdupW(face_name);
1330 needed = buffer_size;
1331 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1332 face->FullName = strdupW( buffer );
1333 else
1334 face->FullName = NULL;
1336 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1337 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1338 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1339 reg_load_dword(hkey_face, face_vertical_value, (DWORD*)&face->vertical);
1340 reg_load_dword(hkey_face, face_aa_value, (DWORD*)&face->aa_flags);
1342 needed = sizeof(face->fs);
1343 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1345 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1347 face->scalable = TRUE;
1348 memset(&face->size, 0, sizeof(face->size));
1350 else
1352 face->scalable = FALSE;
1353 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1354 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1355 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1356 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1357 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1359 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1360 face->size.height, face->size.width, face->size.size >> 6,
1361 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1364 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1365 face->fs.fsCsb[0], face->fs.fsCsb[1],
1366 face->fs.fsUsb[0], face->fs.fsUsb[1],
1367 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1369 insert_face_in_family_list(face, family);
1371 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1374 /* load bitmap strikes */
1376 needed = buffer_size;
1377 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1379 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1381 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1382 RegCloseKey(hkey_strike);
1384 needed = buffer_size;
1388 static void load_font_list_from_cache(HKEY hkey_font_cache)
1390 DWORD size, family_index = 0;
1391 Family *family;
1392 HKEY hkey_family;
1393 WCHAR buffer[4096];
1395 size = sizeof(buffer);
1396 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1398 WCHAR *english_family = NULL;
1399 WCHAR *family_name = strdupW( buffer );
1400 DWORD face_index = 0;
1402 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1403 TRACE("opened family key %s\n", debugstr_w(family_name));
1404 size = sizeof(buffer);
1405 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1406 english_family = strdupW( buffer );
1408 family = create_family(family_name, english_family);
1409 list_add_tail(&font_list, &family->entry);
1411 if(english_family)
1413 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1414 subst->from.name = strdupW(english_family);
1415 subst->from.charset = -1;
1416 subst->to.name = strdupW(family_name);
1417 subst->to.charset = -1;
1418 add_font_subst(&font_subst_list, subst, 0);
1421 size = sizeof(buffer);
1422 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1424 WCHAR *face_name = strdupW( buffer );
1425 HKEY hkey_face;
1427 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1429 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1430 RegCloseKey(hkey_face);
1432 HeapFree( GetProcessHeap(), 0, face_name );
1433 size = sizeof(buffer);
1435 RegCloseKey(hkey_family);
1436 size = sizeof(buffer);
1440 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1442 LONG ret;
1443 HKEY hkey_wine_fonts;
1445 /* We don't want to create the fonts key as volatile, so open this first */
1446 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1447 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1448 if(ret != ERROR_SUCCESS)
1450 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1451 return ret;
1454 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1455 KEY_ALL_ACCESS, NULL, hkey, disposition);
1456 RegCloseKey(hkey_wine_fonts);
1457 return ret;
1460 static void add_face_to_cache(Face *face)
1462 HKEY hkey_font_cache, hkey_family, hkey_face;
1463 WCHAR *face_key_name;
1465 create_font_cache_key(&hkey_font_cache, NULL);
1467 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1468 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1469 if(face->family->EnglishName)
1470 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1471 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1473 if(face->scalable)
1474 face_key_name = face->StyleName;
1475 else
1477 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1478 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1479 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1481 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1482 &hkey_face, NULL);
1483 if(!face->scalable)
1484 HeapFree(GetProcessHeap(), 0, face_key_name);
1486 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1487 (strlenW(face->file) + 1) * sizeof(WCHAR));
1488 if (face->FullName)
1489 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1490 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1492 reg_save_dword(hkey_face, face_index_value, face->face_index);
1493 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1494 reg_save_dword(hkey_face, face_version_value, face->font_version);
1495 if (face->vertical) reg_save_dword(hkey_face, face_vertical_value, face->vertical);
1496 if (face->aa_flags) reg_save_dword(hkey_face, face_aa_value, face->aa_flags);
1498 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1500 if(!face->scalable)
1502 reg_save_dword(hkey_face, face_height_value, face->size.height);
1503 reg_save_dword(hkey_face, face_width_value, face->size.width);
1504 reg_save_dword(hkey_face, face_size_value, face->size.size);
1505 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1506 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1507 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1509 RegCloseKey(hkey_face);
1510 RegCloseKey(hkey_family);
1511 RegCloseKey(hkey_font_cache);
1514 static WCHAR *prepend_at(WCHAR *family)
1516 WCHAR *str;
1518 if (!family)
1519 return NULL;
1521 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1522 str[0] = '@';
1523 strcpyW(str + 1, family);
1524 HeapFree(GetProcessHeap(), 0, family);
1525 return str;
1528 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1530 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1531 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1533 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1534 if (!*name)
1536 *name = *english;
1537 *english = NULL;
1539 else if (!strcmpiW( *name, *english ))
1541 HeapFree( GetProcessHeap(), 0, *english );
1542 *english = NULL;
1545 if (vertical)
1547 *name = prepend_at( *name );
1548 *english = prepend_at( *english );
1552 static Family *get_family( FT_Face ft_face, BOOL vertical )
1554 Family *family;
1555 WCHAR *name, *english_name;
1557 get_family_names( ft_face, &name, &english_name, vertical );
1559 family = find_family_from_name( name );
1561 if (!family)
1563 family = create_family( name, english_name );
1564 list_add_tail( &font_list, &family->entry );
1566 if (english_name)
1568 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1569 subst->from.name = strdupW( english_name );
1570 subst->from.charset = -1;
1571 subst->to.name = strdupW( name );
1572 subst->to.charset = -1;
1573 add_font_subst( &font_subst_list, subst, 0 );
1576 else
1578 HeapFree( GetProcessHeap(), 0, name );
1579 HeapFree( GetProcessHeap(), 0, english_name );
1582 return family;
1585 static inline FT_Fixed get_font_version( FT_Face ft_face )
1587 FT_Fixed version = 0;
1588 TT_Header *header;
1590 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1591 if (header) version = header->Font_Revision;
1593 return version;
1596 static inline DWORD get_ntm_flags( FT_Face ft_face )
1598 DWORD flags = 0;
1599 FT_ULong table_size = 0;
1601 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1602 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1603 if (flags == 0) flags = NTM_REGULAR;
1605 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1606 flags |= NTM_PS_OPENTYPE;
1608 return flags;
1611 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1613 int internal_leading = 0;
1614 FT_WinFNT_HeaderRec winfnt_header;
1616 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1617 internal_leading = winfnt_header.internal_leading;
1619 return internal_leading;
1622 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1624 TT_OS2 *os2;
1625 FT_UInt dummy;
1626 CHARSETINFO csi;
1627 FT_WinFNT_HeaderRec winfnt_header;
1628 int i;
1630 memset( fs, 0, sizeof(*fs) );
1632 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1633 if (os2)
1635 fs->fsUsb[0] = os2->ulUnicodeRange1;
1636 fs->fsUsb[1] = os2->ulUnicodeRange2;
1637 fs->fsUsb[2] = os2->ulUnicodeRange3;
1638 fs->fsUsb[3] = os2->ulUnicodeRange4;
1640 if (os2->version == 0)
1642 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1643 fs->fsCsb[0] = FS_LATIN1;
1644 else
1645 fs->fsCsb[0] = FS_SYMBOL;
1647 else
1649 fs->fsCsb[0] = os2->ulCodePageRange1;
1650 fs->fsCsb[1] = os2->ulCodePageRange2;
1653 else
1655 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1657 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1658 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1659 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1660 *fs = csi.fs;
1664 if (fs->fsCsb[0] == 0)
1666 /* let's see if we can find any interesting cmaps */
1667 for (i = 0; i < ft_face->num_charmaps; i++)
1669 switch (ft_face->charmaps[i]->encoding)
1671 case FT_ENCODING_UNICODE:
1672 case FT_ENCODING_APPLE_ROMAN:
1673 fs->fsCsb[0] |= FS_LATIN1;
1674 break;
1675 case FT_ENCODING_MS_SYMBOL:
1676 fs->fsCsb[0] |= FS_SYMBOL;
1677 break;
1678 default:
1679 break;
1685 #define ADDFONT_EXTERNAL_FONT 0x01
1686 #define ADDFONT_FORCE_BITMAP 0x02
1687 #define ADDFONT_ADD_TO_CACHE 0x04
1688 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
1690 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1691 DWORD flags, BOOL vertical, DWORD aa_flags )
1693 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1694 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1696 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
1697 if (!face->StyleName)
1698 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1699 if (!face->StyleName)
1701 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1704 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
1705 if (!face->FullName)
1706 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1707 if (vertical)
1708 face->FullName = prepend_at( face->FullName );
1710 if (file)
1712 face->file = towstr( CP_UNIXCP, file );
1713 face->font_data_ptr = NULL;
1714 face->font_data_size = 0;
1716 else
1718 face->file = NULL;
1719 face->font_data_ptr = font_data_ptr;
1720 face->font_data_size = font_data_size;
1723 face->face_index = face_index;
1724 get_fontsig( ft_face, &face->fs );
1725 face->ntmFlags = get_ntm_flags( ft_face );
1726 face->font_version = get_font_version( ft_face );
1728 if (FT_IS_SCALABLE( ft_face ))
1730 memset( &face->size, 0, sizeof(face->size) );
1731 face->scalable = TRUE;
1733 else
1735 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1736 size->height, size->width, size->size >> 6,
1737 size->x_ppem >> 6, size->y_ppem >> 6);
1738 face->size.height = size->height;
1739 face->size.width = size->width;
1740 face->size.size = size->size;
1741 face->size.x_ppem = size->x_ppem;
1742 face->size.y_ppem = size->y_ppem;
1743 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1744 face->scalable = FALSE;
1747 face->vertical = vertical;
1748 face->external = (flags & ADDFONT_EXTERNAL_FONT) != 0;
1749 face->aa_flags = aa_flags;
1750 face->family = NULL;
1751 face->cached_enum_data = NULL;
1753 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1754 face->fs.fsCsb[0], face->fs.fsCsb[1],
1755 face->fs.fsUsb[0], face->fs.fsUsb[1],
1756 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1758 return face;
1761 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1762 FT_Long face_index, DWORD flags, BOOL vertical, DWORD aa_flags )
1764 Face *face;
1765 Family *family;
1767 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags, vertical, aa_flags );
1768 family = get_family( ft_face, vertical );
1769 if (!insert_face_in_family_list( face, family ))
1771 free_face( face );
1772 return;
1775 if (flags & ADDFONT_ADD_TO_CACHE)
1776 add_face_to_cache( face );
1778 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1779 debugstr_w(face->StyleName));
1782 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1783 FT_Long face_index, BOOL allow_bitmap )
1785 FT_Error err;
1786 TT_OS2 *pOS2;
1787 FT_Face ft_face;
1789 if (file)
1791 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1792 err = pFT_New_Face(library, file, face_index, &ft_face);
1794 else
1796 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1797 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1800 if (err != 0)
1802 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1803 return NULL;
1806 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1807 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1809 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1810 goto fail;
1813 if (!FT_IS_SFNT( ft_face ))
1815 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1817 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1818 goto fail;
1821 else
1823 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1824 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1825 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1827 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1828 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1829 goto fail;
1832 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1833 we don't want to load these. */
1834 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1836 FT_ULong len = 0;
1838 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1840 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1841 goto fail;
1846 if (!ft_face->family_name || !ft_face->style_name)
1848 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1849 goto fail;
1852 return ft_face;
1853 fail:
1854 pFT_Done_Face( ft_face );
1855 return NULL;
1858 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1860 FT_Face ft_face;
1861 FT_Long face_index = 0, num_faces;
1862 INT ret = 0;
1863 DWORD aa_flags = HIWORD( flags );
1865 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1866 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1868 #ifdef HAVE_CARBON_CARBON_H
1869 if(file)
1871 char **mac_list = expand_mac_font(file);
1872 if(mac_list)
1874 BOOL had_one = FALSE;
1875 char **cursor;
1876 for(cursor = mac_list; *cursor; cursor++)
1878 had_one = TRUE;
1879 AddFontToList(*cursor, NULL, 0, flags);
1880 HeapFree(GetProcessHeap(), 0, *cursor);
1882 HeapFree(GetProcessHeap(), 0, mac_list);
1883 if(had_one)
1884 return 1;
1887 #endif /* HAVE_CARBON_CARBON_H */
1889 do {
1890 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_FORCE_BITMAP );
1891 if (!ft_face) return 0;
1893 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1895 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1896 pFT_Done_Face(ft_face);
1897 return 0;
1900 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE, aa_flags);
1901 ++ret;
1903 if (FT_HAS_VERTICAL(ft_face))
1905 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE, aa_flags);
1906 ++ret;
1909 num_faces = ft_face->num_faces;
1910 pFT_Done_Face(ft_face);
1911 } while(num_faces > ++face_index);
1912 return ret;
1915 static void DumpFontList(void)
1917 Family *family;
1918 Face *face;
1919 struct list *family_elem_ptr, *face_elem_ptr;
1921 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1922 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1923 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1924 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1925 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1926 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1927 if(!face->scalable)
1928 TRACE(" %d", face->size.height);
1929 TRACE("\n");
1932 return;
1935 /***********************************************************
1936 * The replacement list is a way to map an entire font
1937 * family onto another family. For example adding
1939 * [HKCU\Software\Wine\Fonts\Replacements]
1940 * "Wingdings"="Winedings"
1942 * would enumerate the Winedings font both as Winedings and
1943 * Wingdings. However if a real Wingdings font is present the
1944 * replacement does not take place.
1947 static void LoadReplaceList(void)
1949 HKEY hkey;
1950 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1951 LPWSTR value;
1952 LPVOID data;
1954 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1955 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1957 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1958 &valuelen, &datalen, NULL, NULL);
1960 valuelen++; /* returned value doesn't include room for '\0' */
1961 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1962 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1964 dlen = datalen;
1965 vlen = valuelen;
1966 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1967 &dlen) == ERROR_SUCCESS) {
1968 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1969 /* "NewName"="Oldname" */
1970 if(!find_family_from_any_name(value))
1972 Family * const family = find_family_from_any_name(data);
1973 if (family != NULL)
1975 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
1976 if (new_family != NULL)
1978 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
1979 new_family->FamilyName = strdupW(value);
1980 new_family->EnglishName = NULL;
1981 list_init(&new_family->faces);
1982 new_family->replacement = &family->faces;
1983 list_add_tail(&font_list, &new_family->entry);
1986 else
1988 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
1991 else
1993 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
1995 /* reset dlen and vlen */
1996 dlen = datalen;
1997 vlen = valuelen;
1999 HeapFree(GetProcessHeap(), 0, data);
2000 HeapFree(GetProcessHeap(), 0, value);
2001 RegCloseKey(hkey);
2005 static const WCHAR *font_links_list[] =
2007 Lucida_Sans_Unicode,
2008 Microsoft_Sans_Serif,
2009 Tahoma
2012 static const struct font_links_defaults_list
2014 /* Keyed off substitution for "MS Shell Dlg" */
2015 const WCHAR *shelldlg;
2016 /* Maximum of four substitutes, plus terminating NULL pointer */
2017 const WCHAR *substitutes[5];
2018 } font_links_defaults_list[] =
2020 /* Non East-Asian */
2021 { Tahoma, /* FIXME unverified ordering */
2022 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2024 /* Below lists are courtesy of
2025 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2027 /* Japanese */
2028 { MS_UI_Gothic,
2029 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2031 /* Chinese Simplified */
2032 { SimSun,
2033 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2035 /* Korean */
2036 { Gulim,
2037 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2039 /* Chinese Traditional */
2040 { PMingLiU,
2041 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2046 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2048 SYSTEM_LINKS *font_link;
2050 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2052 if(!strcmpiW(font_link->font_name, name))
2053 return font_link;
2056 return NULL;
2059 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2061 const WCHAR *value;
2062 int i;
2063 FontSubst *psub;
2064 Family *family;
2065 Face *face;
2066 const WCHAR *file;
2068 if (values)
2070 SYSTEM_LINKS *font_link;
2072 psub = get_font_subst(&font_subst_list, name, -1);
2073 /* Don't store fonts that are only substitutes for other fonts */
2074 if(psub)
2076 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2077 return;
2080 font_link = find_font_link(name);
2081 if (font_link == NULL)
2083 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2084 font_link->font_name = strdupW(name);
2085 list_init(&font_link->links);
2086 list_add_tail(&system_links, &font_link->entry);
2089 memset(&font_link->fs, 0, sizeof font_link->fs);
2090 for (i = 0; values[i] != NULL; i++)
2092 const struct list *face_list;
2093 CHILD_FONT *child_font;
2095 value = values[i];
2096 if (!strcmpiW(name,value))
2097 continue;
2098 psub = get_font_subst(&font_subst_list, value, -1);
2099 if(psub)
2100 value = psub->to.name;
2101 family = find_family_from_name(value);
2102 if (!family)
2103 continue;
2104 file = NULL;
2105 /* Use first extant filename for this Family */
2106 face_list = get_face_list_from_family(family);
2107 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2109 if (!face->file)
2110 continue;
2111 file = strrchrW(face->file, '/');
2112 if (!file)
2113 file = face->file;
2114 else
2115 file++;
2116 break;
2118 if (!file)
2119 continue;
2120 face = find_face_from_filename(file, value);
2121 if(!face)
2123 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2124 continue;
2127 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2128 child_font->face = face;
2129 child_font->font = NULL;
2130 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2131 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2132 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2133 child_font->face->face_index);
2134 list_add_tail(&font_link->links, &child_font->entry);
2136 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2142 /*************************************************************
2143 * init_system_links
2145 static BOOL init_system_links(void)
2147 HKEY hkey;
2148 BOOL ret = FALSE;
2149 DWORD type, max_val, max_data, val_len, data_len, index;
2150 WCHAR *value, *data;
2151 WCHAR *entry, *next;
2152 SYSTEM_LINKS *font_link, *system_font_link;
2153 CHILD_FONT *child_font;
2154 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2155 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2156 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2157 Face *face;
2158 FontSubst *psub;
2159 UINT i, j;
2161 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2163 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2164 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2165 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2166 val_len = max_val + 1;
2167 data_len = max_data;
2168 index = 0;
2169 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2171 psub = get_font_subst(&font_subst_list, value, -1);
2172 /* Don't store fonts that are only substitutes for other fonts */
2173 if(psub)
2175 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2176 goto next;
2178 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2179 font_link->font_name = strdupW(value);
2180 memset(&font_link->fs, 0, sizeof font_link->fs);
2181 list_init(&font_link->links);
2182 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2184 WCHAR *face_name;
2185 CHILD_FONT *child_font;
2187 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2189 next = entry + strlenW(entry) + 1;
2191 face_name = strchrW(entry, ',');
2192 if(face_name)
2194 *face_name++ = 0;
2195 while(isspaceW(*face_name))
2196 face_name++;
2198 psub = get_font_subst(&font_subst_list, face_name, -1);
2199 if(psub)
2200 face_name = psub->to.name;
2202 face = find_face_from_filename(entry, face_name);
2203 if(!face)
2205 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2206 continue;
2209 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2210 child_font->face = face;
2211 child_font->font = NULL;
2212 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2213 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2214 TRACE("Adding file %s index %ld\n",
2215 debugstr_w(child_font->face->file), child_font->face->face_index);
2216 list_add_tail(&font_link->links, &child_font->entry);
2218 list_add_tail(&system_links, &font_link->entry);
2219 next:
2220 val_len = max_val + 1;
2221 data_len = max_data;
2224 HeapFree(GetProcessHeap(), 0, value);
2225 HeapFree(GetProcessHeap(), 0, data);
2226 RegCloseKey(hkey);
2230 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2231 if (!psub) {
2232 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2233 goto skip_internal;
2236 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2238 const FontSubst *psub2;
2239 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2241 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2243 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2244 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2246 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2247 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2249 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2251 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2255 skip_internal:
2257 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2258 that Tahoma has */
2260 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2261 system_font_link->font_name = strdupW(System);
2262 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2263 list_init(&system_font_link->links);
2265 face = find_face_from_filename(tahoma_ttf, Tahoma);
2266 if(face)
2268 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2269 child_font->face = face;
2270 child_font->font = NULL;
2271 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2272 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2273 TRACE("Found Tahoma in %s index %ld\n",
2274 debugstr_w(child_font->face->file), child_font->face->face_index);
2275 list_add_tail(&system_font_link->links, &child_font->entry);
2277 font_link = find_font_link(Tahoma);
2278 if (font_link != NULL)
2280 CHILD_FONT *font_link_entry;
2281 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2283 CHILD_FONT *new_child;
2284 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2285 new_child->face = font_link_entry->face;
2286 new_child->font = NULL;
2287 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2288 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2289 list_add_tail(&system_font_link->links, &new_child->entry);
2292 list_add_tail(&system_links, &system_font_link->entry);
2293 return ret;
2296 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2298 DIR *dir;
2299 struct dirent *dent;
2300 char path[MAX_PATH];
2302 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2304 dir = opendir(dirname);
2305 if(!dir) {
2306 WARN("Can't open directory %s\n", debugstr_a(dirname));
2307 return FALSE;
2309 while((dent = readdir(dir)) != NULL) {
2310 struct stat statbuf;
2312 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2313 continue;
2315 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2317 sprintf(path, "%s/%s", dirname, dent->d_name);
2319 if(stat(path, &statbuf) == -1)
2321 WARN("Can't stat %s\n", debugstr_a(path));
2322 continue;
2324 if(S_ISDIR(statbuf.st_mode))
2325 ReadFontDir(path, external_fonts);
2326 else
2328 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2329 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2330 AddFontToList(path, NULL, 0, addfont_flags);
2333 closedir(dir);
2334 return TRUE;
2337 #ifdef SONAME_LIBFONTCONFIG
2338 static void load_fontconfig_fonts(void)
2340 void *fc_handle = NULL;
2341 FcPattern *pat;
2342 FcObjectSet *os;
2343 FcFontSet *fontset;
2344 int i, len;
2345 char *file;
2346 const char *ext;
2348 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2349 if(!fc_handle) {
2350 TRACE("Wine cannot find the fontconfig library (%s).\n",
2351 SONAME_LIBFONTCONFIG);
2352 return;
2354 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
2355 LOAD_FUNCPTR(FcConfigSubstitute);
2356 LOAD_FUNCPTR(FcFontList);
2357 LOAD_FUNCPTR(FcFontSetDestroy);
2358 LOAD_FUNCPTR(FcInit);
2359 LOAD_FUNCPTR(FcObjectSetAdd);
2360 LOAD_FUNCPTR(FcObjectSetCreate);
2361 LOAD_FUNCPTR(FcObjectSetDestroy);
2362 LOAD_FUNCPTR(FcPatternCreate);
2363 LOAD_FUNCPTR(FcPatternDestroy);
2364 LOAD_FUNCPTR(FcPatternGetBool);
2365 LOAD_FUNCPTR(FcPatternGetInteger);
2366 LOAD_FUNCPTR(FcPatternGetString);
2367 LOAD_FUNCPTR(FcPatternPrint);
2368 #undef LOAD_FUNCPTR
2370 if(!pFcInit()) return;
2372 pat = pFcPatternCreate();
2373 os = pFcObjectSetCreate();
2374 pFcObjectSetAdd(os, FC_FILE);
2375 pFcObjectSetAdd(os, FC_SCALABLE);
2376 pFcObjectSetAdd(os, FC_ANTIALIAS);
2377 pFcObjectSetAdd(os, FC_RGBA);
2378 fontset = pFcFontList(NULL, pat, os);
2379 if(!fontset) return;
2380 for(i = 0; i < fontset->nfont; i++) {
2381 FcBool scalable;
2382 FcBool antialias;
2383 int rgba;
2384 DWORD aa_flags = 0;
2386 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2387 continue;
2388 TRACE("fontconfig: %s\n", file);
2390 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2392 /* We're just interested in OT/TT fonts for now, so this hack just
2393 picks up the scalable fonts without extensions .pf[ab] to save time
2394 loading every other font */
2396 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2398 TRACE("not scalable\n");
2399 continue;
2402 if (pFcPatternGetBool( fontset->fonts[i], FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2403 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2405 if (pFcPatternGetInteger( fontset->fonts[i], FC_RGBA, 0, &rgba ) == FcResultMatch)
2407 switch (rgba)
2409 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2410 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2411 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2412 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2413 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2417 len = strlen( file );
2418 if(len < 4) continue;
2419 ext = &file[ len - 3 ];
2420 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2421 AddFontToList(file, NULL, 0,
2422 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2424 pFcFontSetDestroy(fontset);
2425 pFcObjectSetDestroy(os);
2426 pFcPatternDestroy(pat);
2427 sym_not_found:
2428 return;
2431 #elif defined(HAVE_CARBON_CARBON_H)
2433 static void load_mac_font_callback(const void *value, void *context)
2435 CFStringRef pathStr = value;
2436 CFIndex len;
2437 char* path;
2439 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2440 path = HeapAlloc(GetProcessHeap(), 0, len);
2441 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2443 TRACE("font file %s\n", path);
2444 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2446 HeapFree(GetProcessHeap(), 0, path);
2449 static void load_mac_fonts(void)
2451 CFStringRef removeDupesKey;
2452 CFBooleanRef removeDupesValue;
2453 CFDictionaryRef options;
2454 CTFontCollectionRef col;
2455 CFArrayRef descs;
2456 CFMutableSetRef paths;
2457 CFIndex i;
2459 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2460 removeDupesValue = kCFBooleanTrue;
2461 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2462 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2463 col = CTFontCollectionCreateFromAvailableFonts(options);
2464 if (options) CFRelease(options);
2465 if (!col)
2467 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2468 return;
2471 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2472 CFRelease(col);
2473 if (!descs)
2475 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2476 return;
2479 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2480 if (!paths)
2482 WARN("CFSetCreateMutable failed\n");
2483 CFRelease(descs);
2484 return;
2487 for (i = 0; i < CFArrayGetCount(descs); i++)
2489 CTFontDescriptorRef desc;
2490 CTFontRef font;
2491 ATSFontRef atsFont;
2492 OSStatus status;
2493 FSRef fsref;
2494 CFURLRef url;
2495 CFStringRef ext;
2496 CFStringRef path;
2498 desc = CFArrayGetValueAtIndex(descs, i);
2500 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2501 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2502 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2503 if (!font) continue;
2505 atsFont = CTFontGetPlatformFont(font, NULL);
2506 if (!atsFont)
2508 CFRelease(font);
2509 continue;
2512 status = ATSFontGetFileReference(atsFont, &fsref);
2513 CFRelease(font);
2514 if (status != noErr) continue;
2516 url = CFURLCreateFromFSRef(NULL, &fsref);
2517 if (!url) continue;
2519 ext = CFURLCopyPathExtension(url);
2520 if (ext)
2522 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2523 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2524 CFRelease(ext);
2525 if (skip)
2527 CFRelease(url);
2528 continue;
2532 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2533 CFRelease(url);
2534 if (!path) continue;
2536 CFSetAddValue(paths, path);
2537 CFRelease(path);
2540 CFRelease(descs);
2542 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2543 CFRelease(paths);
2546 #endif
2548 static BOOL load_font_from_data_dir(LPCWSTR file)
2550 BOOL ret = FALSE;
2551 const char *data_dir = wine_get_data_dir();
2553 if (!data_dir) data_dir = wine_get_build_dir();
2555 if (data_dir)
2557 INT len;
2558 char *unix_name;
2560 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2562 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2564 strcpy(unix_name, data_dir);
2565 strcat(unix_name, "/fonts/");
2567 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2569 EnterCriticalSection( &freetype_cs );
2570 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2571 LeaveCriticalSection( &freetype_cs );
2572 HeapFree(GetProcessHeap(), 0, unix_name);
2574 return ret;
2577 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2579 static const WCHAR slashW[] = {'\\','\0'};
2580 BOOL ret = FALSE;
2581 WCHAR windowsdir[MAX_PATH];
2582 char *unixname;
2584 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2585 strcatW(windowsdir, fontsW);
2586 strcatW(windowsdir, slashW);
2587 strcatW(windowsdir, file);
2588 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2589 EnterCriticalSection( &freetype_cs );
2590 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2591 LeaveCriticalSection( &freetype_cs );
2592 HeapFree(GetProcessHeap(), 0, unixname);
2594 return ret;
2597 static void load_system_fonts(void)
2599 HKEY hkey;
2600 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2601 const WCHAR * const *value;
2602 DWORD dlen, type;
2603 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2604 char *unixname;
2606 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2607 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2608 strcatW(windowsdir, fontsW);
2609 for(value = SystemFontValues; *value; value++) {
2610 dlen = sizeof(data);
2611 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2612 type == REG_SZ) {
2613 BOOL added = FALSE;
2615 sprintfW(pathW, fmtW, windowsdir, data);
2616 if((unixname = wine_get_unix_file_name(pathW))) {
2617 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2618 HeapFree(GetProcessHeap(), 0, unixname);
2620 if (!added)
2621 load_font_from_data_dir(data);
2624 RegCloseKey(hkey);
2628 /*************************************************************
2630 * This adds registry entries for any externally loaded fonts
2631 * (fonts from fontconfig or FontDirs). It also deletes entries
2632 * of no longer existing fonts.
2635 static void update_reg_entries(void)
2637 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2638 LPWSTR valueW;
2639 DWORD len;
2640 Family *family;
2641 Face *face;
2642 struct list *family_elem_ptr, *face_elem_ptr;
2643 WCHAR *file, *path;
2644 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2646 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2647 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2648 ERR("Can't create Windows font reg key\n");
2649 goto end;
2652 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2653 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2654 ERR("Can't create Windows font reg key\n");
2655 goto end;
2658 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2659 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2660 ERR("Can't create external font reg key\n");
2661 goto end;
2664 /* enumerate the fonts and add external ones to the two keys */
2666 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2667 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2668 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2669 char *buffer;
2670 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2671 if(!face->external) continue;
2673 if(face->FullName)
2675 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2676 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2677 strcpyW(valueW, face->FullName);
2679 else
2681 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2682 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2683 strcpyW(valueW, family->FamilyName);
2686 buffer = strWtoA( CP_UNIXCP, face->file );
2687 path = wine_get_dos_file_name( buffer );
2688 HeapFree( GetProcessHeap(), 0, buffer );
2690 if (path)
2691 file = path;
2692 else if ((file = strrchrW(face->file, '/')))
2693 file++;
2694 else
2695 file = face->file;
2697 len = strlenW(file) + 1;
2698 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2699 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2700 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2702 HeapFree(GetProcessHeap(), 0, path);
2703 HeapFree(GetProcessHeap(), 0, valueW);
2706 end:
2707 if(external_key) RegCloseKey(external_key);
2708 if(win9x_key) RegCloseKey(win9x_key);
2709 if(winnt_key) RegCloseKey(winnt_key);
2710 return;
2713 static void delete_external_font_keys(void)
2715 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2716 DWORD dlen, vlen, datalen, valuelen, i, type;
2717 LPWSTR valueW;
2718 LPVOID data;
2720 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2721 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2722 ERR("Can't create Windows font reg key\n");
2723 goto end;
2726 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2727 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2728 ERR("Can't create Windows font reg key\n");
2729 goto end;
2732 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2733 ERR("Can't create external font reg key\n");
2734 goto end;
2737 /* Delete all external fonts added last time */
2739 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2740 &valuelen, &datalen, NULL, NULL);
2741 valuelen++; /* returned value doesn't include room for '\0' */
2742 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2743 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2745 dlen = datalen * sizeof(WCHAR);
2746 vlen = valuelen;
2747 i = 0;
2748 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2749 &dlen) == ERROR_SUCCESS) {
2751 RegDeleteValueW(winnt_key, valueW);
2752 RegDeleteValueW(win9x_key, valueW);
2753 /* reset dlen and vlen */
2754 dlen = datalen;
2755 vlen = valuelen;
2757 HeapFree(GetProcessHeap(), 0, data);
2758 HeapFree(GetProcessHeap(), 0, valueW);
2760 /* Delete the old external fonts key */
2761 RegCloseKey(external_key);
2762 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2764 end:
2765 if(win9x_key) RegCloseKey(win9x_key);
2766 if(winnt_key) RegCloseKey(winnt_key);
2769 /*************************************************************
2770 * WineEngAddFontResourceEx
2773 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2775 INT ret = 0;
2777 GDI_CheckNotLock();
2779 if (ft_handle) /* do it only if we have freetype up and running */
2781 char *unixname;
2783 if(flags)
2784 FIXME("Ignoring flags %x\n", flags);
2786 if((unixname = wine_get_unix_file_name(file)))
2788 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2790 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2791 EnterCriticalSection( &freetype_cs );
2792 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2793 LeaveCriticalSection( &freetype_cs );
2794 HeapFree(GetProcessHeap(), 0, unixname);
2796 if (!ret && !strchrW(file, '\\')) {
2797 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2798 ret = load_font_from_winfonts_dir(file);
2799 if (!ret) {
2800 /* Try in datadir/fonts (or builddir/fonts),
2801 * needed for Magic the Gathering Online
2803 ret = load_font_from_data_dir(file);
2807 return ret;
2810 /*************************************************************
2811 * WineEngAddFontMemResourceEx
2814 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2816 GDI_CheckNotLock();
2818 if (ft_handle) /* do it only if we have freetype up and running */
2820 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2822 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2823 memcpy(pFontCopy, pbFont, cbFont);
2825 EnterCriticalSection( &freetype_cs );
2826 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2827 LeaveCriticalSection( &freetype_cs );
2829 if (*pcFonts == 0)
2831 TRACE("AddFontToList failed\n");
2832 HeapFree(GetProcessHeap(), 0, pFontCopy);
2833 return 0;
2835 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2836 * For now return something unique but quite random
2838 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2839 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2842 *pcFonts = 0;
2843 return 0;
2846 /*************************************************************
2847 * WineEngRemoveFontResourceEx
2850 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2852 GDI_CheckNotLock();
2853 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2854 return TRUE;
2857 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
2859 WCHAR *fullname;
2860 char *unix_name;
2861 int file_len;
2863 if (!font_file) return NULL;
2865 file_len = strlenW( font_file );
2867 if (font_path && font_path[0])
2869 int path_len = strlenW( font_path );
2870 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
2871 if (!fullname) return NULL;
2872 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
2873 fullname[path_len] = '\\';
2874 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
2876 else
2878 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
2879 if (!len) return NULL;
2880 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2881 if (!fullname) return NULL;
2882 GetFullPathNameW( font_file, len, fullname, NULL );
2885 unix_name = wine_get_unix_file_name( fullname );
2886 HeapFree( GetProcessHeap(), 0, fullname );
2887 return unix_name;
2890 #include <pshpack1.h>
2891 struct fontdir
2893 WORD num_of_resources;
2894 WORD res_id;
2895 WORD dfVersion;
2896 DWORD dfSize;
2897 CHAR dfCopyright[60];
2898 WORD dfType;
2899 WORD dfPoints;
2900 WORD dfVertRes;
2901 WORD dfHorizRes;
2902 WORD dfAscent;
2903 WORD dfInternalLeading;
2904 WORD dfExternalLeading;
2905 BYTE dfItalic;
2906 BYTE dfUnderline;
2907 BYTE dfStrikeOut;
2908 WORD dfWeight;
2909 BYTE dfCharSet;
2910 WORD dfPixWidth;
2911 WORD dfPixHeight;
2912 BYTE dfPitchAndFamily;
2913 WORD dfAvgWidth;
2914 WORD dfMaxWidth;
2915 BYTE dfFirstChar;
2916 BYTE dfLastChar;
2917 BYTE dfDefaultChar;
2918 BYTE dfBreakChar;
2919 WORD dfWidthBytes;
2920 DWORD dfDevice;
2921 DWORD dfFace;
2922 DWORD dfReserved;
2923 CHAR szFaceName[LF_FACESIZE];
2926 #include <poppack.h>
2928 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2929 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
2931 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
2933 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
2934 Face *face;
2935 Family *family;
2936 WCHAR *name, *english_name;
2937 ENUMLOGFONTEXW elf;
2938 NEWTEXTMETRICEXW ntm;
2939 DWORD type;
2941 if (!ft_face) return FALSE;
2942 face = create_face( ft_face, 0, unix_name, NULL, 0, 0, FALSE, 0 );
2943 get_family_names( ft_face, &name, &english_name, FALSE );
2944 family = create_family( name, english_name );
2945 insert_face_in_family_list( face, family );
2946 pFT_Done_Face( ft_face );
2948 GetEnumStructs( face, &elf, &ntm, &type );
2949 free_family( family );
2951 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
2953 memset( fd, 0, sizeof(*fd) );
2955 fd->num_of_resources = 1;
2956 fd->res_id = 0;
2957 fd->dfVersion = 0x200;
2958 fd->dfSize = sizeof(*fd);
2959 strcpy( fd->dfCopyright, "Wine fontdir" );
2960 fd->dfType = 0x4003; /* 0x0080 set if private */
2961 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
2962 fd->dfVertRes = 72;
2963 fd->dfHorizRes = 72;
2964 fd->dfAscent = ntm.ntmTm.tmAscent;
2965 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
2966 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
2967 fd->dfItalic = ntm.ntmTm.tmItalic;
2968 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
2969 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
2970 fd->dfWeight = ntm.ntmTm.tmWeight;
2971 fd->dfCharSet = ntm.ntmTm.tmCharSet;
2972 fd->dfPixWidth = 0;
2973 fd->dfPixHeight = ntm.ntmTm.tmHeight;
2974 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
2975 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
2976 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
2977 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
2978 fd->dfLastChar = ntm.ntmTm.tmLastChar;
2979 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
2980 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
2981 fd->dfWidthBytes = 0;
2982 fd->dfDevice = 0;
2983 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
2984 fd->dfReserved = 0;
2985 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
2987 return TRUE;
2990 #define NE_FFLAGS_LIBMODULE 0x8000
2991 #define NE_OSFLAGS_WINDOWS 0x02
2993 static const char dos_string[0x40] = "This is a TrueType resource file";
2994 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
2996 #include <pshpack2.h>
2998 struct ne_typeinfo
3000 WORD type_id;
3001 WORD count;
3002 DWORD res;
3005 struct ne_nameinfo
3007 WORD off;
3008 WORD len;
3009 WORD flags;
3010 WORD id;
3011 DWORD res;
3014 struct rsrc_tab
3016 WORD align;
3017 struct ne_typeinfo fontdir_type;
3018 struct ne_nameinfo fontdir_name;
3019 struct ne_typeinfo scalable_type;
3020 struct ne_nameinfo scalable_name;
3021 WORD end_of_rsrc;
3022 BYTE fontdir_res_name[8];
3025 #include <poppack.h>
3027 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3029 BOOL ret = FALSE;
3030 HANDLE file;
3031 DWORD size, written;
3032 BYTE *ptr, *start;
3033 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3034 char *font_fileA, *last_part, *ext;
3035 IMAGE_DOS_HEADER dos;
3036 IMAGE_OS2_HEADER ne =
3038 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3039 0, 0, 0, 0, 0, 0,
3040 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3041 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3043 struct rsrc_tab rsrc_tab =
3046 { 0x8007, 1, 0 },
3047 { 0, 0, 0x0c50, 0x2c, 0 },
3048 { 0x80cc, 1, 0 },
3049 { 0, 0, 0x0c50, 0x8001, 0 },
3051 { 7,'F','O','N','T','D','I','R'}
3054 memset( &dos, 0, sizeof(dos) );
3055 dos.e_magic = IMAGE_DOS_SIGNATURE;
3056 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3058 /* import name is last part\0, resident name is last part without extension
3059 non-resident name is "FONTRES:" + lfFaceName */
3061 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3062 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3063 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3065 last_part = strrchr( font_fileA, '\\' );
3066 if (last_part) last_part++;
3067 else last_part = font_fileA;
3068 import_name_len = strlen( last_part ) + 1;
3070 ext = strchr( last_part, '.' );
3071 if (ext) res_name_len = ext - last_part;
3072 else res_name_len = import_name_len - 1;
3074 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3076 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3077 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3078 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3079 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3080 ne.ne_cbenttab = 2;
3081 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3083 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3084 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3085 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3086 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3088 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3089 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3091 if (!ptr)
3093 HeapFree( GetProcessHeap(), 0, font_fileA );
3094 return FALSE;
3097 memcpy( ptr, &dos, sizeof(dos) );
3098 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3099 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3101 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3102 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3104 ptr = start + dos.e_lfanew + ne.ne_restab;
3105 *ptr++ = res_name_len;
3106 memcpy( ptr, last_part, res_name_len );
3108 ptr = start + dos.e_lfanew + ne.ne_imptab;
3109 *ptr++ = import_name_len;
3110 memcpy( ptr, last_part, import_name_len );
3112 ptr = start + ne.ne_nrestab;
3113 *ptr++ = non_res_name_len;
3114 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3115 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3117 ptr = start + (rsrc_tab.scalable_name.off << 4);
3118 memcpy( ptr, font_fileA, font_file_len );
3120 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3121 memcpy( ptr, fontdir, fontdir->dfSize );
3123 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3124 if (file != INVALID_HANDLE_VALUE)
3126 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3127 ret = TRUE;
3128 CloseHandle( file );
3131 HeapFree( GetProcessHeap(), 0, start );
3132 HeapFree( GetProcessHeap(), 0, font_fileA );
3134 return ret;
3137 /*************************************************************
3138 * WineEngCreateScalableFontResource
3141 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3142 LPCWSTR font_file, LPCWSTR font_path )
3144 char *unix_name = get_ttf_file_name( font_file, font_path );
3145 struct fontdir fontdir;
3146 BOOL ret = FALSE;
3148 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3149 SetLastError( ERROR_INVALID_PARAMETER );
3150 else
3152 if (hidden) fontdir.dfType |= 0x80;
3153 ret = create_fot( resource, font_file, &fontdir );
3156 HeapFree( GetProcessHeap(), 0, unix_name );
3157 return ret;
3160 static const struct nls_update_font_list
3162 UINT ansi_cp, oem_cp;
3163 const char *oem, *fixed, *system;
3164 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3165 /* these are for font substitutes */
3166 const char *shelldlg, *tmsrmn;
3167 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3168 *helv_0, *tmsrmn_0;
3169 const struct subst
3171 const char *from, *to;
3172 } arial_0, courier_new_0, times_new_roman_0;
3173 } nls_update_font_list[] =
3175 /* Latin 1 (United States) */
3176 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3177 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3178 "Tahoma","Times New Roman",
3179 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3180 { 0 }, { 0 }, { 0 }
3182 /* Latin 1 (Multilingual) */
3183 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3184 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3185 "Tahoma","Times New Roman", /* FIXME unverified */
3186 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3187 { 0 }, { 0 }, { 0 }
3189 /* Eastern Europe */
3190 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3191 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3192 "Tahoma","Times New Roman", /* FIXME unverified */
3193 "Fixedsys,238", "System,238",
3194 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3195 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3196 { "Arial CE,0", "Arial,238" },
3197 { "Courier New CE,0", "Courier New,238" },
3198 { "Times New Roman CE,0", "Times New Roman,238" }
3200 /* Cyrillic */
3201 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3202 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3203 "Tahoma","Times New Roman", /* FIXME unverified */
3204 "Fixedsys,204", "System,204",
3205 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3206 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3207 { "Arial Cyr,0", "Arial,204" },
3208 { "Courier New Cyr,0", "Courier New,204" },
3209 { "Times New Roman Cyr,0", "Times New Roman,204" }
3211 /* Greek */
3212 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3213 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3214 "Tahoma","Times New Roman", /* FIXME unverified */
3215 "Fixedsys,161", "System,161",
3216 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3217 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3218 { "Arial Greek,0", "Arial,161" },
3219 { "Courier New Greek,0", "Courier New,161" },
3220 { "Times New Roman Greek,0", "Times New Roman,161" }
3222 /* Turkish */
3223 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3224 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3225 "Tahoma","Times New Roman", /* FIXME unverified */
3226 "Fixedsys,162", "System,162",
3227 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3228 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3229 { "Arial Tur,0", "Arial,162" },
3230 { "Courier New Tur,0", "Courier New,162" },
3231 { "Times New Roman Tur,0", "Times New Roman,162" }
3233 /* Hebrew */
3234 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3235 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3236 "Tahoma","Times New Roman", /* FIXME unverified */
3237 "Fixedsys,177", "System,177",
3238 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3239 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3240 { 0 }, { 0 }, { 0 }
3242 /* Arabic */
3243 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3244 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3245 "Tahoma","Times New Roman", /* FIXME unverified */
3246 "Fixedsys,178", "System,178",
3247 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3248 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3249 { 0 }, { 0 }, { 0 }
3251 /* Baltic */
3252 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3253 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3254 "Tahoma","Times New Roman", /* FIXME unverified */
3255 "Fixedsys,186", "System,186",
3256 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3257 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3258 { "Arial Baltic,0", "Arial,186" },
3259 { "Courier New Baltic,0", "Courier New,186" },
3260 { "Times New Roman Baltic,0", "Times New Roman,186" }
3262 /* Vietnamese */
3263 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3264 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3265 "Tahoma","Times New Roman", /* FIXME unverified */
3266 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3267 { 0 }, { 0 }, { 0 }
3269 /* Thai */
3270 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3271 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3272 "Tahoma","Times New Roman", /* FIXME unverified */
3273 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3274 { 0 }, { 0 }, { 0 }
3276 /* Japanese */
3277 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3278 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3279 "MS UI Gothic","MS Serif",
3280 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3281 { 0 }, { 0 }, { 0 }
3283 /* Chinese Simplified */
3284 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3285 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3286 "SimSun", "NSimSun",
3287 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3288 { 0 }, { 0 }, { 0 }
3290 /* Korean */
3291 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3292 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3293 "Gulim", "Batang",
3294 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3295 { 0 }, { 0 }, { 0 }
3297 /* Chinese Traditional */
3298 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3299 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3300 "PMingLiU", "MingLiU",
3301 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3302 { 0 }, { 0 }, { 0 }
3306 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3308 return ( ansi_cp == 932 /* CP932 for Japanese */
3309 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3310 || ansi_cp == 949 /* CP949 for Korean */
3311 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3314 static inline HKEY create_fonts_NT_registry_key(void)
3316 HKEY hkey = 0;
3318 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3319 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3320 return hkey;
3323 static inline HKEY create_fonts_9x_registry_key(void)
3325 HKEY hkey = 0;
3327 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3328 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3329 return hkey;
3332 static inline HKEY create_config_fonts_registry_key(void)
3334 HKEY hkey = 0;
3336 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3337 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3338 return hkey;
3341 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3343 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3345 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3346 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3347 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3348 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3351 static void set_value_key(HKEY hkey, const char *name, const char *value)
3353 if (value)
3354 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3355 else if (name)
3356 RegDeleteValueA(hkey, name);
3359 static void update_font_info(void)
3361 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3362 char buf[40], cpbuf[40];
3363 DWORD len, type;
3364 HKEY hkey = 0;
3365 UINT i, ansi_cp = 0, oem_cp = 0;
3366 DWORD screen_dpi = 96, font_dpi = 0;
3367 BOOL done = FALSE;
3369 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3370 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3371 &hkey) == ERROR_SUCCESS)
3373 reg_load_dword(hkey, logpixels, &screen_dpi);
3374 RegCloseKey(hkey);
3377 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3378 return;
3380 reg_load_dword(hkey, logpixels, &font_dpi);
3382 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3383 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3384 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3385 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3386 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3388 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3389 if (is_dbcs_ansi_cp(ansi_cp))
3390 use_default_fallback = TRUE;
3392 len = sizeof(buf);
3393 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3395 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3397 RegCloseKey(hkey);
3398 return;
3400 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3401 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3403 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3404 ansi_cp, oem_cp, screen_dpi);
3406 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3407 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3408 RegCloseKey(hkey);
3410 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3412 HKEY hkey;
3414 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3415 nls_update_font_list[i].oem_cp == oem_cp)
3417 hkey = create_config_fonts_registry_key();
3418 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3419 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3420 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3421 RegCloseKey(hkey);
3423 hkey = create_fonts_NT_registry_key();
3424 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3425 RegCloseKey(hkey);
3427 hkey = create_fonts_9x_registry_key();
3428 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3429 RegCloseKey(hkey);
3431 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3433 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3434 strlen(nls_update_font_list[i].shelldlg)+1);
3435 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3436 strlen(nls_update_font_list[i].tmsrmn)+1);
3438 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3439 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3440 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3441 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3442 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3443 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3444 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3445 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3447 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3448 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3449 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3451 RegCloseKey(hkey);
3453 done = TRUE;
3455 else
3457 /* Delete the FontSubstitutes from other locales */
3458 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3460 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3461 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3462 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3463 RegCloseKey(hkey);
3467 if (!done)
3468 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3471 static BOOL init_freetype(void)
3473 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3474 if(!ft_handle) {
3475 WINE_MESSAGE(
3476 "Wine cannot find the FreeType font library. To enable Wine to\n"
3477 "use TrueType fonts please install a version of FreeType greater than\n"
3478 "or equal to 2.0.5.\n"
3479 "http://www.freetype.org\n");
3480 return FALSE;
3483 #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;}
3485 LOAD_FUNCPTR(FT_Done_Face)
3486 LOAD_FUNCPTR(FT_Get_Char_Index)
3487 LOAD_FUNCPTR(FT_Get_First_Char)
3488 LOAD_FUNCPTR(FT_Get_Module)
3489 LOAD_FUNCPTR(FT_Get_Next_Char)
3490 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3491 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3492 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3493 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3494 LOAD_FUNCPTR(FT_Init_FreeType)
3495 LOAD_FUNCPTR(FT_Library_Version)
3496 LOAD_FUNCPTR(FT_Load_Glyph)
3497 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3498 LOAD_FUNCPTR(FT_Matrix_Multiply)
3499 #ifndef FT_MULFIX_INLINED
3500 LOAD_FUNCPTR(FT_MulFix)
3501 #endif
3502 LOAD_FUNCPTR(FT_New_Face)
3503 LOAD_FUNCPTR(FT_New_Memory_Face)
3504 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3505 LOAD_FUNCPTR(FT_Outline_Transform)
3506 LOAD_FUNCPTR(FT_Outline_Translate)
3507 LOAD_FUNCPTR(FT_Render_Glyph)
3508 LOAD_FUNCPTR(FT_Select_Charmap)
3509 LOAD_FUNCPTR(FT_Set_Charmap)
3510 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3511 LOAD_FUNCPTR(FT_Vector_Transform)
3512 LOAD_FUNCPTR(FT_Vector_Unit)
3513 #undef LOAD_FUNCPTR
3514 /* Don't warn if these ones are missing */
3515 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3516 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3517 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3518 #endif
3520 if(pFT_Init_FreeType(&library) != 0) {
3521 ERR("Can't init FreeType library\n");
3522 wine_dlclose(ft_handle, NULL, 0);
3523 ft_handle = NULL;
3524 return FALSE;
3526 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3528 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3529 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3530 ((FT_Version.minor << 8) & 0x00ff00) |
3531 ((FT_Version.patch ) & 0x0000ff);
3533 font_driver = &freetype_funcs;
3534 return TRUE;
3536 sym_not_found:
3537 WINE_MESSAGE(
3538 "Wine cannot find certain functions that it needs inside the FreeType\n"
3539 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3540 "FreeType to at least version 2.1.4.\n"
3541 "http://www.freetype.org\n");
3542 wine_dlclose(ft_handle, NULL, 0);
3543 ft_handle = NULL;
3544 return FALSE;
3547 static void init_font_list(void)
3549 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3550 static const WCHAR pathW[] = {'P','a','t','h',0};
3551 HKEY hkey;
3552 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3553 WCHAR windowsdir[MAX_PATH];
3554 char *unixname;
3555 const char *data_dir;
3557 delete_external_font_keys();
3559 /* load the system bitmap fonts */
3560 load_system_fonts();
3562 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3563 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3564 strcatW(windowsdir, fontsW);
3565 if((unixname = wine_get_unix_file_name(windowsdir)))
3567 ReadFontDir(unixname, FALSE);
3568 HeapFree(GetProcessHeap(), 0, unixname);
3571 /* load the system truetype fonts */
3572 data_dir = wine_get_data_dir();
3573 if (!data_dir) data_dir = wine_get_build_dir();
3574 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3576 strcpy(unixname, data_dir);
3577 strcat(unixname, "/fonts/");
3578 ReadFontDir(unixname, TRUE);
3579 HeapFree(GetProcessHeap(), 0, unixname);
3582 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3583 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3584 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3585 will skip these. */
3586 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3587 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3588 &hkey) == ERROR_SUCCESS)
3590 LPWSTR data, valueW;
3591 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3592 &valuelen, &datalen, NULL, NULL);
3594 valuelen++; /* returned value doesn't include room for '\0' */
3595 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3596 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3597 if (valueW && data)
3599 dlen = datalen * sizeof(WCHAR);
3600 vlen = valuelen;
3601 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3602 &dlen) == ERROR_SUCCESS)
3604 if(data[0] && (data[1] == ':'))
3606 if((unixname = wine_get_unix_file_name(data)))
3608 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3609 HeapFree(GetProcessHeap(), 0, unixname);
3612 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3614 WCHAR pathW[MAX_PATH];
3615 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3616 BOOL added = FALSE;
3618 sprintfW(pathW, fmtW, windowsdir, data);
3619 if((unixname = wine_get_unix_file_name(pathW)))
3621 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3622 HeapFree(GetProcessHeap(), 0, unixname);
3624 if (!added)
3625 load_font_from_data_dir(data);
3627 /* reset dlen and vlen */
3628 dlen = datalen;
3629 vlen = valuelen;
3632 HeapFree(GetProcessHeap(), 0, data);
3633 HeapFree(GetProcessHeap(), 0, valueW);
3634 RegCloseKey(hkey);
3637 #ifdef SONAME_LIBFONTCONFIG
3638 load_fontconfig_fonts();
3639 #elif defined(HAVE_CARBON_CARBON_H)
3640 load_mac_fonts();
3641 #endif
3643 /* then look in any directories that we've specified in the config file */
3644 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3645 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3647 DWORD len;
3648 LPWSTR valueW;
3649 LPSTR valueA, ptr;
3651 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3653 len += sizeof(WCHAR);
3654 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3655 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3657 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3658 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3659 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3660 TRACE( "got font path %s\n", debugstr_a(valueA) );
3661 ptr = valueA;
3662 while (ptr)
3664 const char* home;
3665 LPSTR next = strchr( ptr, ':' );
3666 if (next) *next++ = 0;
3667 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3668 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3670 strcpy( unixname, home );
3671 strcat( unixname, ptr + 1 );
3672 ReadFontDir( unixname, TRUE );
3673 HeapFree( GetProcessHeap(), 0, unixname );
3675 else
3676 ReadFontDir( ptr, TRUE );
3677 ptr = next;
3679 HeapFree( GetProcessHeap(), 0, valueA );
3681 HeapFree( GetProcessHeap(), 0, valueW );
3683 RegCloseKey(hkey);
3687 static BOOL move_to_front(const WCHAR *name)
3689 Family *family, *cursor2;
3690 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3692 if(!strcmpiW(family->FamilyName, name))
3694 list_remove(&family->entry);
3695 list_add_head(&font_list, &family->entry);
3696 return TRUE;
3699 return FALSE;
3702 static BOOL set_default(const WCHAR **name_list)
3704 while (*name_list)
3706 if (move_to_front(*name_list)) return TRUE;
3707 name_list++;
3710 return FALSE;
3713 static void reorder_font_list(void)
3715 set_default( default_serif_list );
3716 set_default( default_fixed_list );
3717 set_default( default_sans_list );
3720 /*************************************************************
3721 * WineEngInit
3723 * Initialize FreeType library and create a list of available faces
3725 BOOL WineEngInit(void)
3727 HKEY hkey_font_cache;
3728 DWORD disposition;
3729 HANDLE font_mutex;
3731 /* update locale dependent font info in registry */
3732 update_font_info();
3734 if(!init_freetype()) return FALSE;
3736 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3738 ERR("Failed to create font mutex\n");
3739 return FALSE;
3741 WaitForSingleObject(font_mutex, INFINITE);
3743 create_font_cache_key(&hkey_font_cache, &disposition);
3745 if(disposition == REG_CREATED_NEW_KEY)
3746 init_font_list();
3747 else
3748 load_font_list_from_cache(hkey_font_cache);
3750 RegCloseKey(hkey_font_cache);
3752 reorder_font_list();
3754 DumpFontList();
3755 LoadSubstList();
3756 DumpSubstList();
3757 LoadReplaceList();
3759 if(disposition == REG_CREATED_NEW_KEY)
3760 update_reg_entries();
3762 init_system_links();
3764 ReleaseMutex(font_mutex);
3765 return TRUE;
3769 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3771 TT_OS2 *pOS2;
3772 TT_HoriHeader *pHori;
3774 LONG ppem;
3776 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3777 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3779 if(height == 0) height = 16;
3781 /* Calc. height of EM square:
3783 * For +ve lfHeight we have
3784 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3785 * Re-arranging gives:
3786 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3788 * For -ve lfHeight we have
3789 * |lfHeight| = ppem
3790 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3791 * with il = winAscent + winDescent - units_per_em]
3795 if(height > 0) {
3796 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3797 ppem = MulDiv(ft_face->units_per_EM, height,
3798 pHori->Ascender - pHori->Descender);
3799 else
3800 ppem = MulDiv(ft_face->units_per_EM, height,
3801 pOS2->usWinAscent + pOS2->usWinDescent);
3803 else
3804 ppem = -height;
3806 return ppem;
3809 static struct font_mapping *map_font_file( const char *name )
3811 struct font_mapping *mapping;
3812 struct stat st;
3813 int fd;
3815 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3816 if (fstat( fd, &st ) == -1) goto error;
3818 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3820 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3822 mapping->refcount++;
3823 close( fd );
3824 return mapping;
3827 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3828 goto error;
3830 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3831 close( fd );
3833 if (mapping->data == MAP_FAILED)
3835 HeapFree( GetProcessHeap(), 0, mapping );
3836 return NULL;
3838 mapping->refcount = 1;
3839 mapping->dev = st.st_dev;
3840 mapping->ino = st.st_ino;
3841 mapping->size = st.st_size;
3842 list_add_tail( &mappings_list, &mapping->entry );
3843 return mapping;
3845 error:
3846 close( fd );
3847 return NULL;
3850 static void unmap_font_file( struct font_mapping *mapping )
3852 if (!--mapping->refcount)
3854 list_remove( &mapping->entry );
3855 munmap( mapping->data, mapping->size );
3856 HeapFree( GetProcessHeap(), 0, mapping );
3860 static LONG load_VDMX(GdiFont*, LONG);
3862 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3864 FT_Error err;
3865 FT_Face ft_face;
3866 void *data_ptr;
3867 DWORD data_size;
3869 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
3871 if (face->file)
3873 char *filename = strWtoA( CP_UNIXCP, face->file );
3874 font->mapping = map_font_file( filename );
3875 HeapFree( GetProcessHeap(), 0, filename );
3876 if (!font->mapping)
3878 WARN("failed to map %s\n", debugstr_w(face->file));
3879 return 0;
3881 data_ptr = font->mapping->data;
3882 data_size = font->mapping->size;
3884 else
3886 data_ptr = face->font_data_ptr;
3887 data_size = face->font_data_size;
3890 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3891 if(err) {
3892 ERR("FT_New_Face rets %d\n", err);
3893 return 0;
3896 /* set it here, as load_VDMX needs it */
3897 font->ft_face = ft_face;
3899 if(FT_IS_SCALABLE(ft_face)) {
3900 /* load the VDMX table if we have one */
3901 font->ppem = load_VDMX(font, height);
3902 if(font->ppem == 0)
3903 font->ppem = calc_ppem_for_height(ft_face, height);
3904 TRACE("height %d => ppem %d\n", height, font->ppem);
3906 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3907 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3908 } else {
3909 font->ppem = height;
3910 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3911 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3913 return ft_face;
3917 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3919 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3920 a single face with the requested charset. The idea is to check if
3921 the selected font supports the current ANSI codepage, if it does
3922 return the corresponding charset, else return the first charset */
3924 CHARSETINFO csi;
3925 int acp = GetACP(), i;
3926 DWORD fs0;
3928 *cp = acp;
3929 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3931 const SYSTEM_LINKS *font_link;
3933 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
3934 return csi.ciCharset;
3936 font_link = find_font_link(family_name);
3937 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
3938 return csi.ciCharset;
3941 for(i = 0; i < 32; i++) {
3942 fs0 = 1L << i;
3943 if(face->fs.fsCsb[0] & fs0) {
3944 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3945 *cp = csi.ciACP;
3946 return csi.ciCharset;
3948 else
3949 FIXME("TCI failing on %x\n", fs0);
3953 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3954 face->fs.fsCsb[0], debugstr_w(face->file));
3955 *cp = acp;
3956 return DEFAULT_CHARSET;
3959 static GdiFont *alloc_font(void)
3961 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3962 ret->gmsize = 1;
3963 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3964 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3965 ret->potm = NULL;
3966 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3967 ret->total_kern_pairs = (DWORD)-1;
3968 ret->kern_pairs = NULL;
3969 list_init(&ret->hfontlist);
3970 list_init(&ret->child_fonts);
3971 return ret;
3974 static void free_font(GdiFont *font)
3976 struct list *cursor, *cursor2;
3977 DWORD i;
3979 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3981 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3982 list_remove(cursor);
3983 if(child->font)
3984 free_font(child->font);
3985 HeapFree(GetProcessHeap(), 0, child);
3988 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3990 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3991 DeleteObject(hfontlist->hfont);
3992 list_remove(&hfontlist->entry);
3993 HeapFree(GetProcessHeap(), 0, hfontlist);
3996 if (font->ft_face) pFT_Done_Face(font->ft_face);
3997 if (font->mapping) unmap_font_file( font->mapping );
3998 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3999 HeapFree(GetProcessHeap(), 0, font->potm);
4000 HeapFree(GetProcessHeap(), 0, font->name);
4001 for (i = 0; i < font->gmsize; i++)
4002 HeapFree(GetProcessHeap(),0,font->gm[i]);
4003 HeapFree(GetProcessHeap(), 0, font->gm);
4004 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4005 HeapFree(GetProcessHeap(), 0, font);
4009 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4011 FT_Face ft_face = font->ft_face;
4012 FT_ULong len;
4013 FT_Error err;
4015 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4017 if(!buf)
4018 len = 0;
4019 else
4020 len = cbData;
4022 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4024 /* make sure value of len is the value freetype says it needs */
4025 if (buf && len)
4027 FT_ULong needed = 0;
4028 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4029 if( !err && needed < len) len = needed;
4031 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4032 if (err)
4034 TRACE("Can't find table %c%c%c%c\n",
4035 /* bytes were reversed */
4036 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4037 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4038 return GDI_ERROR;
4040 return len;
4043 /*************************************************************
4044 * load_VDMX
4046 * load the vdmx entry for the specified height
4049 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4050 ( ( (FT_ULong)_x4 << 24 ) | \
4051 ( (FT_ULong)_x3 << 16 ) | \
4052 ( (FT_ULong)_x2 << 8 ) | \
4053 (FT_ULong)_x1 )
4055 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4057 typedef struct {
4058 BYTE bCharSet;
4059 BYTE xRatio;
4060 BYTE yStartRatio;
4061 BYTE yEndRatio;
4062 } Ratios;
4064 typedef struct {
4065 WORD recs;
4066 BYTE startsz;
4067 BYTE endsz;
4068 } VDMX_group;
4070 static LONG load_VDMX(GdiFont *font, LONG height)
4072 WORD hdr[3], tmp;
4073 VDMX_group group;
4074 BYTE devXRatio, devYRatio;
4075 USHORT numRecs, numRatios;
4076 DWORD result, offset = -1;
4077 LONG ppem = 0;
4078 int i;
4080 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
4082 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4083 return ppem;
4085 /* FIXME: need the real device aspect ratio */
4086 devXRatio = 1;
4087 devYRatio = 1;
4089 numRecs = GET_BE_WORD(hdr[1]);
4090 numRatios = GET_BE_WORD(hdr[2]);
4092 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4093 for(i = 0; i < numRatios; i++) {
4094 Ratios ratio;
4096 offset = (3 * 2) + (i * sizeof(Ratios));
4097 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4098 offset = -1;
4100 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4102 if((ratio.xRatio == 0 &&
4103 ratio.yStartRatio == 0 &&
4104 ratio.yEndRatio == 0) ||
4105 (devXRatio == ratio.xRatio &&
4106 devYRatio >= ratio.yStartRatio &&
4107 devYRatio <= ratio.yEndRatio))
4109 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4110 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4111 offset = GET_BE_WORD(tmp);
4112 break;
4116 if(offset == -1) {
4117 FIXME("No suitable ratio found\n");
4118 return ppem;
4121 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4122 USHORT recs;
4123 BYTE startsz, endsz;
4124 WORD *vTable;
4126 recs = GET_BE_WORD(group.recs);
4127 startsz = group.startsz;
4128 endsz = group.endsz;
4130 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4132 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4133 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4134 if(result == GDI_ERROR) {
4135 FIXME("Failed to retrieve vTable\n");
4136 goto end;
4139 if(height > 0) {
4140 for(i = 0; i < recs; i++) {
4141 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4142 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4143 ppem = GET_BE_WORD(vTable[i * 3]);
4145 if(yMax + -yMin == height) {
4146 font->yMax = yMax;
4147 font->yMin = yMin;
4148 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4149 break;
4151 if(yMax + -yMin > height) {
4152 if(--i < 0) {
4153 ppem = 0;
4154 goto end; /* failed */
4156 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4157 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4158 ppem = GET_BE_WORD(vTable[i * 3]);
4159 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4160 break;
4163 if(!font->yMax) {
4164 ppem = 0;
4165 TRACE("ppem not found for height %d\n", height);
4168 end:
4169 HeapFree(GetProcessHeap(), 0, vTable);
4172 return ppem;
4175 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4177 if(font->font_desc.hash != fd->hash) return TRUE;
4178 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4179 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4180 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4181 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4184 static void calc_hash(FONT_DESC *pfd)
4186 DWORD hash = 0, *ptr, two_chars;
4187 WORD *pwc;
4188 unsigned int i;
4190 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4191 hash ^= *ptr;
4192 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4193 hash ^= *ptr;
4194 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4195 two_chars = *ptr;
4196 pwc = (WCHAR *)&two_chars;
4197 if(!*pwc) break;
4198 *pwc = toupperW(*pwc);
4199 pwc++;
4200 *pwc = toupperW(*pwc);
4201 hash ^= two_chars;
4202 if(!*pwc) break;
4204 hash ^= !pfd->can_use_bitmap;
4205 pfd->hash = hash;
4206 return;
4209 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4211 GdiFont *ret;
4212 FONT_DESC fd;
4213 HFONTLIST *hflist;
4214 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4216 fd.lf = *plf;
4217 fd.matrix = *pmat;
4218 fd.can_use_bitmap = can_use_bitmap;
4219 calc_hash(&fd);
4221 /* try the child list */
4222 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
4223 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4224 if(!fontcmp(ret, &fd)) {
4225 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4226 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4227 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4228 if(hflist->hfont == hfont)
4229 return ret;
4234 /* try the in-use list */
4235 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
4236 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4237 if(!fontcmp(ret, &fd)) {
4238 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4239 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4240 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4241 if(hflist->hfont == hfont)
4242 return ret;
4244 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4245 hflist->hfont = hfont;
4246 list_add_head(&ret->hfontlist, &hflist->entry);
4247 return ret;
4251 /* then the unused list */
4252 font_elem_ptr = list_head(&unused_gdi_font_list);
4253 while(font_elem_ptr) {
4254 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4255 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4256 if(!fontcmp(ret, &fd)) {
4257 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4258 assert(list_empty(&ret->hfontlist));
4259 TRACE("Found %p in unused list\n", ret);
4260 list_remove(&ret->entry);
4261 list_add_head(&gdi_font_list, &ret->entry);
4262 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4263 hflist->hfont = hfont;
4264 list_add_head(&ret->hfontlist, &hflist->entry);
4265 return ret;
4268 return NULL;
4271 static void add_to_cache(GdiFont *font)
4273 static DWORD cache_num = 1;
4275 font->cache_num = cache_num++;
4276 list_add_head(&gdi_font_list, &font->entry);
4279 /*************************************************************
4280 * create_child_font_list
4282 static BOOL create_child_font_list(GdiFont *font)
4284 BOOL ret = FALSE;
4285 SYSTEM_LINKS *font_link;
4286 CHILD_FONT *font_link_entry, *new_child;
4287 FontSubst *psub;
4288 WCHAR* font_name;
4290 psub = get_font_subst(&font_subst_list, font->name, -1);
4291 font_name = psub ? psub->to.name : font->name;
4292 font_link = find_font_link(font_name);
4293 if (font_link != NULL)
4295 TRACE("found entry in system list\n");
4296 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4298 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4299 new_child->face = font_link_entry->face;
4300 new_child->font = NULL;
4301 list_add_tail(&font->child_fonts, &new_child->entry);
4302 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4304 ret = TRUE;
4307 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4308 * Sans Serif. This is how asian windows get default fallbacks for fonts
4310 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4311 font->charset != OEM_CHARSET &&
4312 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4314 font_link = find_font_link(szDefaultFallbackLink);
4315 if (font_link != NULL)
4317 TRACE("found entry in default fallback list\n");
4318 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4320 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4321 new_child->face = font_link_entry->face;
4322 new_child->font = NULL;
4323 list_add_tail(&font->child_fonts, &new_child->entry);
4324 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4326 ret = TRUE;
4330 return ret;
4333 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4335 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4337 if (pFT_Set_Charmap)
4339 FT_Int i;
4340 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4342 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4344 for (i = 0; i < ft_face->num_charmaps; i++)
4346 if (ft_face->charmaps[i]->encoding == encoding)
4348 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4349 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4351 switch (ft_face->charmaps[i]->platform_id)
4353 default:
4354 cmap_def = ft_face->charmaps[i];
4355 break;
4356 case 0: /* Apple Unicode */
4357 cmap0 = ft_face->charmaps[i];
4358 break;
4359 case 1: /* Macintosh */
4360 cmap1 = ft_face->charmaps[i];
4361 break;
4362 case 2: /* ISO */
4363 cmap2 = ft_face->charmaps[i];
4364 break;
4365 case 3: /* Microsoft */
4366 cmap3 = ft_face->charmaps[i];
4367 break;
4371 if (cmap3) /* prefer Microsoft cmap table */
4372 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4373 else if (cmap1)
4374 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4375 else if (cmap2)
4376 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4377 else if (cmap0)
4378 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4379 else if (cmap_def)
4380 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4382 return ft_err == FT_Err_Ok;
4385 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4389 /*************************************************************
4390 * freetype_CreateDC
4392 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4393 LPCWSTR output, const DEVMODEW *devmode )
4395 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4397 if (!physdev) return FALSE;
4398 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4399 return TRUE;
4403 /*************************************************************
4404 * freetype_DeleteDC
4406 static BOOL freetype_DeleteDC( PHYSDEV dev )
4408 struct freetype_physdev *physdev = get_freetype_dev( dev );
4409 HeapFree( GetProcessHeap(), 0, physdev );
4410 return TRUE;
4413 static FT_Encoding pick_charmap( FT_Face face, int charset )
4415 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
4416 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
4417 const FT_Encoding *encs = regular_order;
4419 if (charset == SYMBOL_CHARSET) encs = symbol_order;
4421 while (*encs != 0)
4423 if (select_charmap( face, *encs )) break;
4424 encs++;
4426 return *encs;
4429 /*************************************************************
4430 * freetype_SelectFont
4432 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
4434 struct freetype_physdev *physdev = get_freetype_dev( dev );
4435 GdiFont *ret;
4436 Face *face, *best, *best_bitmap;
4437 Family *family, *last_resort_family;
4438 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
4439 INT height, width = 0;
4440 unsigned int score = 0, new_score;
4441 signed int diff = 0, newdiff;
4442 BOOL bd, it, can_use_bitmap, want_vertical;
4443 LOGFONTW lf;
4444 CHARSETINFO csi;
4445 HFONTLIST *hflist;
4446 FMAT2 dcmat;
4447 FontSubst *psub = NULL;
4448 DC *dc = get_dc_ptr( dev->hdc );
4449 const SYSTEM_LINKS *font_link;
4451 if (!hfont) /* notification that the font has been changed by another driver */
4453 dc->gdiFont = NULL;
4454 physdev->font = NULL;
4455 release_dc_ptr( dc );
4456 return 0;
4459 GetObjectW( hfont, sizeof(lf), &lf );
4460 lf.lfWidth = abs(lf.lfWidth);
4462 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4464 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4465 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4466 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4467 lf.lfEscapement);
4469 if(dc->GraphicsMode == GM_ADVANCED)
4471 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4472 /* Try to avoid not necessary glyph transformations */
4473 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4475 lf.lfHeight *= fabs(dcmat.eM11);
4476 lf.lfWidth *= fabs(dcmat.eM11);
4477 dcmat.eM11 = dcmat.eM22 = 1.0;
4480 else
4482 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4483 font scaling abilities. */
4484 dcmat.eM11 = dcmat.eM22 = 1.0;
4485 dcmat.eM21 = dcmat.eM12 = 0;
4486 if (dc->vport2WorldValid)
4488 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4489 lf.lfOrientation = -lf.lfOrientation;
4490 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4491 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4495 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4496 dcmat.eM21, dcmat.eM22);
4498 GDI_CheckNotLock();
4499 EnterCriticalSection( &freetype_cs );
4501 /* check the cache first */
4502 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4503 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4504 goto done;
4507 if(list_empty(&font_list)) /* No fonts installed */
4509 TRACE("No fonts installed\n");
4510 goto done;
4513 TRACE("not in cache\n");
4514 ret = alloc_font();
4516 ret->font_desc.matrix = dcmat;
4517 ret->font_desc.lf = lf;
4518 ret->font_desc.can_use_bitmap = can_use_bitmap;
4519 calc_hash(&ret->font_desc);
4520 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4521 hflist->hfont = hfont;
4522 list_add_head(&ret->hfontlist, &hflist->entry);
4524 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4525 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4526 original value lfCharSet. Note this is a special case for
4527 Symbol and doesn't happen at least for "Wingdings*" */
4529 if(!strcmpiW(lf.lfFaceName, SymbolW))
4530 lf.lfCharSet = SYMBOL_CHARSET;
4532 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4533 switch(lf.lfCharSet) {
4534 case DEFAULT_CHARSET:
4535 csi.fs.fsCsb[0] = 0;
4536 break;
4537 default:
4538 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4539 csi.fs.fsCsb[0] = 0;
4540 break;
4544 family = NULL;
4545 if(lf.lfFaceName[0] != '\0') {
4546 CHILD_FONT *font_link_entry;
4547 LPWSTR FaceName = lf.lfFaceName;
4549 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4551 if(psub) {
4552 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4553 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4554 if (psub->to.charset != -1)
4555 lf.lfCharSet = psub->to.charset;
4558 /* We want a match on name and charset or just name if
4559 charset was DEFAULT_CHARSET. If the latter then
4560 we fixup the returned charset later in get_nearest_charset
4561 where we'll either use the charset of the current ansi codepage
4562 or if that's unavailable the first charset that the font supports.
4564 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4565 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4566 if (!strcmpiW(family->FamilyName, FaceName) ||
4567 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4569 font_link = find_font_link(family->FamilyName);
4570 face_list = get_face_list_from_family(family);
4571 LIST_FOR_EACH(face_elem_ptr, face_list) {
4572 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4573 if (!(face->scalable || can_use_bitmap))
4574 continue;
4575 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4576 goto found;
4577 if (font_link != NULL &&
4578 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4579 goto found;
4580 if (!csi.fs.fsCsb[0])
4581 goto found;
4586 /* Search by full face name. */
4587 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4588 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4589 face_list = get_face_list_from_family(family);
4590 LIST_FOR_EACH(face_elem_ptr, face_list) {
4591 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4592 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4593 (face->scalable || can_use_bitmap))
4595 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4596 goto found_face;
4597 font_link = find_font_link(family->FamilyName);
4598 if (font_link != NULL &&
4599 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4600 goto found_face;
4606 * Try check the SystemLink list first for a replacement font.
4607 * We may find good replacements there.
4609 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4611 if(!strcmpiW(font_link->font_name, FaceName) ||
4612 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4614 TRACE("found entry in system list\n");
4615 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4617 const SYSTEM_LINKS *links;
4619 face = font_link_entry->face;
4620 if (!(face->scalable || can_use_bitmap))
4621 continue;
4622 family = face->family;
4623 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4624 goto found;
4625 links = find_font_link(family->FamilyName);
4626 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4627 goto found;
4633 psub = NULL; /* substitution is no more relevant */
4635 /* If requested charset was DEFAULT_CHARSET then try using charset
4636 corresponding to the current ansi codepage */
4637 if (!csi.fs.fsCsb[0])
4639 INT acp = GetACP();
4640 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4641 FIXME("TCI failed on codepage %d\n", acp);
4642 csi.fs.fsCsb[0] = 0;
4643 } else
4644 lf.lfCharSet = csi.ciCharset;
4647 want_vertical = (lf.lfFaceName[0] == '@');
4649 /* Face families are in the top 4 bits of lfPitchAndFamily,
4650 so mask with 0xF0 before testing */
4652 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4653 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4654 strcpyW(lf.lfFaceName, defFixed);
4655 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4656 strcpyW(lf.lfFaceName, defSerif);
4657 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4658 strcpyW(lf.lfFaceName, defSans);
4659 else
4660 strcpyW(lf.lfFaceName, defSans);
4661 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4662 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4663 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4664 font_link = find_font_link(family->FamilyName);
4665 face_list = get_face_list_from_family(family);
4666 LIST_FOR_EACH(face_elem_ptr, face_list) {
4667 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4668 if (!(face->scalable || can_use_bitmap))
4669 continue;
4670 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4671 goto found;
4672 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4673 goto found;
4678 last_resort_family = NULL;
4679 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4680 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4681 font_link = find_font_link(family->FamilyName);
4682 face_list = get_face_list_from_family(family);
4683 LIST_FOR_EACH(face_elem_ptr, face_list) {
4684 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4685 if(face->vertical == want_vertical &&
4686 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4687 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4688 if(face->scalable)
4689 goto found;
4690 if(can_use_bitmap && !last_resort_family)
4691 last_resort_family = family;
4696 if(last_resort_family) {
4697 family = last_resort_family;
4698 csi.fs.fsCsb[0] = 0;
4699 goto found;
4702 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4703 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4704 face_list = get_face_list_from_family(family);
4705 LIST_FOR_EACH(face_elem_ptr, face_list) {
4706 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4707 if(face->scalable && face->vertical == want_vertical) {
4708 csi.fs.fsCsb[0] = 0;
4709 WARN("just using first face for now\n");
4710 goto found;
4712 if(can_use_bitmap && !last_resort_family)
4713 last_resort_family = family;
4716 if(!last_resort_family) {
4717 FIXME("can't find a single appropriate font - bailing\n");
4718 free_font(ret);
4719 ret = NULL;
4720 goto done;
4723 WARN("could only find a bitmap font - this will probably look awful!\n");
4724 family = last_resort_family;
4725 csi.fs.fsCsb[0] = 0;
4727 found:
4728 it = lf.lfItalic ? 1 : 0;
4729 bd = lf.lfWeight > 550 ? 1 : 0;
4731 height = lf.lfHeight;
4733 face = best = best_bitmap = NULL;
4734 font_link = find_font_link(family->FamilyName);
4735 face_list = get_face_list_from_family(family);
4736 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4738 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4739 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4740 !csi.fs.fsCsb[0])
4742 BOOL italic, bold;
4744 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4745 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4746 new_score = (italic ^ it) + (bold ^ bd);
4747 if(!best || new_score <= score)
4749 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4750 italic, bold, it, bd);
4751 score = new_score;
4752 best = face;
4753 if(best->scalable && score == 0) break;
4754 if(!best->scalable)
4756 if(height > 0)
4757 newdiff = height - (signed int)(best->size.height);
4758 else
4759 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4760 if(!best_bitmap || new_score < score ||
4761 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4763 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4764 diff = newdiff;
4765 best_bitmap = best;
4766 if(score == 0 && diff == 0) break;
4772 if(best)
4773 face = best->scalable ? best : best_bitmap;
4774 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4775 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4777 found_face:
4778 height = lf.lfHeight;
4780 ret->fs = face->fs;
4782 if(csi.fs.fsCsb[0]) {
4783 ret->charset = lf.lfCharSet;
4784 ret->codepage = csi.ciACP;
4786 else
4787 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4789 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4790 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
4792 ret->aveWidth = height ? lf.lfWidth : 0;
4794 if(!face->scalable) {
4795 /* Windows uses integer scaling factors for bitmap fonts */
4796 INT scale, scaled_height;
4797 GdiFont *cachedfont;
4799 /* FIXME: rotation of bitmap fonts is ignored */
4800 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4801 if (ret->aveWidth)
4802 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4803 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4804 dcmat.eM11 = dcmat.eM22 = 1.0;
4805 /* As we changed the matrix, we need to search the cache for the font again,
4806 * otherwise we might explode the cache. */
4807 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4808 TRACE("Found cached font after non-scalable matrix rescale!\n");
4809 free_font( ret );
4810 ret = cachedfont;
4811 goto done;
4813 calc_hash(&ret->font_desc);
4815 if (height != 0) height = diff;
4816 height += face->size.height;
4818 scale = (height + face->size.height - 1) / face->size.height;
4819 scaled_height = scale * face->size.height;
4820 /* Only jump to the next height if the difference <= 25% original height */
4821 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4822 /* The jump between unscaled and doubled is delayed by 1 */
4823 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4824 ret->scale_y = scale;
4826 width = face->size.x_ppem >> 6;
4827 height = face->size.y_ppem >> 6;
4829 else
4830 ret->scale_y = 1.0;
4831 TRACE("font scale y: %f\n", ret->scale_y);
4833 ret->ft_face = OpenFontFace(ret, face, width, height);
4835 if (!ret->ft_face)
4837 free_font( ret );
4838 ret = NULL;
4839 goto done;
4842 ret->ntmFlags = face->ntmFlags;
4844 pick_charmap( ret->ft_face, ret->charset );
4846 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4847 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4848 ret->underline = lf.lfUnderline ? 0xff : 0;
4849 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4850 create_child_font_list(ret);
4852 if (face->vertical) /* We need to try to load the GSUB table */
4854 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4855 if (length != GDI_ERROR)
4857 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4858 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4859 TRACE("Loaded GSUB table of %i bytes\n",length);
4863 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4865 add_to_cache(ret);
4866 done:
4867 if (ret)
4869 dc->gdiFont = ret;
4870 physdev->font = ret;
4872 LeaveCriticalSection( &freetype_cs );
4873 release_dc_ptr( dc );
4874 return ret ? hfont : 0;
4877 static void dump_gdi_font_list(void)
4879 GdiFont *gdiFont;
4880 struct list *elem_ptr;
4882 TRACE("---------- gdiFont Cache ----------\n");
4883 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4884 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4885 TRACE("gdiFont=%p %s %d\n",
4886 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4889 TRACE("---------- Unused gdiFont Cache ----------\n");
4890 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4891 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4892 TRACE("gdiFont=%p %s %d\n",
4893 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4896 TRACE("---------- Child gdiFont Cache ----------\n");
4897 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4898 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4899 TRACE("gdiFont=%p %s %d\n",
4900 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4904 /*************************************************************
4905 * WineEngDestroyFontInstance
4907 * free the gdiFont associated with this handle
4910 BOOL WineEngDestroyFontInstance(HFONT handle)
4912 GdiFont *gdiFont;
4913 HFONTLIST *hflist;
4914 BOOL ret = FALSE;
4915 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4916 int i = 0;
4918 GDI_CheckNotLock();
4919 EnterCriticalSection( &freetype_cs );
4921 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4923 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4924 while(hfontlist_elem_ptr) {
4925 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4926 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4927 if(hflist->hfont == handle) {
4928 TRACE("removing child font %p from child list\n", gdiFont);
4929 list_remove(&gdiFont->entry);
4930 LeaveCriticalSection( &freetype_cs );
4931 return TRUE;
4936 TRACE("destroying hfont=%p\n", handle);
4937 if(TRACE_ON(font))
4938 dump_gdi_font_list();
4940 font_elem_ptr = list_head(&gdi_font_list);
4941 while(font_elem_ptr) {
4942 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4943 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4945 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4946 while(hfontlist_elem_ptr) {
4947 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4948 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4949 if(hflist->hfont == handle) {
4950 list_remove(&hflist->entry);
4951 HeapFree(GetProcessHeap(), 0, hflist);
4952 ret = TRUE;
4955 if(list_empty(&gdiFont->hfontlist)) {
4956 TRACE("Moving to Unused list\n");
4957 list_remove(&gdiFont->entry);
4958 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4963 font_elem_ptr = list_head(&unused_gdi_font_list);
4964 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4965 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4966 while(font_elem_ptr) {
4967 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4968 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4969 TRACE("freeing %p\n", gdiFont);
4970 list_remove(&gdiFont->entry);
4971 free_font(gdiFont);
4973 LeaveCriticalSection( &freetype_cs );
4974 return ret;
4977 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4979 HRSRC rsrc;
4980 HGLOBAL hMem;
4981 WCHAR *p;
4982 int i;
4984 id += IDS_FIRST_SCRIPT;
4985 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4986 if (!rsrc) return 0;
4987 hMem = LoadResource( gdi32_module, rsrc );
4988 if (!hMem) return 0;
4990 p = LockResource( hMem );
4991 id &= 0x000f;
4992 while (id--) p += *p + 1;
4994 i = min(LF_FACESIZE - 1, *p);
4995 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4996 buffer[i] = 0;
4997 return i;
5001 /***************************************************
5002 * create_enum_charset_list
5004 * This function creates charset enumeration list because in DEFAULT_CHARSET
5005 * case, the ANSI codepage's charset takes precedence over other charsets.
5006 * This function works as a filter other than DEFAULT_CHARSET case.
5008 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5010 CHARSETINFO csi;
5011 DWORD n = 0;
5013 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5014 csi.fs.fsCsb[0] != 0) {
5015 list->element[n].mask = csi.fs.fsCsb[0];
5016 list->element[n].charset = csi.ciCharset;
5017 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5018 n++;
5020 else { /* charset is DEFAULT_CHARSET or invalid. */
5021 INT acp, i;
5022 DWORD mask = 0;
5024 /* Set the current codepage's charset as the first element. */
5025 acp = GetACP();
5026 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5027 csi.fs.fsCsb[0] != 0) {
5028 list->element[n].mask = csi.fs.fsCsb[0];
5029 list->element[n].charset = csi.ciCharset;
5030 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5031 mask |= csi.fs.fsCsb[0];
5032 n++;
5035 /* Fill out left elements. */
5036 for (i = 0; i < 32; i++) {
5037 FONTSIGNATURE fs;
5038 fs.fsCsb[0] = 1L << i;
5039 fs.fsCsb[1] = 0;
5040 if (fs.fsCsb[0] & mask)
5041 continue; /* skip, already added. */
5042 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5043 continue; /* skip, this is an invalid fsCsb bit. */
5045 list->element[n].mask = fs.fsCsb[0];
5046 list->element[n].charset = csi.ciCharset;
5047 load_script_name( i, list->element[n].name );
5048 mask |= fs.fsCsb[0];
5049 n++;
5052 /* add catch all mask for remaining bits */
5053 if (~mask)
5055 list->element[n].mask = ~mask;
5056 list->element[n].charset = DEFAULT_CHARSET;
5057 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5058 n++;
5061 list->total = n;
5063 return n;
5066 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
5067 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5069 GdiFont *font;
5070 LONG width, height;
5072 if (face->cached_enum_data)
5074 TRACE("Cached\n");
5075 *pelf = face->cached_enum_data->elf;
5076 *pntm = face->cached_enum_data->ntm;
5077 *ptype = face->cached_enum_data->type;
5078 return;
5081 font = alloc_font();
5083 if(face->scalable) {
5084 height = 100;
5085 width = 0;
5086 } else {
5087 height = face->size.y_ppem >> 6;
5088 width = face->size.x_ppem >> 6;
5090 font->scale_y = 1.0;
5092 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5094 free_font(font);
5095 return;
5098 font->name = strdupW(face->family->FamilyName);
5099 font->ntmFlags = face->ntmFlags;
5101 if (get_outline_text_metrics(font))
5103 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5105 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5106 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5107 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5109 lstrcpynW(pelf->elfLogFont.lfFaceName,
5110 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5111 LF_FACESIZE);
5112 lstrcpynW(pelf->elfFullName,
5113 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5114 LF_FULLFACESIZE);
5115 lstrcpynW(pelf->elfStyle,
5116 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5117 LF_FACESIZE);
5119 else
5121 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5123 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5124 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5125 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5127 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
5128 if (face->FullName)
5129 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5130 else
5131 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
5132 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5135 pntm->ntmTm.ntmFlags = face->ntmFlags;
5136 pntm->ntmFontSig = face->fs;
5138 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5140 pelf->elfLogFont.lfEscapement = 0;
5141 pelf->elfLogFont.lfOrientation = 0;
5142 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5143 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5144 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5145 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5146 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5147 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5148 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5149 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5150 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5151 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5152 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5154 *ptype = 0;
5155 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5156 *ptype |= TRUETYPE_FONTTYPE;
5157 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5158 *ptype |= DEVICE_FONTTYPE;
5159 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5160 *ptype |= RASTER_FONTTYPE;
5162 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5163 if (face->cached_enum_data)
5165 face->cached_enum_data->elf = *pelf;
5166 face->cached_enum_data->ntm = *pntm;
5167 face->cached_enum_data->type = *ptype;
5170 free_font(font);
5173 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5175 const struct list *face_list, *face_elem_ptr;
5177 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5179 face_list = get_face_list_from_family(family);
5180 LIST_FOR_EACH(face_elem_ptr, face_list)
5182 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
5184 if (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName)) return TRUE;
5187 return FALSE;
5190 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5192 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5194 return (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName));
5197 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5198 FONTENUMPROCW proc, LPARAM lparam)
5200 ENUMLOGFONTEXW elf;
5201 NEWTEXTMETRICEXW ntm;
5202 DWORD type = 0;
5203 int i;
5205 GetEnumStructs(face, &elf, &ntm, &type);
5206 for(i = 0; i < list->total; i++) {
5207 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5208 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5209 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
5210 i = list->total; /* break out of loop after enumeration */
5212 else
5214 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
5215 /* use the DEFAULT_CHARSET case only if no other charset is present */
5216 if (list->element[i].charset == DEFAULT_CHARSET &&
5217 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
5218 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5219 strcpyW(elf.elfScript, list->element[i].name);
5220 if (!elf.elfScript[0])
5221 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5223 /* Font Replacement */
5224 if (family != face->family)
5226 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5227 if (face->FullName)
5228 strcpyW(elf.elfFullName, face->FullName);
5229 else
5230 strcpyW(elf.elfFullName, family->FamilyName);
5232 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5233 debugstr_w(elf.elfLogFont.lfFaceName),
5234 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5235 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5236 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5237 ntm.ntmTm.ntmFlags);
5238 /* release section before callback (FIXME) */
5239 LeaveCriticalSection( &freetype_cs );
5240 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5241 EnterCriticalSection( &freetype_cs );
5243 return TRUE;
5246 /*************************************************************
5247 * freetype_EnumFonts
5249 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5251 Family *family;
5252 Face *face;
5253 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
5254 LOGFONTW lf;
5255 struct enum_charset_list enum_charsets;
5257 if (!plf)
5259 lf.lfCharSet = DEFAULT_CHARSET;
5260 lf.lfPitchAndFamily = 0;
5261 lf.lfFaceName[0] = 0;
5262 plf = &lf;
5265 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5267 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5269 GDI_CheckNotLock();
5270 EnterCriticalSection( &freetype_cs );
5271 if(plf->lfFaceName[0]) {
5272 FontSubst *psub;
5273 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5275 if(psub) {
5276 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5277 debugstr_w(psub->to.name));
5278 lf = *plf;
5279 strcpyW(lf.lfFaceName, psub->to.name);
5280 plf = &lf;
5283 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5284 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5285 if(family_matches(family, plf)) {
5286 face_list = get_face_list_from_family(family);
5287 LIST_FOR_EACH(face_elem_ptr, face_list) {
5288 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5289 if (!face_matches(family->FamilyName, face, plf)) continue;
5290 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5294 } else {
5295 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5296 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5297 face_list = get_face_list_from_family(family);
5298 face_elem_ptr = list_head(face_list);
5299 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5300 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5303 LeaveCriticalSection( &freetype_cs );
5304 return TRUE;
5307 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5309 pt->x.value = vec->x >> 6;
5310 pt->x.fract = (vec->x & 0x3f) << 10;
5311 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5312 pt->y.value = vec->y >> 6;
5313 pt->y.fract = (vec->y & 0x3f) << 10;
5314 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5315 return;
5318 /***************************************************
5319 * According to the MSDN documentation on WideCharToMultiByte,
5320 * certain codepages cannot set the default_used parameter.
5321 * This returns TRUE if the codepage can set that parameter, false else
5322 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5324 static BOOL codepage_sets_default_used(UINT codepage)
5326 switch (codepage)
5328 case CP_UTF7:
5329 case CP_UTF8:
5330 case CP_SYMBOL:
5331 return FALSE;
5332 default:
5333 return TRUE;
5338 * GSUB Table handling functions
5341 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5343 const GSUB_CoverageFormat1* cf1;
5345 cf1 = table;
5347 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5349 int count = GET_BE_WORD(cf1->GlyphCount);
5350 int i;
5351 TRACE("Coverage Format 1, %i glyphs\n",count);
5352 for (i = 0; i < count; i++)
5353 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5354 return i;
5355 return -1;
5357 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5359 const GSUB_CoverageFormat2* cf2;
5360 int i;
5361 int count;
5362 cf2 = (const GSUB_CoverageFormat2*)cf1;
5364 count = GET_BE_WORD(cf2->RangeCount);
5365 TRACE("Coverage Format 2, %i ranges\n",count);
5366 for (i = 0; i < count; i++)
5368 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5369 return -1;
5370 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5371 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5373 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5374 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5377 return -1;
5379 else
5380 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5382 return -1;
5385 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5387 const GSUB_ScriptList *script;
5388 const GSUB_Script *deflt = NULL;
5389 int i;
5390 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5392 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5393 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5395 const GSUB_Script *scr;
5396 int offset;
5398 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5399 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5401 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5402 return scr;
5403 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5404 deflt = scr;
5406 return deflt;
5409 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5411 int i;
5412 int offset;
5413 const GSUB_LangSys *Lang;
5415 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5417 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5419 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5420 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5422 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5423 return Lang;
5425 offset = GET_BE_WORD(script->DefaultLangSys);
5426 if (offset)
5428 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5429 return Lang;
5431 return NULL;
5434 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5436 int i;
5437 const GSUB_FeatureList *feature;
5438 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5440 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5441 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5443 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5444 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5446 const GSUB_Feature *feat;
5447 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5448 return feat;
5451 return NULL;
5454 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5456 int i;
5457 int offset;
5458 const GSUB_LookupList *lookup;
5459 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5461 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5462 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5464 const GSUB_LookupTable *look;
5465 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5466 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5467 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5468 if (GET_BE_WORD(look->LookupType) != 1)
5469 FIXME("We only handle SubType 1\n");
5470 else
5472 int j;
5474 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5476 const GSUB_SingleSubstFormat1 *ssf1;
5477 offset = GET_BE_WORD(look->SubTable[j]);
5478 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5479 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5481 int offset = GET_BE_WORD(ssf1->Coverage);
5482 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5483 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5485 TRACE(" Glyph 0x%x ->",glyph);
5486 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5487 TRACE(" 0x%x\n",glyph);
5490 else
5492 const GSUB_SingleSubstFormat2 *ssf2;
5493 INT index;
5494 INT offset;
5496 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5497 offset = GET_BE_WORD(ssf1->Coverage);
5498 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5499 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5500 TRACE(" Coverage index %i\n",index);
5501 if (index != -1)
5503 TRACE(" Glyph is 0x%x ->",glyph);
5504 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5505 TRACE("0x%x\n",glyph);
5511 return glyph;
5514 static const char* get_opentype_script(const GdiFont *font)
5517 * I am not sure if this is the correct way to generate our script tag
5520 switch (font->charset)
5522 case ANSI_CHARSET: return "latn";
5523 case BALTIC_CHARSET: return "latn"; /* ?? */
5524 case CHINESEBIG5_CHARSET: return "hani";
5525 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5526 case GB2312_CHARSET: return "hani";
5527 case GREEK_CHARSET: return "grek";
5528 case HANGUL_CHARSET: return "hang";
5529 case RUSSIAN_CHARSET: return "cyrl";
5530 case SHIFTJIS_CHARSET: return "kana";
5531 case TURKISH_CHARSET: return "latn"; /* ?? */
5532 case VIETNAMESE_CHARSET: return "latn";
5533 case JOHAB_CHARSET: return "latn"; /* ?? */
5534 case ARABIC_CHARSET: return "arab";
5535 case HEBREW_CHARSET: return "hebr";
5536 case THAI_CHARSET: return "thai";
5537 default: return "latn";
5541 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5543 const GSUB_Header *header;
5544 const GSUB_Script *script;
5545 const GSUB_LangSys *language;
5546 const GSUB_Feature *feature;
5548 if (!font->GSUB_Table)
5549 return glyph;
5551 header = font->GSUB_Table;
5553 script = GSUB_get_script_table(header, get_opentype_script(font));
5554 if (!script)
5556 TRACE("Script not found\n");
5557 return glyph;
5559 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5560 if (!language)
5562 TRACE("Language not found\n");
5563 return glyph;
5565 feature = GSUB_get_feature(header, language, "vrt2");
5566 if (!feature)
5567 feature = GSUB_get_feature(header, language, "vert");
5568 if (!feature)
5570 TRACE("vrt2/vert feature not found\n");
5571 return glyph;
5573 return GSUB_apply_feature(header, feature, glyph);
5576 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5578 FT_UInt glyphId;
5580 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5581 WCHAR wc = (WCHAR)glyph;
5582 BOOL default_used;
5583 BOOL *default_used_pointer;
5584 FT_UInt ret;
5585 char buf;
5586 default_used_pointer = NULL;
5587 default_used = FALSE;
5588 if (codepage_sets_default_used(font->codepage))
5589 default_used_pointer = &default_used;
5590 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5592 if (font->codepage == CP_SYMBOL && wc < 0x100)
5593 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
5594 else
5595 ret = 0;
5597 else
5598 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5599 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5600 return ret;
5603 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5605 if (glyph < 0x100) glyph += 0xf000;
5606 /* there is a number of old pre-Unicode "broken" TTFs, which
5607 do have symbols at U+00XX instead of U+f0XX */
5608 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5609 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5611 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5613 return glyphId;
5616 /*************************************************************
5617 * freetype_GetGlyphIndices
5619 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5621 struct freetype_physdev *physdev = get_freetype_dev( dev );
5622 int i;
5623 WORD default_char;
5624 BOOL got_default = FALSE;
5626 if (!physdev->font)
5628 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5629 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5632 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5634 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5635 got_default = TRUE;
5638 GDI_CheckNotLock();
5639 EnterCriticalSection( &freetype_cs );
5641 for(i = 0; i < count; i++)
5643 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5644 if (pgi[i] == 0)
5646 if (!got_default)
5648 if (FT_IS_SFNT(physdev->font->ft_face))
5650 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5651 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5653 else
5655 TEXTMETRICW textm;
5656 get_text_metrics(physdev->font, &textm);
5657 default_char = textm.tmDefaultChar;
5659 got_default = TRUE;
5661 pgi[i] = default_char;
5664 LeaveCriticalSection( &freetype_cs );
5665 return count;
5668 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5670 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5671 return !memcmp(matrix, &identity, sizeof(FMAT2));
5674 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5676 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5677 return !memcmp(matrix, &identity, sizeof(MAT2));
5680 static inline BYTE get_max_level( UINT format )
5682 switch( format )
5684 case GGO_GRAY2_BITMAP: return 4;
5685 case GGO_GRAY4_BITMAP: return 16;
5686 case GGO_GRAY8_BITMAP: return 64;
5688 return 255;
5691 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5693 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5694 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5695 const MAT2* lpmat)
5697 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5698 FT_Face ft_face = incoming_font->ft_face;
5699 GdiFont *font = incoming_font;
5700 FT_UInt glyph_index;
5701 DWORD width, height, pitch, needed = 0;
5702 FT_Bitmap ft_bitmap;
5703 FT_Error err;
5704 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5705 FT_Angle angle = 0;
5706 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5707 double widthRatio = 1.0;
5708 FT_Matrix transMat = identityMat;
5709 FT_Matrix transMatUnrotated;
5710 BOOL needsTransform = FALSE;
5711 BOOL tategaki = (font->GSUB_Table != NULL);
5712 UINT original_index;
5714 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5715 buflen, buf, lpmat);
5717 TRACE("font transform %f %f %f %f\n",
5718 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5719 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5721 if(format & GGO_GLYPH_INDEX) {
5722 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5723 original_index = glyph;
5724 format &= ~GGO_GLYPH_INDEX;
5725 } else {
5726 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5727 ft_face = font->ft_face;
5728 original_index = glyph_index;
5731 if(format & GGO_UNHINTED) {
5732 load_flags |= FT_LOAD_NO_HINTING;
5733 format &= ~GGO_UNHINTED;
5736 /* tategaki never appears to happen to lower glyph index */
5737 if (glyph_index < TATEGAKI_LOWER_BOUND )
5738 tategaki = FALSE;
5740 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5741 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5742 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5743 font->gmsize * sizeof(GM*));
5744 } else {
5745 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5746 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5748 *lpgm = FONT_GM(font,original_index)->gm;
5749 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5750 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5751 lpgm->gmCellIncX, lpgm->gmCellIncY);
5752 return 1; /* FIXME */
5756 if (!font->gm[original_index / GM_BLOCK_SIZE])
5757 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5759 /* Scaling factor */
5760 if (font->aveWidth)
5762 TEXTMETRICW tm;
5764 get_text_metrics(font, &tm);
5766 widthRatio = (double)font->aveWidth;
5767 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5769 else
5770 widthRatio = font->scale_y;
5772 /* Scaling transform */
5773 if (widthRatio != 1.0 || font->scale_y != 1.0)
5775 FT_Matrix scaleMat;
5776 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5777 scaleMat.xy = 0;
5778 scaleMat.yx = 0;
5779 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5781 pFT_Matrix_Multiply(&scaleMat, &transMat);
5782 needsTransform = TRUE;
5785 /* Slant transform */
5786 if (font->fake_italic) {
5787 FT_Matrix slantMat;
5789 slantMat.xx = (1 << 16);
5790 slantMat.xy = ((1 << 16) >> 2);
5791 slantMat.yx = 0;
5792 slantMat.yy = (1 << 16);
5793 pFT_Matrix_Multiply(&slantMat, &transMat);
5794 needsTransform = TRUE;
5797 /* Rotation transform */
5798 transMatUnrotated = transMat;
5799 if(font->orientation && !tategaki) {
5800 FT_Matrix rotationMat;
5801 FT_Vector vecAngle;
5802 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5803 pFT_Vector_Unit(&vecAngle, angle);
5804 rotationMat.xx = vecAngle.x;
5805 rotationMat.xy = -vecAngle.y;
5806 rotationMat.yx = -rotationMat.xy;
5807 rotationMat.yy = rotationMat.xx;
5809 pFT_Matrix_Multiply(&rotationMat, &transMat);
5810 needsTransform = TRUE;
5813 /* World transform */
5814 if (!is_identity_FMAT2(&font->font_desc.matrix))
5816 FT_Matrix worldMat;
5817 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5818 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5819 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5820 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5821 pFT_Matrix_Multiply(&worldMat, &transMat);
5822 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5823 needsTransform = TRUE;
5826 /* Extra transformation specified by caller */
5827 if (!is_identity_MAT2(lpmat))
5829 FT_Matrix extraMat;
5830 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5831 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5832 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5833 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5834 pFT_Matrix_Multiply(&extraMat, &transMat);
5835 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5836 needsTransform = TRUE;
5839 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5840 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5841 format == GGO_GRAY8_BITMAP))
5843 load_flags |= FT_LOAD_NO_BITMAP;
5846 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5848 if(err) {
5849 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5850 return GDI_ERROR;
5853 if(!needsTransform) {
5854 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5855 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5856 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5858 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5859 bottom = (ft_face->glyph->metrics.horiBearingY -
5860 ft_face->glyph->metrics.height) & -64;
5861 lpgm->gmCellIncX = adv;
5862 lpgm->gmCellIncY = 0;
5863 } else {
5864 INT xc, yc;
5865 FT_Vector vec;
5867 left = right = 0;
5869 for(xc = 0; xc < 2; xc++) {
5870 for(yc = 0; yc < 2; yc++) {
5871 vec.x = (ft_face->glyph->metrics.horiBearingX +
5872 xc * ft_face->glyph->metrics.width);
5873 vec.y = ft_face->glyph->metrics.horiBearingY -
5874 yc * ft_face->glyph->metrics.height;
5875 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5876 pFT_Vector_Transform(&vec, &transMat);
5877 if(xc == 0 && yc == 0) {
5878 left = right = vec.x;
5879 top = bottom = vec.y;
5880 } else {
5881 if(vec.x < left) left = vec.x;
5882 else if(vec.x > right) right = vec.x;
5883 if(vec.y < bottom) bottom = vec.y;
5884 else if(vec.y > top) top = vec.y;
5888 left = left & -64;
5889 right = (right + 63) & -64;
5890 bottom = bottom & -64;
5891 top = (top + 63) & -64;
5893 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5894 vec.x = ft_face->glyph->metrics.horiAdvance;
5895 vec.y = 0;
5896 pFT_Vector_Transform(&vec, &transMat);
5897 lpgm->gmCellIncX = (vec.x+63) >> 6;
5898 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5900 vec.x = ft_face->glyph->metrics.horiAdvance;
5901 vec.y = 0;
5902 pFT_Vector_Transform(&vec, &transMatUnrotated);
5903 adv = (vec.x+63) >> 6;
5906 lsb = left >> 6;
5907 bbx = (right - left) >> 6;
5908 lpgm->gmBlackBoxX = (right - left) >> 6;
5909 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5910 lpgm->gmptGlyphOrigin.x = left >> 6;
5911 lpgm->gmptGlyphOrigin.y = top >> 6;
5913 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5914 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5915 lpgm->gmCellIncX, lpgm->gmCellIncY);
5917 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5918 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5920 FONT_GM(font,original_index)->gm = *lpgm;
5921 FONT_GM(font,original_index)->adv = adv;
5922 FONT_GM(font,original_index)->lsb = lsb;
5923 FONT_GM(font,original_index)->bbx = bbx;
5924 FONT_GM(font,original_index)->init = TRUE;
5927 if(format == GGO_METRICS)
5929 return 1; /* FIXME */
5932 if(ft_face->glyph->format != ft_glyph_format_outline &&
5933 (format == GGO_NATIVE || format == GGO_BEZIER))
5935 TRACE("loaded a bitmap\n");
5936 return GDI_ERROR;
5939 switch(format) {
5940 case GGO_BITMAP:
5941 width = lpgm->gmBlackBoxX;
5942 height = lpgm->gmBlackBoxY;
5943 pitch = ((width + 31) >> 5) << 2;
5944 needed = pitch * height;
5946 if(!buf || !buflen) break;
5948 switch(ft_face->glyph->format) {
5949 case ft_glyph_format_bitmap:
5951 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5952 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5953 INT h = ft_face->glyph->bitmap.rows;
5954 while(h--) {
5955 memcpy(dst, src, w);
5956 src += ft_face->glyph->bitmap.pitch;
5957 dst += pitch;
5959 break;
5962 case ft_glyph_format_outline:
5963 ft_bitmap.width = width;
5964 ft_bitmap.rows = height;
5965 ft_bitmap.pitch = pitch;
5966 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5967 ft_bitmap.buffer = buf;
5969 if(needsTransform)
5970 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5972 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5974 /* Note: FreeType will only set 'black' bits for us. */
5975 memset(buf, 0, needed);
5976 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5977 break;
5979 default:
5980 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5981 return GDI_ERROR;
5983 break;
5985 case GGO_GRAY2_BITMAP:
5986 case GGO_GRAY4_BITMAP:
5987 case GGO_GRAY8_BITMAP:
5988 case WINE_GGO_GRAY16_BITMAP:
5990 unsigned int max_level, row, col;
5991 BYTE *start, *ptr;
5993 width = lpgm->gmBlackBoxX;
5994 height = lpgm->gmBlackBoxY;
5995 pitch = (width + 3) / 4 * 4;
5996 needed = pitch * height;
5998 if(!buf || !buflen) break;
6000 max_level = get_max_level( format );
6002 switch(ft_face->glyph->format) {
6003 case ft_glyph_format_bitmap:
6005 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6006 INT h = ft_face->glyph->bitmap.rows;
6007 INT x;
6008 memset( buf, 0, needed );
6009 while(h--) {
6010 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
6011 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
6012 src += ft_face->glyph->bitmap.pitch;
6013 dst += pitch;
6015 return needed;
6017 case ft_glyph_format_outline:
6019 ft_bitmap.width = width;
6020 ft_bitmap.rows = height;
6021 ft_bitmap.pitch = pitch;
6022 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6023 ft_bitmap.buffer = buf;
6025 if(needsTransform)
6026 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6028 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6030 memset(ft_bitmap.buffer, 0, buflen);
6032 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6034 if (max_level != 255)
6036 for (row = 0, start = buf; row < height; row++)
6038 for (col = 0, ptr = start; col < width; col++, ptr++)
6039 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6040 start += pitch;
6043 return needed;
6046 default:
6047 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6048 return GDI_ERROR;
6050 break;
6053 case WINE_GGO_HRGB_BITMAP:
6054 case WINE_GGO_HBGR_BITMAP:
6055 case WINE_GGO_VRGB_BITMAP:
6056 case WINE_GGO_VBGR_BITMAP:
6057 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6059 switch (ft_face->glyph->format)
6061 case FT_GLYPH_FORMAT_BITMAP:
6063 BYTE *src, *dst;
6064 INT src_pitch, x;
6066 width = lpgm->gmBlackBoxX;
6067 height = lpgm->gmBlackBoxY;
6068 pitch = width * 4;
6069 needed = pitch * height;
6071 if (!buf || !buflen) break;
6073 memset(buf, 0, buflen);
6074 dst = buf;
6075 src = ft_face->glyph->bitmap.buffer;
6076 src_pitch = ft_face->glyph->bitmap.pitch;
6078 height = min( height, ft_face->glyph->bitmap.rows );
6079 while ( height-- )
6081 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6083 if ( src[x / 8] & masks[x % 8] )
6084 ((unsigned int *)dst)[x] = ~0u;
6086 src += src_pitch;
6087 dst += pitch;
6090 break;
6093 case FT_GLYPH_FORMAT_OUTLINE:
6095 unsigned int *dst;
6096 BYTE *src;
6097 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6098 INT x_shift, y_shift;
6099 BOOL rgb;
6100 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6101 FT_Render_Mode render_mode =
6102 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6103 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6105 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6107 if ( render_mode == FT_RENDER_MODE_LCD)
6109 lpgm->gmBlackBoxX += 2;
6110 lpgm->gmptGlyphOrigin.x -= 1;
6112 else
6114 lpgm->gmBlackBoxY += 2;
6115 lpgm->gmptGlyphOrigin.y += 1;
6119 width = lpgm->gmBlackBoxX;
6120 height = lpgm->gmBlackBoxY;
6121 pitch = width * 4;
6122 needed = pitch * height;
6124 if (!buf || !buflen) break;
6126 memset(buf, 0, buflen);
6127 dst = buf;
6128 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6130 if ( needsTransform )
6131 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
6133 if ( pFT_Library_SetLcdFilter )
6134 pFT_Library_SetLcdFilter( library, lcdfilter );
6135 pFT_Render_Glyph (ft_face->glyph, render_mode);
6137 src = ft_face->glyph->bitmap.buffer;
6138 src_pitch = ft_face->glyph->bitmap.pitch;
6139 src_width = ft_face->glyph->bitmap.width;
6140 src_height = ft_face->glyph->bitmap.rows;
6142 if ( render_mode == FT_RENDER_MODE_LCD)
6144 rgb_interval = 1;
6145 hmul = 3;
6146 vmul = 1;
6148 else
6150 rgb_interval = src_pitch;
6151 hmul = 1;
6152 vmul = 3;
6155 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6156 if ( x_shift < 0 ) x_shift = 0;
6157 if ( x_shift + (src_width / hmul) > width )
6158 x_shift = width - (src_width / hmul);
6160 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6161 if ( y_shift < 0 ) y_shift = 0;
6162 if ( y_shift + (src_height / vmul) > height )
6163 y_shift = height - (src_height / vmul);
6165 dst += x_shift + y_shift * ( pitch / 4 );
6166 while ( src_height )
6168 for ( x = 0; x < src_width / hmul; x++ )
6170 if ( rgb )
6172 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6173 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6174 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6175 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6177 else
6179 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6180 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6181 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6182 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6185 src += src_pitch * vmul;
6186 dst += pitch / 4;
6187 src_height -= vmul;
6190 break;
6193 default:
6194 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6195 return GDI_ERROR;
6198 break;
6200 #else
6201 return GDI_ERROR;
6202 #endif
6204 case GGO_NATIVE:
6206 int contour, point = 0, first_pt;
6207 FT_Outline *outline = &ft_face->glyph->outline;
6208 TTPOLYGONHEADER *pph;
6209 TTPOLYCURVE *ppc;
6210 DWORD pph_start, cpfx, type;
6212 if(buflen == 0) buf = NULL;
6214 if (needsTransform && buf) {
6215 pFT_Outline_Transform(outline, &transMat);
6218 for(contour = 0; contour < outline->n_contours; contour++) {
6219 pph_start = needed;
6220 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6221 first_pt = point;
6222 if(buf) {
6223 pph->dwType = TT_POLYGON_TYPE;
6224 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6226 needed += sizeof(*pph);
6227 point++;
6228 while(point <= outline->contours[contour]) {
6229 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6230 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6231 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6232 cpfx = 0;
6233 do {
6234 if(buf)
6235 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6236 cpfx++;
6237 point++;
6238 } while(point <= outline->contours[contour] &&
6239 (outline->tags[point] & FT_Curve_Tag_On) ==
6240 (outline->tags[point-1] & FT_Curve_Tag_On));
6241 /* At the end of a contour Windows adds the start point, but
6242 only for Beziers */
6243 if(point > outline->contours[contour] &&
6244 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6245 if(buf)
6246 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6247 cpfx++;
6248 } else if(point <= outline->contours[contour] &&
6249 outline->tags[point] & FT_Curve_Tag_On) {
6250 /* add closing pt for bezier */
6251 if(buf)
6252 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6253 cpfx++;
6254 point++;
6256 if(buf) {
6257 ppc->wType = type;
6258 ppc->cpfx = cpfx;
6260 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6262 if(buf)
6263 pph->cb = needed - pph_start;
6265 break;
6267 case GGO_BEZIER:
6269 /* Convert the quadratic Beziers to cubic Beziers.
6270 The parametric eqn for a cubic Bezier is, from PLRM:
6271 r(t) = at^3 + bt^2 + ct + r0
6272 with the control points:
6273 r1 = r0 + c/3
6274 r2 = r1 + (c + b)/3
6275 r3 = r0 + c + b + a
6277 A quadratic Bezier has the form:
6278 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6280 So equating powers of t leads to:
6281 r1 = 2/3 p1 + 1/3 p0
6282 r2 = 2/3 p1 + 1/3 p2
6283 and of course r0 = p0, r3 = p2
6286 int contour, point = 0, first_pt;
6287 FT_Outline *outline = &ft_face->glyph->outline;
6288 TTPOLYGONHEADER *pph;
6289 TTPOLYCURVE *ppc;
6290 DWORD pph_start, cpfx, type;
6291 FT_Vector cubic_control[4];
6292 if(buflen == 0) buf = NULL;
6294 if (needsTransform && buf) {
6295 pFT_Outline_Transform(outline, &transMat);
6298 for(contour = 0; contour < outline->n_contours; contour++) {
6299 pph_start = needed;
6300 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6301 first_pt = point;
6302 if(buf) {
6303 pph->dwType = TT_POLYGON_TYPE;
6304 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6306 needed += sizeof(*pph);
6307 point++;
6308 while(point <= outline->contours[contour]) {
6309 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6310 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6311 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6312 cpfx = 0;
6313 do {
6314 if(type == TT_PRIM_LINE) {
6315 if(buf)
6316 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6317 cpfx++;
6318 point++;
6319 } else {
6320 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6321 so cpfx = 3n */
6323 /* FIXME: Possible optimization in endpoint calculation
6324 if there are two consecutive curves */
6325 cubic_control[0] = outline->points[point-1];
6326 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6327 cubic_control[0].x += outline->points[point].x + 1;
6328 cubic_control[0].y += outline->points[point].y + 1;
6329 cubic_control[0].x >>= 1;
6330 cubic_control[0].y >>= 1;
6332 if(point+1 > outline->contours[contour])
6333 cubic_control[3] = outline->points[first_pt];
6334 else {
6335 cubic_control[3] = outline->points[point+1];
6336 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6337 cubic_control[3].x += outline->points[point].x + 1;
6338 cubic_control[3].y += outline->points[point].y + 1;
6339 cubic_control[3].x >>= 1;
6340 cubic_control[3].y >>= 1;
6343 /* r1 = 1/3 p0 + 2/3 p1
6344 r2 = 1/3 p2 + 2/3 p1 */
6345 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6346 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6347 cubic_control[2] = cubic_control[1];
6348 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6349 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6350 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6351 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6352 if(buf) {
6353 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6354 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6355 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6357 cpfx += 3;
6358 point++;
6360 } while(point <= outline->contours[contour] &&
6361 (outline->tags[point] & FT_Curve_Tag_On) ==
6362 (outline->tags[point-1] & FT_Curve_Tag_On));
6363 /* At the end of a contour Windows adds the start point,
6364 but only for Beziers and we've already done that.
6366 if(point <= outline->contours[contour] &&
6367 outline->tags[point] & FT_Curve_Tag_On) {
6368 /* This is the closing pt of a bezier, but we've already
6369 added it, so just inc point and carry on */
6370 point++;
6372 if(buf) {
6373 ppc->wType = type;
6374 ppc->cpfx = cpfx;
6376 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6378 if(buf)
6379 pph->cb = needed - pph_start;
6381 break;
6384 default:
6385 FIXME("Unsupported format %d\n", format);
6386 return GDI_ERROR;
6388 return needed;
6391 static BOOL get_bitmap_text_metrics(GdiFont *font)
6393 FT_Face ft_face = font->ft_face;
6394 FT_WinFNT_HeaderRec winfnt_header;
6395 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6396 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6397 font->potm->otmSize = size;
6399 #define TM font->potm->otmTextMetrics
6400 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6402 TM.tmHeight = winfnt_header.pixel_height;
6403 TM.tmAscent = winfnt_header.ascent;
6404 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6405 TM.tmInternalLeading = winfnt_header.internal_leading;
6406 TM.tmExternalLeading = winfnt_header.external_leading;
6407 TM.tmAveCharWidth = winfnt_header.avg_width;
6408 TM.tmMaxCharWidth = winfnt_header.max_width;
6409 TM.tmWeight = winfnt_header.weight;
6410 TM.tmOverhang = 0;
6411 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6412 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6413 TM.tmFirstChar = winfnt_header.first_char;
6414 TM.tmLastChar = winfnt_header.last_char;
6415 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6416 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6417 TM.tmItalic = winfnt_header.italic;
6418 TM.tmUnderlined = font->underline;
6419 TM.tmStruckOut = font->strikeout;
6420 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6421 TM.tmCharSet = winfnt_header.charset;
6423 else
6425 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6426 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6427 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6428 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6429 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6430 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6431 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6432 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6433 TM.tmOverhang = 0;
6434 TM.tmDigitizedAspectX = 96; /* FIXME */
6435 TM.tmDigitizedAspectY = 96; /* FIXME */
6436 TM.tmFirstChar = 1;
6437 TM.tmLastChar = 255;
6438 TM.tmDefaultChar = 32;
6439 TM.tmBreakChar = 32;
6440 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6441 TM.tmUnderlined = font->underline;
6442 TM.tmStruckOut = font->strikeout;
6443 /* NB inverted meaning of TMPF_FIXED_PITCH */
6444 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6445 TM.tmCharSet = font->charset;
6447 #undef TM
6449 return TRUE;
6453 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6455 double scale_x, scale_y;
6457 if (font->aveWidth)
6459 scale_x = (double)font->aveWidth;
6460 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6462 else
6463 scale_x = font->scale_y;
6465 scale_x *= fabs(font->font_desc.matrix.eM11);
6466 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6468 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6469 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6471 SCALE_Y(ptm->tmHeight);
6472 SCALE_Y(ptm->tmAscent);
6473 SCALE_Y(ptm->tmDescent);
6474 SCALE_Y(ptm->tmInternalLeading);
6475 SCALE_Y(ptm->tmExternalLeading);
6476 SCALE_Y(ptm->tmOverhang);
6478 SCALE_X(ptm->tmAveCharWidth);
6479 SCALE_X(ptm->tmMaxCharWidth);
6481 #undef SCALE_X
6482 #undef SCALE_Y
6485 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6487 double scale_x, scale_y;
6489 if (font->aveWidth)
6491 scale_x = (double)font->aveWidth;
6492 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6494 else
6495 scale_x = font->scale_y;
6497 scale_x *= fabs(font->font_desc.matrix.eM11);
6498 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6500 scale_font_metrics(font, &potm->otmTextMetrics);
6502 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6503 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6505 SCALE_Y(potm->otmAscent);
6506 SCALE_Y(potm->otmDescent);
6507 SCALE_Y(potm->otmLineGap);
6508 SCALE_Y(potm->otmsCapEmHeight);
6509 SCALE_Y(potm->otmsXHeight);
6510 SCALE_Y(potm->otmrcFontBox.top);
6511 SCALE_Y(potm->otmrcFontBox.bottom);
6512 SCALE_X(potm->otmrcFontBox.left);
6513 SCALE_X(potm->otmrcFontBox.right);
6514 SCALE_Y(potm->otmMacAscent);
6515 SCALE_Y(potm->otmMacDescent);
6516 SCALE_Y(potm->otmMacLineGap);
6517 SCALE_X(potm->otmptSubscriptSize.x);
6518 SCALE_Y(potm->otmptSubscriptSize.y);
6519 SCALE_X(potm->otmptSubscriptOffset.x);
6520 SCALE_Y(potm->otmptSubscriptOffset.y);
6521 SCALE_X(potm->otmptSuperscriptSize.x);
6522 SCALE_Y(potm->otmptSuperscriptSize.y);
6523 SCALE_X(potm->otmptSuperscriptOffset.x);
6524 SCALE_Y(potm->otmptSuperscriptOffset.y);
6525 SCALE_Y(potm->otmsStrikeoutSize);
6526 SCALE_Y(potm->otmsStrikeoutPosition);
6527 SCALE_Y(potm->otmsUnderscoreSize);
6528 SCALE_Y(potm->otmsUnderscorePosition);
6530 #undef SCALE_X
6531 #undef SCALE_Y
6534 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6536 if(!font->potm)
6538 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6540 /* Make sure that the font has sane width/height ratio */
6541 if (font->aveWidth)
6543 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6545 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6546 font->aveWidth = 0;
6550 *ptm = font->potm->otmTextMetrics;
6551 scale_font_metrics(font, ptm);
6552 return TRUE;
6555 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6557 int i;
6559 for(i = 0; i < ft_face->num_charmaps; i++)
6561 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6562 return TRUE;
6564 return FALSE;
6567 static BOOL get_outline_text_metrics(GdiFont *font)
6569 BOOL ret = FALSE;
6570 FT_Face ft_face = font->ft_face;
6571 UINT needed, lenfam, lensty, lenface, lenfull;
6572 TT_OS2 *pOS2;
6573 TT_HoriHeader *pHori;
6574 TT_Postscript *pPost;
6575 FT_Fixed x_scale, y_scale;
6576 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
6577 char *cp;
6578 INT ascent, descent;
6580 TRACE("font=%p\n", font);
6582 if(!FT_IS_SCALABLE(ft_face))
6583 return FALSE;
6585 needed = sizeof(*font->potm);
6587 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6588 family_nameW = strdupW(font->name);
6590 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
6591 if (!style_nameW)
6592 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6593 if (!style_nameW)
6595 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
6596 style_nameW = towstr( CP_ACP, ft_face->style_name );
6598 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
6600 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
6601 if (!face_nameW)
6602 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6603 if (!face_nameW)
6605 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
6606 face_nameW = strdupW(font->name);
6608 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
6609 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
6611 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
6612 if (!full_nameW)
6613 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6614 if (!full_nameW)
6616 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
6617 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
6618 full_nameW = strdupW(fake_nameW);
6620 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
6622 /* These names should be read from the TT name table */
6624 /* length of otmpFamilyName */
6625 needed += lenfam;
6627 /* length of otmpFaceName */
6628 needed += lenface;
6630 /* length of otmpStyleName */
6631 needed += lensty;
6633 /* length of otmpFullName */
6634 needed += lenfull;
6637 x_scale = ft_face->size->metrics.x_scale;
6638 y_scale = ft_face->size->metrics.y_scale;
6640 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6641 if(!pOS2) {
6642 FIXME("Can't find OS/2 table - not TT font?\n");
6643 goto end;
6646 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6647 if(!pHori) {
6648 FIXME("Can't find HHEA table - not TT font?\n");
6649 goto end;
6652 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6654 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",
6655 pOS2->usWinAscent, pOS2->usWinDescent,
6656 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6657 pOS2->xAvgCharWidth,
6658 ft_face->ascender, ft_face->descender, ft_face->height,
6659 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6660 ft_face->bbox.yMax, ft_face->bbox.yMin);
6662 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6663 font->potm->otmSize = needed;
6665 #define TM font->potm->otmTextMetrics
6667 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6668 ascent = pHori->Ascender;
6669 descent = -pHori->Descender;
6670 } else {
6671 ascent = pOS2->usWinAscent;
6672 descent = pOS2->usWinDescent;
6675 font->ntmCellHeight = ascent + descent;
6676 font->ntmAvgWidth = pOS2->xAvgCharWidth;
6678 if(font->yMax) {
6679 TM.tmAscent = font->yMax;
6680 TM.tmDescent = -font->yMin;
6681 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6682 } else {
6683 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6684 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6685 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6686 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6689 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6691 /* MSDN says:
6692 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6694 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6695 ((ascent + descent) -
6696 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6698 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6699 if (TM.tmAveCharWidth == 0) {
6700 TM.tmAveCharWidth = 1;
6702 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6703 TM.tmWeight = FW_REGULAR;
6704 if (font->fake_bold)
6705 TM.tmWeight = FW_BOLD;
6706 else
6708 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6710 if (pOS2->usWeightClass > FW_MEDIUM)
6711 TM.tmWeight = pOS2->usWeightClass;
6713 else if (pOS2->usWeightClass <= FW_MEDIUM)
6714 TM.tmWeight = pOS2->usWeightClass;
6716 TM.tmOverhang = 0;
6717 TM.tmDigitizedAspectX = 96; /* FIXME */
6718 TM.tmDigitizedAspectY = 96; /* FIXME */
6719 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6720 * symbol range to 0 - f0ff
6723 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6725 TM.tmFirstChar = 0;
6726 switch(GetACP())
6728 case 1257: /* Baltic */
6729 TM.tmLastChar = 0xf8fd;
6730 break;
6731 default:
6732 TM.tmLastChar = 0xf0ff;
6734 TM.tmBreakChar = 0x20;
6735 TM.tmDefaultChar = 0x1f;
6737 else
6739 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6740 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6742 if(pOS2->usFirstCharIndex <= 1)
6743 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6744 else if (pOS2->usFirstCharIndex > 0xff)
6745 TM.tmBreakChar = 0x20;
6746 else
6747 TM.tmBreakChar = pOS2->usFirstCharIndex;
6748 TM.tmDefaultChar = TM.tmBreakChar - 1;
6750 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6751 TM.tmUnderlined = font->underline;
6752 TM.tmStruckOut = font->strikeout;
6754 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6755 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6756 (pOS2->version == 0xFFFFU ||
6757 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6758 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6759 else
6760 TM.tmPitchAndFamily = 0;
6762 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6764 case PAN_FAMILY_SCRIPT:
6765 TM.tmPitchAndFamily |= FF_SCRIPT;
6766 break;
6768 case PAN_FAMILY_DECORATIVE:
6769 TM.tmPitchAndFamily |= FF_DECORATIVE;
6770 break;
6772 case PAN_ANY:
6773 case PAN_NO_FIT:
6774 case PAN_FAMILY_TEXT_DISPLAY:
6775 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6776 /* which is clearly not what the panose spec says. */
6777 default:
6778 if(TM.tmPitchAndFamily == 0 || /* fixed */
6779 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6780 TM.tmPitchAndFamily = FF_MODERN;
6781 else
6783 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6785 case PAN_ANY:
6786 case PAN_NO_FIT:
6787 default:
6788 TM.tmPitchAndFamily |= FF_DONTCARE;
6789 break;
6791 case PAN_SERIF_COVE:
6792 case PAN_SERIF_OBTUSE_COVE:
6793 case PAN_SERIF_SQUARE_COVE:
6794 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6795 case PAN_SERIF_SQUARE:
6796 case PAN_SERIF_THIN:
6797 case PAN_SERIF_BONE:
6798 case PAN_SERIF_EXAGGERATED:
6799 case PAN_SERIF_TRIANGLE:
6800 TM.tmPitchAndFamily |= FF_ROMAN;
6801 break;
6803 case PAN_SERIF_NORMAL_SANS:
6804 case PAN_SERIF_OBTUSE_SANS:
6805 case PAN_SERIF_PERP_SANS:
6806 case PAN_SERIF_FLARED:
6807 case PAN_SERIF_ROUNDED:
6808 TM.tmPitchAndFamily |= FF_SWISS;
6809 break;
6812 break;
6815 if(FT_IS_SCALABLE(ft_face))
6816 TM.tmPitchAndFamily |= TMPF_VECTOR;
6818 if(FT_IS_SFNT(ft_face))
6820 if (font->ntmFlags & NTM_PS_OPENTYPE)
6821 TM.tmPitchAndFamily |= TMPF_DEVICE;
6822 else
6823 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6826 TM.tmCharSet = font->charset;
6828 font->potm->otmFiller = 0;
6829 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6830 font->potm->otmfsSelection = pOS2->fsSelection;
6831 font->potm->otmfsType = pOS2->fsType;
6832 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6833 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6834 font->potm->otmItalicAngle = 0; /* POST table */
6835 font->potm->otmEMSquare = ft_face->units_per_EM;
6836 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6837 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6838 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6839 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6840 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6841 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6842 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6843 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6844 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6845 font->potm->otmMacAscent = TM.tmAscent;
6846 font->potm->otmMacDescent = -TM.tmDescent;
6847 font->potm->otmMacLineGap = font->potm->otmLineGap;
6848 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6849 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6850 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6851 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6852 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6853 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6854 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6855 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6856 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6857 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6858 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6859 if(!pPost) {
6860 font->potm->otmsUnderscoreSize = 0;
6861 font->potm->otmsUnderscorePosition = 0;
6862 } else {
6863 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6864 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6866 #undef TM
6868 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6869 cp = (char*)font->potm + sizeof(*font->potm);
6870 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6871 strcpyW((WCHAR*)cp, family_nameW);
6872 cp += lenfam;
6873 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6874 strcpyW((WCHAR*)cp, style_nameW);
6875 cp += lensty;
6876 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6877 strcpyW((WCHAR*)cp, face_nameW);
6878 cp += lenface;
6879 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6880 strcpyW((WCHAR*)cp, full_nameW);
6881 ret = TRUE;
6883 end:
6884 HeapFree(GetProcessHeap(), 0, style_nameW);
6885 HeapFree(GetProcessHeap(), 0, family_nameW);
6886 HeapFree(GetProcessHeap(), 0, face_nameW);
6887 HeapFree(GetProcessHeap(), 0, full_nameW);
6888 return ret;
6891 /*************************************************************
6892 * freetype_GetGlyphOutline
6894 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6895 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6897 struct freetype_physdev *physdev = get_freetype_dev( dev );
6898 DWORD ret;
6900 if (!physdev->font)
6902 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6903 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6906 GDI_CheckNotLock();
6907 EnterCriticalSection( &freetype_cs );
6908 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6909 LeaveCriticalSection( &freetype_cs );
6910 return ret;
6913 /*************************************************************
6914 * freetype_GetTextMetrics
6916 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6918 struct freetype_physdev *physdev = get_freetype_dev( dev );
6919 BOOL ret;
6921 if (!physdev->font)
6923 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6924 return dev->funcs->pGetTextMetrics( dev, metrics );
6927 GDI_CheckNotLock();
6928 EnterCriticalSection( &freetype_cs );
6929 ret = get_text_metrics( physdev->font, metrics );
6930 LeaveCriticalSection( &freetype_cs );
6931 return ret;
6934 /*************************************************************
6935 * freetype_GetOutlineTextMetrics
6937 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6939 struct freetype_physdev *physdev = get_freetype_dev( dev );
6940 UINT ret = 0;
6942 if (!physdev->font)
6944 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6945 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6948 TRACE("font=%p\n", physdev->font);
6950 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6952 GDI_CheckNotLock();
6953 EnterCriticalSection( &freetype_cs );
6955 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6957 if(cbSize >= physdev->font->potm->otmSize)
6959 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6960 scale_outline_font_metrics(physdev->font, potm);
6962 ret = physdev->font->potm->otmSize;
6964 LeaveCriticalSection( &freetype_cs );
6965 return ret;
6968 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6970 HFONTLIST *hfontlist;
6971 child->font = alloc_font();
6972 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6973 if(!child->font->ft_face)
6975 free_font(child->font);
6976 child->font = NULL;
6977 return FALSE;
6980 child->font->font_desc = font->font_desc;
6981 child->font->ntmFlags = child->face->ntmFlags;
6982 child->font->orientation = font->orientation;
6983 child->font->scale_y = font->scale_y;
6984 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6985 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6986 child->font->name = strdupW(child->face->family->FamilyName);
6987 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6988 child->font->base_font = font;
6989 list_add_head(&child_font_list, &child->font->entry);
6990 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6991 return TRUE;
6994 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6996 FT_UInt g;
6997 CHILD_FONT *child_font;
6999 if(font->base_font)
7000 font = font->base_font;
7002 *linked_font = font;
7004 if((*glyph = get_glyph_index(font, c)))
7006 *glyph = get_GSUB_vert_glyph(font, *glyph);
7007 return TRUE;
7010 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7012 if(!child_font->font)
7013 if(!load_child_font(font, child_font))
7014 continue;
7016 if(!child_font->font->ft_face)
7017 continue;
7018 g = get_glyph_index(child_font->font, c);
7019 g = get_GSUB_vert_glyph(child_font->font, g);
7020 if(g)
7022 *glyph = g;
7023 *linked_font = child_font->font;
7024 return TRUE;
7027 return FALSE;
7030 /*************************************************************
7031 * freetype_GetCharWidth
7033 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7035 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7036 UINT c;
7037 GLYPHMETRICS gm;
7038 FT_UInt glyph_index;
7039 GdiFont *linked_font;
7040 struct freetype_physdev *physdev = get_freetype_dev( dev );
7042 if (!physdev->font)
7044 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7045 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7048 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7050 GDI_CheckNotLock();
7051 EnterCriticalSection( &freetype_cs );
7052 for(c = firstChar; c <= lastChar; c++) {
7053 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
7054 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7055 &gm, 0, NULL, &identity);
7056 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
7058 LeaveCriticalSection( &freetype_cs );
7059 return TRUE;
7062 /*************************************************************
7063 * freetype_GetCharABCWidths
7065 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7067 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7068 UINT c;
7069 GLYPHMETRICS gm;
7070 FT_UInt glyph_index;
7071 GdiFont *linked_font;
7072 struct freetype_physdev *physdev = get_freetype_dev( dev );
7074 if (!physdev->font)
7076 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7077 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7080 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7082 GDI_CheckNotLock();
7083 EnterCriticalSection( &freetype_cs );
7085 for(c = firstChar; c <= lastChar; c++) {
7086 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
7087 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7088 &gm, 0, NULL, &identity);
7089 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
7090 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
7091 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
7092 FONT_GM(linked_font,glyph_index)->bbx;
7094 LeaveCriticalSection( &freetype_cs );
7095 return TRUE;
7098 /*************************************************************
7099 * freetype_GetCharABCWidthsI
7101 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7103 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7104 UINT c;
7105 GLYPHMETRICS gm;
7106 FT_UInt glyph_index;
7107 GdiFont *linked_font;
7108 struct freetype_physdev *physdev = get_freetype_dev( dev );
7110 if (!physdev->font)
7112 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7113 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7116 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7117 return FALSE;
7119 GDI_CheckNotLock();
7120 EnterCriticalSection( &freetype_cs );
7122 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
7123 if (!pgi)
7124 for(c = firstChar; c < firstChar+count; c++) {
7125 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
7126 &gm, 0, NULL, &identity);
7127 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
7128 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
7129 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
7130 - FONT_GM(linked_font,c)->bbx;
7132 else
7133 for(c = 0; c < count; c++) {
7134 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
7135 &gm, 0, NULL, &identity);
7136 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
7137 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
7138 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
7139 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
7142 LeaveCriticalSection( &freetype_cs );
7143 return TRUE;
7146 /*************************************************************
7147 * freetype_GetTextExtentExPoint
7149 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
7150 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
7152 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7153 INT idx;
7154 INT nfit = 0, ext;
7155 GLYPHMETRICS gm;
7156 TEXTMETRICW tm;
7157 FT_UInt glyph_index;
7158 GdiFont *linked_font;
7159 struct freetype_physdev *physdev = get_freetype_dev( dev );
7161 if (!physdev->font)
7163 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7164 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
7167 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
7169 GDI_CheckNotLock();
7170 EnterCriticalSection( &freetype_cs );
7172 size->cx = 0;
7173 get_text_metrics( physdev->font, &tm );
7174 size->cy = tm.tmHeight;
7176 for(idx = 0; idx < count; idx++) {
7177 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
7178 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7179 &gm, 0, NULL, &identity);
7180 size->cx += FONT_GM(linked_font,glyph_index)->adv;
7181 ext = size->cx;
7182 if (! pnfit || ext <= max_ext) {
7183 ++nfit;
7184 if (dxs)
7185 dxs[idx] = ext;
7189 if (pnfit)
7190 *pnfit = nfit;
7192 LeaveCriticalSection( &freetype_cs );
7193 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7194 return TRUE;
7197 /*************************************************************
7198 * freetype_GetTextExtentExPointI
7200 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
7201 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
7203 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7204 INT idx;
7205 INT nfit = 0, ext;
7206 GLYPHMETRICS gm;
7207 TEXTMETRICW tm;
7208 struct freetype_physdev *physdev = get_freetype_dev( dev );
7210 if (!physdev->font)
7212 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7213 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
7216 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
7218 GDI_CheckNotLock();
7219 EnterCriticalSection( &freetype_cs );
7221 size->cx = 0;
7222 get_text_metrics(physdev->font, &tm);
7223 size->cy = tm.tmHeight;
7225 for(idx = 0; idx < count; idx++) {
7226 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
7227 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
7228 ext = size->cx;
7229 if (! pnfit || ext <= max_ext) {
7230 ++nfit;
7231 if (dxs)
7232 dxs[idx] = ext;
7236 if (pnfit)
7237 *pnfit = nfit;
7239 LeaveCriticalSection( &freetype_cs );
7240 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7241 return TRUE;
7244 /*************************************************************
7245 * freetype_GetFontData
7247 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7249 struct freetype_physdev *physdev = get_freetype_dev( dev );
7251 if (!physdev->font)
7253 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7254 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7257 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7258 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7259 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7261 return get_font_data( physdev->font, table, offset, buf, cbData );
7264 /*************************************************************
7265 * freetype_GetTextFace
7267 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7269 INT n;
7270 struct freetype_physdev *physdev = get_freetype_dev( dev );
7272 if (!physdev->font)
7274 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7275 return dev->funcs->pGetTextFace( dev, count, str );
7278 n = strlenW(physdev->font->name) + 1;
7279 if (str)
7281 lstrcpynW(str, physdev->font->name, count);
7282 n = min(count, n);
7284 return n;
7287 /*************************************************************
7288 * freetype_GetTextCharsetInfo
7290 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7292 struct freetype_physdev *physdev = get_freetype_dev( dev );
7294 if (!physdev->font)
7296 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7297 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7299 if (fs) *fs = physdev->font->fs;
7300 return physdev->font->charset;
7303 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7305 GdiFont *font = dc->gdiFont, *linked_font;
7306 struct list *first_hfont;
7307 BOOL ret;
7309 GDI_CheckNotLock();
7310 EnterCriticalSection( &freetype_cs );
7311 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
7312 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
7313 if(font == linked_font)
7314 *new_hfont = dc->hFont;
7315 else
7317 first_hfont = list_head(&linked_font->hfontlist);
7318 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
7320 LeaveCriticalSection( &freetype_cs );
7321 return ret;
7324 /* Retrieve a list of supported Unicode ranges for a given font.
7325 * Can be called with NULL gs to calculate the buffer size. Returns
7326 * the number of ranges found.
7328 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7330 DWORD num_ranges = 0;
7332 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7334 FT_UInt glyph_code;
7335 FT_ULong char_code, char_code_prev;
7337 glyph_code = 0;
7338 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7340 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7341 face->num_glyphs, glyph_code, char_code);
7343 if (!glyph_code) return 0;
7345 if (gs)
7347 gs->ranges[0].wcLow = (USHORT)char_code;
7348 gs->ranges[0].cGlyphs = 0;
7349 gs->cGlyphsSupported = 0;
7352 num_ranges = 1;
7353 while (glyph_code)
7355 if (char_code < char_code_prev)
7357 ERR("expected increasing char code from FT_Get_Next_Char\n");
7358 return 0;
7360 if (char_code - char_code_prev > 1)
7362 num_ranges++;
7363 if (gs)
7365 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7366 gs->ranges[num_ranges - 1].cGlyphs = 1;
7367 gs->cGlyphsSupported++;
7370 else if (gs)
7372 gs->ranges[num_ranges - 1].cGlyphs++;
7373 gs->cGlyphsSupported++;
7375 char_code_prev = char_code;
7376 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7379 else
7380 FIXME("encoding %u not supported\n", face->charmap->encoding);
7382 return num_ranges;
7385 /*************************************************************
7386 * freetype_GetFontUnicodeRanges
7388 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7390 struct freetype_physdev *physdev = get_freetype_dev( dev );
7391 DWORD size, num_ranges;
7393 if (!physdev->font)
7395 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7396 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7399 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7400 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7401 if (glyphset)
7403 glyphset->cbThis = size;
7404 glyphset->cRanges = num_ranges;
7405 glyphset->flAccel = 0;
7407 return size;
7410 /*************************************************************
7411 * freetype_FontIsLinked
7413 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7415 struct freetype_physdev *physdev = get_freetype_dev( dev );
7416 BOOL ret;
7418 if (!physdev->font)
7420 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7421 return dev->funcs->pFontIsLinked( dev );
7424 GDI_CheckNotLock();
7425 EnterCriticalSection( &freetype_cs );
7426 ret = !list_empty(&physdev->font->child_fonts);
7427 LeaveCriticalSection( &freetype_cs );
7428 return ret;
7431 static BOOL is_hinting_enabled(void)
7433 /* Use the >= 2.2.0 function if available */
7434 if(pFT_Get_TrueType_Engine_Type)
7436 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
7437 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
7439 #ifdef FT_DRIVER_HAS_HINTER
7440 else
7442 FT_Module mod;
7444 /* otherwise if we've been compiled with < 2.2.0 headers
7445 use the internal macro */
7446 mod = pFT_Get_Module(library, "truetype");
7447 if(mod && FT_DRIVER_HAS_HINTER(mod))
7448 return TRUE;
7450 #endif
7452 return FALSE;
7455 static BOOL is_subpixel_rendering_enabled( void )
7457 #ifdef HAVE_FREETYPE_FTLCDFIL_H
7458 return pFT_Library_SetLcdFilter &&
7459 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
7460 #else
7461 return FALSE;
7462 #endif
7465 /*************************************************************************
7466 * GetRasterizerCaps (GDI32.@)
7468 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7470 static int hinting = -1;
7471 static int subpixel = -1;
7473 if(hinting == -1)
7475 hinting = is_hinting_enabled();
7476 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
7479 if ( subpixel == -1 )
7481 subpixel = is_subpixel_rendering_enabled();
7482 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
7485 lprs->nSize = sizeof(RASTERIZER_STATUS);
7486 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
7487 if ( subpixel )
7488 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
7489 lprs->nLanguageID = 0;
7490 return TRUE;
7493 /*************************************************************
7494 * freetype_GdiRealizationInfo
7496 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7498 struct freetype_physdev *physdev = get_freetype_dev( dev );
7499 realization_info_t *info = ptr;
7501 if (!physdev->font)
7503 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7504 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7507 FIXME("(%p, %p): stub!\n", physdev->font, info);
7509 info->flags = 1;
7510 if(FT_IS_SCALABLE(physdev->font->ft_face))
7511 info->flags |= 2;
7513 info->cache_num = physdev->font->cache_num;
7514 info->unknown2 = -1;
7515 return TRUE;
7518 /*************************************************************************
7519 * Kerning support for TrueType fonts
7521 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7523 struct TT_kern_table
7525 USHORT version;
7526 USHORT nTables;
7529 struct TT_kern_subtable
7531 USHORT version;
7532 USHORT length;
7533 union
7535 USHORT word;
7536 struct
7538 USHORT horizontal : 1;
7539 USHORT minimum : 1;
7540 USHORT cross_stream: 1;
7541 USHORT override : 1;
7542 USHORT reserved1 : 4;
7543 USHORT format : 8;
7544 } bits;
7545 } coverage;
7548 struct TT_format0_kern_subtable
7550 USHORT nPairs;
7551 USHORT searchRange;
7552 USHORT entrySelector;
7553 USHORT rangeShift;
7556 struct TT_kern_pair
7558 USHORT left;
7559 USHORT right;
7560 short value;
7563 static DWORD parse_format0_kern_subtable(GdiFont *font,
7564 const struct TT_format0_kern_subtable *tt_f0_ks,
7565 const USHORT *glyph_to_char,
7566 KERNINGPAIR *kern_pair, DWORD cPairs)
7568 USHORT i, nPairs;
7569 const struct TT_kern_pair *tt_kern_pair;
7571 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7573 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7575 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7576 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7577 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7579 if (!kern_pair || !cPairs)
7580 return nPairs;
7582 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7584 nPairs = min(nPairs, cPairs);
7586 for (i = 0; i < nPairs; i++)
7588 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7589 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7590 /* this algorithm appears to better match what Windows does */
7591 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7592 if (kern_pair->iKernAmount < 0)
7594 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7595 kern_pair->iKernAmount -= font->ppem;
7597 else if (kern_pair->iKernAmount > 0)
7599 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7600 kern_pair->iKernAmount += font->ppem;
7602 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7604 TRACE("left %u right %u value %d\n",
7605 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7607 kern_pair++;
7609 TRACE("copied %u entries\n", nPairs);
7610 return nPairs;
7613 /*************************************************************
7614 * freetype_GetKerningPairs
7616 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7618 DWORD length;
7619 void *buf;
7620 const struct TT_kern_table *tt_kern_table;
7621 const struct TT_kern_subtable *tt_kern_subtable;
7622 USHORT i, nTables;
7623 USHORT *glyph_to_char;
7624 GdiFont *font;
7625 struct freetype_physdev *physdev = get_freetype_dev( dev );
7627 if (!(font = physdev->font))
7629 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7630 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7633 GDI_CheckNotLock();
7634 EnterCriticalSection( &freetype_cs );
7635 if (font->total_kern_pairs != (DWORD)-1)
7637 if (cPairs && kern_pair)
7639 cPairs = min(cPairs, font->total_kern_pairs);
7640 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7642 else cPairs = font->total_kern_pairs;
7644 LeaveCriticalSection( &freetype_cs );
7645 return cPairs;
7648 font->total_kern_pairs = 0;
7650 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7652 if (length == GDI_ERROR)
7654 TRACE("no kerning data in the font\n");
7655 LeaveCriticalSection( &freetype_cs );
7656 return 0;
7659 buf = HeapAlloc(GetProcessHeap(), 0, length);
7660 if (!buf)
7662 WARN("Out of memory\n");
7663 LeaveCriticalSection( &freetype_cs );
7664 return 0;
7667 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7669 /* build a glyph index to char code map */
7670 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7671 if (!glyph_to_char)
7673 WARN("Out of memory allocating a glyph index to char code map\n");
7674 HeapFree(GetProcessHeap(), 0, buf);
7675 LeaveCriticalSection( &freetype_cs );
7676 return 0;
7679 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7681 FT_UInt glyph_code;
7682 FT_ULong char_code;
7684 glyph_code = 0;
7685 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7687 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7688 font->ft_face->num_glyphs, glyph_code, char_code);
7690 while (glyph_code)
7692 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7694 /* FIXME: This doesn't match what Windows does: it does some fancy
7695 * things with duplicate glyph index to char code mappings, while
7696 * we just avoid overriding existing entries.
7698 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7699 glyph_to_char[glyph_code] = (USHORT)char_code;
7701 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7704 else
7706 ULONG n;
7708 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7709 for (n = 0; n <= 65535; n++)
7710 glyph_to_char[n] = (USHORT)n;
7713 tt_kern_table = buf;
7714 nTables = GET_BE_WORD(tt_kern_table->nTables);
7715 TRACE("version %u, nTables %u\n",
7716 GET_BE_WORD(tt_kern_table->version), nTables);
7718 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7720 for (i = 0; i < nTables; i++)
7722 struct TT_kern_subtable tt_kern_subtable_copy;
7724 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7725 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7726 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7728 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7729 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7730 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7732 /* According to the TrueType specification this is the only format
7733 * that will be properly interpreted by Windows and OS/2
7735 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7737 DWORD new_chunk, old_total = font->total_kern_pairs;
7739 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7740 glyph_to_char, NULL, 0);
7741 font->total_kern_pairs += new_chunk;
7743 if (!font->kern_pairs)
7744 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7745 font->total_kern_pairs * sizeof(*font->kern_pairs));
7746 else
7747 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7748 font->total_kern_pairs * sizeof(*font->kern_pairs));
7750 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7751 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7753 else
7754 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7756 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7759 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7760 HeapFree(GetProcessHeap(), 0, buf);
7762 if (cPairs && kern_pair)
7764 cPairs = min(cPairs, font->total_kern_pairs);
7765 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7767 else cPairs = font->total_kern_pairs;
7769 LeaveCriticalSection( &freetype_cs );
7770 return cPairs;
7773 static const struct gdi_dc_funcs freetype_funcs =
7775 NULL, /* pAbortDoc */
7776 NULL, /* pAbortPath */
7777 NULL, /* pAlphaBlend */
7778 NULL, /* pAngleArc */
7779 NULL, /* pArc */
7780 NULL, /* pArcTo */
7781 NULL, /* pBeginPath */
7782 NULL, /* pBlendImage */
7783 NULL, /* pChord */
7784 NULL, /* pCloseFigure */
7785 NULL, /* pCreateCompatibleDC */
7786 freetype_CreateDC, /* pCreateDC */
7787 freetype_DeleteDC, /* pDeleteDC */
7788 NULL, /* pDeleteObject */
7789 NULL, /* pDeviceCapabilities */
7790 NULL, /* pEllipse */
7791 NULL, /* pEndDoc */
7792 NULL, /* pEndPage */
7793 NULL, /* pEndPath */
7794 freetype_EnumFonts, /* pEnumFonts */
7795 NULL, /* pEnumICMProfiles */
7796 NULL, /* pExcludeClipRect */
7797 NULL, /* pExtDeviceMode */
7798 NULL, /* pExtEscape */
7799 NULL, /* pExtFloodFill */
7800 NULL, /* pExtSelectClipRgn */
7801 NULL, /* pExtTextOut */
7802 NULL, /* pFillPath */
7803 NULL, /* pFillRgn */
7804 NULL, /* pFlattenPath */
7805 freetype_FontIsLinked, /* pFontIsLinked */
7806 NULL, /* pFrameRgn */
7807 NULL, /* pGdiComment */
7808 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7809 NULL, /* pGetBoundsRect */
7810 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7811 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7812 freetype_GetCharWidth, /* pGetCharWidth */
7813 NULL, /* pGetDeviceCaps */
7814 NULL, /* pGetDeviceGammaRamp */
7815 freetype_GetFontData, /* pGetFontData */
7816 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7817 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7818 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7819 NULL, /* pGetICMProfile */
7820 NULL, /* pGetImage */
7821 freetype_GetKerningPairs, /* pGetKerningPairs */
7822 NULL, /* pGetNearestColor */
7823 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7824 NULL, /* pGetPixel */
7825 NULL, /* pGetSystemPaletteEntries */
7826 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7827 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7828 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7829 freetype_GetTextFace, /* pGetTextFace */
7830 freetype_GetTextMetrics, /* pGetTextMetrics */
7831 NULL, /* pGradientFill */
7832 NULL, /* pIntersectClipRect */
7833 NULL, /* pInvertRgn */
7834 NULL, /* pLineTo */
7835 NULL, /* pModifyWorldTransform */
7836 NULL, /* pMoveTo */
7837 NULL, /* pOffsetClipRgn */
7838 NULL, /* pOffsetViewportOrg */
7839 NULL, /* pOffsetWindowOrg */
7840 NULL, /* pPaintRgn */
7841 NULL, /* pPatBlt */
7842 NULL, /* pPie */
7843 NULL, /* pPolyBezier */
7844 NULL, /* pPolyBezierTo */
7845 NULL, /* pPolyDraw */
7846 NULL, /* pPolyPolygon */
7847 NULL, /* pPolyPolyline */
7848 NULL, /* pPolygon */
7849 NULL, /* pPolyline */
7850 NULL, /* pPolylineTo */
7851 NULL, /* pPutImage */
7852 NULL, /* pRealizeDefaultPalette */
7853 NULL, /* pRealizePalette */
7854 NULL, /* pRectangle */
7855 NULL, /* pResetDC */
7856 NULL, /* pRestoreDC */
7857 NULL, /* pRoundRect */
7858 NULL, /* pSaveDC */
7859 NULL, /* pScaleViewportExt */
7860 NULL, /* pScaleWindowExt */
7861 NULL, /* pSelectBitmap */
7862 NULL, /* pSelectBrush */
7863 NULL, /* pSelectClipPath */
7864 freetype_SelectFont, /* pSelectFont */
7865 NULL, /* pSelectPalette */
7866 NULL, /* pSelectPen */
7867 NULL, /* pSetArcDirection */
7868 NULL, /* pSetBkColor */
7869 NULL, /* pSetBkMode */
7870 NULL, /* pSetDCBrushColor */
7871 NULL, /* pSetDCPenColor */
7872 NULL, /* pSetDIBColorTable */
7873 NULL, /* pSetDIBitsToDevice */
7874 NULL, /* pSetDeviceClipping */
7875 NULL, /* pSetDeviceGammaRamp */
7876 NULL, /* pSetLayout */
7877 NULL, /* pSetMapMode */
7878 NULL, /* pSetMapperFlags */
7879 NULL, /* pSetPixel */
7880 NULL, /* pSetPolyFillMode */
7881 NULL, /* pSetROP2 */
7882 NULL, /* pSetRelAbs */
7883 NULL, /* pSetStretchBltMode */
7884 NULL, /* pSetTextAlign */
7885 NULL, /* pSetTextCharacterExtra */
7886 NULL, /* pSetTextColor */
7887 NULL, /* pSetTextJustification */
7888 NULL, /* pSetViewportExt */
7889 NULL, /* pSetViewportOrg */
7890 NULL, /* pSetWindowExt */
7891 NULL, /* pSetWindowOrg */
7892 NULL, /* pSetWorldTransform */
7893 NULL, /* pStartDoc */
7894 NULL, /* pStartPage */
7895 NULL, /* pStretchBlt */
7896 NULL, /* pStretchDIBits */
7897 NULL, /* pStrokeAndFillPath */
7898 NULL, /* pStrokePath */
7899 NULL, /* pUnrealizePalette */
7900 NULL, /* pWidenPath */
7901 NULL, /* wine_get_wgl_driver */
7902 GDI_PRIORITY_FONT_DRV /* priority */
7905 #else /* HAVE_FREETYPE */
7907 /*************************************************************************/
7909 BOOL WineEngInit(void)
7911 return FALSE;
7913 BOOL WineEngDestroyFontInstance(HFONT hfont)
7915 return FALSE;
7918 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7920 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7921 return 1;
7924 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7926 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7927 return TRUE;
7930 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7932 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7933 return NULL;
7936 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
7937 LPCWSTR font_file, LPCWSTR font_path )
7939 FIXME("stub\n");
7940 return FALSE;
7943 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7945 return FALSE;
7948 /*************************************************************************
7949 * GetRasterizerCaps (GDI32.@)
7951 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7953 lprs->nSize = sizeof(RASTERIZER_STATUS);
7954 lprs->wFlags = 0;
7955 lprs->nLanguageID = 0;
7956 return TRUE;
7959 #endif /* HAVE_FREETYPE */