msvcp: Sync num_get<>::_Getifld.
[wine.git] / dlls / gdi32 / freetype.c
blob20186fa94720c4f7bed1fc19ef81a80b3b0b31e9
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(FcConfigGetCurrent);
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(FcPatternGetString);
205 #endif
207 #undef MAKE_FUNCPTR
209 #ifndef FT_MAKE_TAG
210 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
211 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
212 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
213 #endif
215 #ifndef ft_encoding_none
216 #define FT_ENCODING_NONE ft_encoding_none
217 #endif
218 #ifndef ft_encoding_ms_symbol
219 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
220 #endif
221 #ifndef ft_encoding_unicode
222 #define FT_ENCODING_UNICODE ft_encoding_unicode
223 #endif
224 #ifndef ft_encoding_apple_roman
225 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
226 #endif
228 #ifdef WORDS_BIGENDIAN
229 #define GET_BE_WORD(x) (x)
230 #else
231 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
232 #endif
234 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
235 typedef struct {
236 FT_Short height;
237 FT_Short width;
238 FT_Pos size;
239 FT_Pos x_ppem;
240 FT_Pos y_ppem;
241 FT_Short internal_leading;
242 } Bitmap_Size;
244 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
245 So to let this compile on older versions of FreeType we'll define the
246 new structure here. */
247 typedef struct {
248 FT_Short height, width;
249 FT_Pos size, x_ppem, y_ppem;
250 } My_FT_Bitmap_Size;
252 struct enum_data
254 ENUMLOGFONTEXW elf;
255 NEWTEXTMETRICEXW ntm;
256 DWORD type;
259 typedef struct tagFace {
260 struct list entry;
261 WCHAR *StyleName;
262 WCHAR *FullName;
263 char *file;
264 void *font_data_ptr;
265 DWORD font_data_size;
266 FT_Long face_index;
267 FONTSIGNATURE fs;
268 DWORD ntmFlags;
269 FT_Fixed font_version;
270 BOOL scalable;
271 BOOL vertical;
272 Bitmap_Size size; /* set if face is a bitmap */
273 BOOL external; /* TRUE if we should manually add this font to the registry */
274 struct tagFamily *family;
275 /* Cached data for Enum */
276 struct enum_data *cached_enum_data;
277 } Face;
279 typedef struct tagFamily {
280 struct list entry;
281 WCHAR *FamilyName;
282 WCHAR *EnglishName;
283 struct list faces;
284 struct list *replacement;
285 } Family;
287 typedef struct {
288 GLYPHMETRICS gm;
289 INT adv; /* These three hold to widths of the unrotated chars */
290 INT lsb;
291 INT bbx;
292 BOOL init;
293 } GM;
295 typedef struct {
296 FLOAT eM11, eM12;
297 FLOAT eM21, eM22;
298 } FMAT2;
300 typedef struct {
301 DWORD hash;
302 LOGFONTW lf;
303 FMAT2 matrix;
304 BOOL can_use_bitmap;
305 } FONT_DESC;
307 typedef struct tagHFONTLIST {
308 struct list entry;
309 HFONT hfont;
310 } HFONTLIST;
312 typedef struct {
313 struct list entry;
314 Face *face;
315 GdiFont *font;
316 } CHILD_FONT;
318 struct tagGdiFont {
319 struct list entry;
320 GM **gm;
321 DWORD gmsize;
322 struct list hfontlist;
323 OUTLINETEXTMETRICW *potm;
324 DWORD total_kern_pairs;
325 KERNINGPAIR *kern_pairs;
326 struct list child_fonts;
328 /* the following members can be accessed without locking, they are never modified after creation */
329 FT_Face ft_face;
330 struct font_mapping *mapping;
331 LPWSTR name;
332 int charset;
333 int codepage;
334 BOOL fake_italic;
335 BOOL fake_bold;
336 BYTE underline;
337 BYTE strikeout;
338 INT orientation;
339 FONT_DESC font_desc;
340 LONG aveWidth, ppem;
341 double scale_y;
342 SHORT yMax;
343 SHORT yMin;
344 DWORD ntmFlags;
345 UINT ntmCellHeight, ntmAvgWidth;
346 FONTSIGNATURE fs;
347 GdiFont *base_font;
348 VOID *GSUB_Table;
349 DWORD cache_num;
352 typedef struct {
353 struct list entry;
354 const WCHAR *font_name;
355 FONTSIGNATURE fs;
356 struct list links;
357 } SYSTEM_LINKS;
359 struct enum_charset_element {
360 DWORD mask;
361 DWORD charset;
362 WCHAR name[LF_FACESIZE];
365 struct enum_charset_list {
366 DWORD total;
367 struct enum_charset_element element[32];
370 #define GM_BLOCK_SIZE 128
371 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
373 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
374 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
375 #define UNUSED_CACHE_SIZE 10
376 static struct list child_font_list = LIST_INIT(child_font_list);
377 static struct list system_links = LIST_INIT(system_links);
379 static struct list font_subst_list = LIST_INIT(font_subst_list);
381 static struct list font_list = LIST_INIT(font_list);
383 struct freetype_physdev
385 struct gdi_physdev dev;
386 GdiFont *font;
389 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
391 return (struct freetype_physdev *)dev;
394 static const struct gdi_dc_funcs freetype_funcs;
396 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
397 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
398 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
400 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
401 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
402 'W','i','n','d','o','w','s','\\',
403 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
404 'F','o','n','t','s','\0'};
406 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
407 'W','i','n','d','o','w','s',' ','N','T','\\',
408 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
409 'F','o','n','t','s','\0'};
411 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
412 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
413 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
414 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
416 static const WCHAR * const SystemFontValues[] = {
417 System_Value,
418 OEMFont_Value,
419 FixedSys_Value,
420 NULL
423 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
424 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
426 /* Interesting and well-known (frequently-assumed!) font names */
427 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
428 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 };
429 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
430 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
431 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
432 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
433 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
434 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
436 static const WCHAR arial[] = {'A','r','i','a','l',0};
437 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
438 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};
439 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};
440 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
441 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
442 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
443 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
444 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
445 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
447 static const WCHAR *default_serif_list[] =
449 times_new_roman,
450 liberation_serif,
451 bitstream_vera_serif,
452 NULL
455 static const WCHAR *default_fixed_list[] =
457 courier_new,
458 liberation_mono,
459 bitstream_vera_sans_mono,
460 NULL
463 static const WCHAR *default_sans_list[] =
465 arial,
466 liberation_sans,
467 bitstream_vera_sans,
468 NULL
471 typedef struct {
472 WCHAR *name;
473 INT charset;
474 } NameCs;
476 typedef struct tagFontSubst {
477 struct list entry;
478 NameCs from;
479 NameCs to;
480 } FontSubst;
482 /* Registry font cache key and value names */
483 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
484 'F','o','n','t','s',0};
485 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
486 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
487 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
488 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
489 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
490 static const WCHAR face_vertical_value[] = {'V','e','r','t','i','c','a','l',0};
491 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
492 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
493 static const WCHAR face_size_value[] = {'S','i','z','e',0};
494 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
495 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
496 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
497 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
498 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
501 struct font_mapping
503 struct list entry;
504 int refcount;
505 dev_t dev;
506 ino_t ino;
507 void *data;
508 size_t size;
511 static struct list mappings_list = LIST_INIT( mappings_list );
513 static CRITICAL_SECTION freetype_cs;
514 static CRITICAL_SECTION_DEBUG critsect_debug =
516 0, 0, &freetype_cs,
517 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
518 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
520 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
522 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
524 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
525 static BOOL use_default_fallback = FALSE;
527 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
528 static BOOL get_outline_text_metrics(GdiFont *font);
529 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
531 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
532 'W','i','n','d','o','w','s',' ','N','T','\\',
533 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
534 'S','y','s','t','e','m','L','i','n','k',0};
536 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
537 'F','o','n','t','L','i','n','k','\\',
538 'S','y','s','t','e','m','L','i','n','k',0};
540 /****************************************
541 * Notes on .fon files
543 * The fonts System, FixedSys and Terminal are special. There are typically multiple
544 * versions installed for different resolutions and codepages. Windows stores which one to use
545 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
546 * Key Meaning
547 * FIXEDFON.FON FixedSys
548 * FONTS.FON System
549 * OEMFONT.FON Terminal
550 * LogPixels Current dpi set by the display control panel applet
551 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
552 * also has a LogPixels value that appears to mirror this)
554 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
555 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
556 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
557 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
558 * so that makes sense.
560 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
561 * to be mapped into the registry on Windows 2000 at least).
562 * I have
563 * woafont=app850.fon
564 * ega80woa.fon=ega80850.fon
565 * ega40woa.fon=ega40850.fon
566 * cga80woa.fon=cga80850.fon
567 * cga40woa.fon=cga40850.fon
570 /* These are all structures needed for the GSUB table */
572 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
573 #define TATEGAKI_LOWER_BOUND 0x02F1
575 typedef struct {
576 DWORD version;
577 WORD ScriptList;
578 WORD FeatureList;
579 WORD LookupList;
580 } GSUB_Header;
582 typedef struct {
583 CHAR ScriptTag[4];
584 WORD Script;
585 } GSUB_ScriptRecord;
587 typedef struct {
588 WORD ScriptCount;
589 GSUB_ScriptRecord ScriptRecord[1];
590 } GSUB_ScriptList;
592 typedef struct {
593 CHAR LangSysTag[4];
594 WORD LangSys;
595 } GSUB_LangSysRecord;
597 typedef struct {
598 WORD DefaultLangSys;
599 WORD LangSysCount;
600 GSUB_LangSysRecord LangSysRecord[1];
601 } GSUB_Script;
603 typedef struct {
604 WORD LookupOrder; /* Reserved */
605 WORD ReqFeatureIndex;
606 WORD FeatureCount;
607 WORD FeatureIndex[1];
608 } GSUB_LangSys;
610 typedef struct {
611 CHAR FeatureTag[4];
612 WORD Feature;
613 } GSUB_FeatureRecord;
615 typedef struct {
616 WORD FeatureCount;
617 GSUB_FeatureRecord FeatureRecord[1];
618 } GSUB_FeatureList;
620 typedef struct {
621 WORD FeatureParams; /* Reserved */
622 WORD LookupCount;
623 WORD LookupListIndex[1];
624 } GSUB_Feature;
626 typedef struct {
627 WORD LookupCount;
628 WORD Lookup[1];
629 } GSUB_LookupList;
631 typedef struct {
632 WORD LookupType;
633 WORD LookupFlag;
634 WORD SubTableCount;
635 WORD SubTable[1];
636 } GSUB_LookupTable;
638 typedef struct {
639 WORD CoverageFormat;
640 WORD GlyphCount;
641 WORD GlyphArray[1];
642 } GSUB_CoverageFormat1;
644 typedef struct {
645 WORD Start;
646 WORD End;
647 WORD StartCoverageIndex;
648 } GSUB_RangeRecord;
650 typedef struct {
651 WORD CoverageFormat;
652 WORD RangeCount;
653 GSUB_RangeRecord RangeRecord[1];
654 } GSUB_CoverageFormat2;
656 typedef struct {
657 WORD SubstFormat; /* = 1 */
658 WORD Coverage;
659 WORD DeltaGlyphID;
660 } GSUB_SingleSubstFormat1;
662 typedef struct {
663 WORD SubstFormat; /* = 2 */
664 WORD Coverage;
665 WORD GlyphCount;
666 WORD Substitute[1];
667 }GSUB_SingleSubstFormat2;
669 #ifdef HAVE_CARBON_CARBON_H
670 static char *find_cache_dir(void)
672 FSRef ref;
673 OSErr err;
674 static char cached_path[MAX_PATH];
675 static const char *wine = "/Wine", *fonts = "/Fonts";
677 if(*cached_path) return cached_path;
679 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
680 if(err != noErr)
682 WARN("can't create cached data folder\n");
683 return NULL;
685 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
686 if(err != noErr)
688 WARN("can't create cached data path\n");
689 *cached_path = '\0';
690 return NULL;
692 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
694 ERR("Could not create full path\n");
695 *cached_path = '\0';
696 return NULL;
698 strcat(cached_path, wine);
700 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
702 WARN("Couldn't mkdir %s\n", cached_path);
703 *cached_path = '\0';
704 return NULL;
706 strcat(cached_path, fonts);
707 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
709 WARN("Couldn't mkdir %s\n", cached_path);
710 *cached_path = '\0';
711 return NULL;
713 return cached_path;
716 /******************************************************************
717 * expand_mac_font
719 * Extracts individual TrueType font files from a Mac suitcase font
720 * and saves them into the user's caches directory (see
721 * find_cache_dir()).
722 * Returns a NULL terminated array of filenames.
724 * We do this because they are apps that try to read ttf files
725 * themselves and they don't like Mac suitcase files.
727 static char **expand_mac_font(const char *path)
729 FSRef ref;
730 SInt16 res_ref;
731 OSStatus s;
732 unsigned int idx;
733 const char *out_dir;
734 const char *filename;
735 int output_len;
736 struct {
737 char **array;
738 unsigned int size, max_size;
739 } ret;
741 TRACE("path %s\n", path);
743 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
744 if(s != noErr)
746 WARN("failed to get ref\n");
747 return NULL;
750 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
751 if(s != noErr)
753 TRACE("no data fork, so trying resource fork\n");
754 res_ref = FSOpenResFile(&ref, fsRdPerm);
755 if(res_ref == -1)
757 TRACE("unable to open resource fork\n");
758 return NULL;
762 ret.size = 0;
763 ret.max_size = 10;
764 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
765 if(!ret.array)
767 CloseResFile(res_ref);
768 return NULL;
771 out_dir = find_cache_dir();
773 filename = strrchr(path, '/');
774 if(!filename) filename = path;
775 else filename++;
777 /* output filename has the form out_dir/filename_%04x.ttf */
778 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
780 UseResFile(res_ref);
781 idx = 1;
782 while(1)
784 FamRec *fam_rec;
785 unsigned short *num_faces_ptr, num_faces, face;
786 AsscEntry *assoc;
787 Handle fond;
788 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
790 fond = Get1IndResource(fond_res, idx);
791 if(!fond) break;
792 TRACE("got fond resource %d\n", idx);
793 HLock(fond);
795 fam_rec = *(FamRec**)fond;
796 num_faces_ptr = (unsigned short *)(fam_rec + 1);
797 num_faces = GET_BE_WORD(*num_faces_ptr);
798 num_faces++;
799 assoc = (AsscEntry*)(num_faces_ptr + 1);
800 TRACE("num faces %04x\n", num_faces);
801 for(face = 0; face < num_faces; face++, assoc++)
803 Handle sfnt;
804 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
805 unsigned short size, font_id;
806 char *output;
808 size = GET_BE_WORD(assoc->fontSize);
809 font_id = GET_BE_WORD(assoc->fontID);
810 if(size != 0)
812 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
813 continue;
816 TRACE("trying to load sfnt id %04x\n", font_id);
817 sfnt = GetResource(sfnt_res, font_id);
818 if(!sfnt)
820 TRACE("can't get sfnt resource %04x\n", font_id);
821 continue;
824 output = HeapAlloc(GetProcessHeap(), 0, output_len);
825 if(output)
827 int fd;
829 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
831 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
832 if(fd != -1 || errno == EEXIST)
834 if(fd != -1)
836 unsigned char *sfnt_data;
838 HLock(sfnt);
839 sfnt_data = *(unsigned char**)sfnt;
840 write(fd, sfnt_data, GetHandleSize(sfnt));
841 HUnlock(sfnt);
842 close(fd);
844 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
846 ret.max_size *= 2;
847 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
849 ret.array[ret.size++] = output;
851 else
853 WARN("unable to create %s\n", output);
854 HeapFree(GetProcessHeap(), 0, output);
857 ReleaseResource(sfnt);
859 HUnlock(fond);
860 ReleaseResource(fond);
861 idx++;
863 CloseResFile(res_ref);
865 return ret.array;
868 #endif /* HAVE_CARBON_CARBON_H */
870 static inline BOOL is_win9x(void)
872 return GetVersion() & 0x80000000;
875 This function builds an FT_Fixed from a double. It fails if the absolute
876 value of the float number is greater than 32768.
878 static inline FT_Fixed FT_FixedFromFloat(double f)
880 return f * 0x10000;
884 This function builds an FT_Fixed from a FIXED. It simply put f.value
885 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
887 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
889 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
893 static const struct list *get_face_list_from_family(const Family *family)
895 if (!list_empty(&family->faces))
896 return &family->faces;
897 else
898 return family->replacement;
901 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
903 Family *family;
904 Face *face;
905 const char *file;
906 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
907 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
909 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
910 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
912 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
914 const struct list *face_list;
915 if(face_name && strcmpiW(face_name, family->FamilyName))
916 continue;
917 face_list = get_face_list_from_family(family);
918 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
920 if (!face->file)
921 continue;
922 file = strrchr(face->file, '/');
923 if(!file)
924 file = face->file;
925 else
926 file++;
927 if(!strcasecmp(file, file_nameA))
929 HeapFree(GetProcessHeap(), 0, file_nameA);
930 return face;
934 HeapFree(GetProcessHeap(), 0, file_nameA);
935 return NULL;
938 static Family *find_family_from_name(const WCHAR *name)
940 Family *family;
942 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
944 if(!strcmpiW(family->FamilyName, name))
945 return family;
948 return NULL;
951 static Family *find_family_from_any_name(const WCHAR *name)
953 Family *family;
955 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
957 if(!strcmpiW(family->FamilyName, name))
958 return family;
959 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
960 return family;
963 return NULL;
966 static void DumpSubstList(void)
968 FontSubst *psub;
970 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
972 if(psub->from.charset != -1 || psub->to.charset != -1)
973 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
974 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
975 else
976 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
977 debugstr_w(psub->to.name));
979 return;
982 static LPWSTR strdupW(LPCWSTR p)
984 LPWSTR ret;
985 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
986 ret = HeapAlloc(GetProcessHeap(), 0, len);
987 memcpy(ret, p, len);
988 return ret;
991 static LPSTR strdupA(LPCSTR p)
993 LPSTR ret;
994 DWORD len = (strlen(p) + 1);
995 ret = HeapAlloc(GetProcessHeap(), 0, len);
996 memcpy(ret, p, len);
997 return ret;
1000 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1001 INT from_charset)
1003 FontSubst *element;
1005 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1007 if(!strcmpiW(element->from.name, from_name) &&
1008 (element->from.charset == from_charset ||
1009 element->from.charset == -1))
1010 return element;
1013 return NULL;
1016 #define ADD_FONT_SUBST_FORCE 1
1018 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1020 FontSubst *from_exist, *to_exist;
1022 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1024 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1026 list_remove(&from_exist->entry);
1027 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
1028 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
1029 HeapFree(GetProcessHeap(), 0, from_exist);
1030 from_exist = NULL;
1033 if(!from_exist)
1035 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1037 if(to_exist)
1039 HeapFree(GetProcessHeap(), 0, subst->to.name);
1040 subst->to.name = strdupW(to_exist->to.name);
1043 list_add_tail(subst_list, &subst->entry);
1045 return TRUE;
1048 HeapFree(GetProcessHeap(), 0, subst->from.name);
1049 HeapFree(GetProcessHeap(), 0, subst->to.name);
1050 HeapFree(GetProcessHeap(), 0, subst);
1051 return FALSE;
1054 static WCHAR *towstr(UINT cp, const char *str)
1056 int len;
1057 WCHAR *wstr;
1059 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1060 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1061 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1062 return wstr;
1065 static void split_subst_info(NameCs *nc, LPSTR str)
1067 CHAR *p = strrchr(str, ',');
1069 nc->charset = -1;
1070 if(p && *(p+1)) {
1071 nc->charset = strtol(p+1, NULL, 10);
1072 *p = '\0';
1074 nc->name = towstr(CP_ACP, str);
1077 static void LoadSubstList(void)
1079 FontSubst *psub;
1080 HKEY hkey;
1081 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1082 LPSTR value;
1083 LPVOID data;
1085 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1086 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1087 &hkey) == ERROR_SUCCESS) {
1089 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1090 &valuelen, &datalen, NULL, NULL);
1092 valuelen++; /* returned value doesn't include room for '\0' */
1093 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1094 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1096 dlen = datalen;
1097 vlen = valuelen;
1098 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1099 &dlen) == ERROR_SUCCESS) {
1100 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1102 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1103 split_subst_info(&psub->from, value);
1104 split_subst_info(&psub->to, data);
1106 /* Win 2000 doesn't allow mapping between different charsets
1107 or mapping of DEFAULT_CHARSET */
1108 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1109 psub->to.charset == DEFAULT_CHARSET) {
1110 HeapFree(GetProcessHeap(), 0, psub->to.name);
1111 HeapFree(GetProcessHeap(), 0, psub->from.name);
1112 HeapFree(GetProcessHeap(), 0, psub);
1113 } else {
1114 add_font_subst(&font_subst_list, psub, 0);
1116 /* reset dlen and vlen */
1117 dlen = datalen;
1118 vlen = valuelen;
1120 HeapFree(GetProcessHeap(), 0, data);
1121 HeapFree(GetProcessHeap(), 0, value);
1122 RegCloseKey(hkey);
1127 /*****************************************************************
1128 * get_name_table_entry
1130 * Supply the platform, encoding, language and name ids in req
1131 * and if the name exists the function will fill in the string
1132 * and string_len members. The string is owned by FreeType so
1133 * don't free it. Returns TRUE if the name is found else FALSE.
1135 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1137 FT_SfntName name;
1138 FT_UInt num_names, name_index;
1140 if(FT_IS_SFNT(ft_face))
1142 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1144 for(name_index = 0; name_index < num_names; name_index++)
1146 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1148 if((name.platform_id == req->platform_id) &&
1149 ((name.encoding_id == TT_MS_ID_UNICODE_CS) || (name.encoding_id == TT_MS_ID_SYMBOL_CS)) &&
1150 (name.language_id == req->language_id) &&
1151 (name.name_id == req->name_id))
1153 req->string = name.string;
1154 req->string_len = name.string_len;
1155 return TRUE;
1160 req->string = NULL;
1161 req->string_len = 0;
1162 return FALSE;
1165 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1167 WCHAR *ret = NULL;
1168 FT_SfntName name;
1170 name.platform_id = TT_PLATFORM_MICROSOFT;
1171 name.language_id = language_id;
1172 name.name_id = name_id;
1174 if(get_name_table_entry(ft_face, &name))
1176 FT_UInt i;
1178 /* String is not nul terminated and string_len is a byte length. */
1179 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1180 for(i = 0; i < name.string_len / 2; i++)
1182 WORD *tmp = (WORD *)&name.string[i * 2];
1183 ret[i] = GET_BE_WORD(*tmp);
1185 ret[i] = 0;
1186 TRACE("Got localised name %s\n", debugstr_w(ret));
1189 return ret;
1192 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1194 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1195 if (f1->scalable) return TRUE;
1196 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1197 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1200 static inline void free_face( Face *face )
1202 HeapFree( GetProcessHeap(), 0, face->file );
1203 HeapFree( GetProcessHeap(), 0, face->StyleName );
1204 HeapFree( GetProcessHeap(), 0, face->FullName );
1205 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1206 HeapFree( GetProcessHeap(), 0, face );
1209 static inline void free_family( Family *family )
1211 Face *face, *cursor2;
1213 LIST_FOR_EACH_ENTRY_SAFE( face, cursor2, &family->faces, Face, entry )
1215 list_remove( &face->entry );
1216 free_face( face );
1218 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1219 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1220 HeapFree( GetProcessHeap(), 0, family );
1223 static inline int style_order(const Face *face)
1225 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1227 case NTM_REGULAR:
1228 return 0;
1229 case NTM_BOLD:
1230 return 1;
1231 case NTM_ITALIC:
1232 return 2;
1233 case NTM_BOLD | NTM_ITALIC:
1234 return 3;
1235 default:
1236 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1237 debugstr_w(face->family->FamilyName),
1238 debugstr_w(face->StyleName),
1239 face->ntmFlags);
1240 return 9999;
1244 static BOOL insert_face_in_family_list( Face *face, Family *family )
1246 Face *cursor;
1248 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1250 if (faces_equal( face, cursor ))
1252 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1253 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1254 cursor->font_version, face->font_version);
1256 if (face->font_version <= cursor->font_version)
1258 TRACE("Original font %s is newer so skipping %s\n",
1259 debugstr_a(cursor->file), debugstr_a(face->file));
1260 return FALSE;
1262 else
1264 TRACE("Replacing original %s with %s\n",
1265 debugstr_a(cursor->file), debugstr_a(face->file));
1266 list_add_before( &cursor->entry, &face->entry );
1267 face->family = family;
1268 list_remove( &cursor->entry);
1269 free_face( cursor );
1270 return TRUE;
1273 else
1274 TRACE("Adding new %s\n", debugstr_a(face->file));
1276 if (style_order( face ) < style_order( cursor )) break;
1279 list_add_before( &cursor->entry, &face->entry );
1280 face->family = family;
1281 return TRUE;
1284 /****************************************************************
1285 * NB This function stores the ptrs to the strings to save copying.
1286 * Don't free them after calling.
1288 static Family *create_family( WCHAR *name, WCHAR *english_name )
1290 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1291 family->FamilyName = name;
1292 family->EnglishName = english_name;
1293 list_init( &family->faces );
1294 family->replacement = &family->faces;
1296 return family;
1299 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1301 DWORD type, needed;
1302 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1303 if(r != ERROR_SUCCESS) return r;
1304 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1305 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
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)
1315 DWORD needed;
1316 DWORD num_strikes, max_strike_key_len;
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 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1322 Face *face;
1323 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1324 face->cached_enum_data = NULL;
1326 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1327 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1329 face->StyleName = strdupW(face_name);
1331 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1333 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1334 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1335 face->FullName = fullName;
1337 else
1338 face->FullName = NULL;
1340 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1341 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1342 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1343 reg_load_dword(hkey_face, face_vertical_value, (DWORD*)&face->vertical);
1345 needed = sizeof(face->fs);
1346 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1348 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1350 face->scalable = TRUE;
1351 memset(&face->size, 0, sizeof(face->size));
1353 else
1355 face->scalable = FALSE;
1356 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1357 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1358 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1359 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1360 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1362 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1363 face->size.height, face->size.width, face->size.size >> 6,
1364 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1367 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1368 face->fs.fsCsb[0], face->fs.fsCsb[1],
1369 face->fs.fsUsb[0], face->fs.fsUsb[1],
1370 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1372 insert_face_in_family_list(face, family);
1374 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1377 /* do we have any bitmap strikes? */
1378 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1379 NULL, NULL, NULL, NULL);
1380 if(num_strikes != 0)
1382 WCHAR strike_name[10];
1383 DWORD strike_index = 0;
1385 needed = sizeof(strike_name) / sizeof(WCHAR);
1386 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1387 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1389 HKEY hkey_strike;
1390 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1391 load_face(hkey_strike, face_name, family);
1392 RegCloseKey(hkey_strike);
1393 needed = sizeof(strike_name) / sizeof(WCHAR);
1398 static void load_font_list_from_cache(HKEY hkey_font_cache)
1400 DWORD max_family_key_len, size;
1401 WCHAR *family_name;
1402 DWORD family_index = 0;
1403 Family *family;
1404 HKEY hkey_family;
1406 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1407 NULL, NULL, NULL, NULL);
1408 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1410 size = max_family_key_len + 1;
1411 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1412 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1414 WCHAR *english_family = NULL;
1415 DWORD face_index = 0;
1416 WCHAR *face_name;
1417 DWORD max_face_key_len;
1419 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1420 TRACE("opened family key %s\n", debugstr_w(family_name));
1421 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1423 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1424 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1427 family = create_family(strdupW(family_name), english_family);
1428 list_add_tail(&font_list, &family->entry);
1430 if(english_family)
1432 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1433 subst->from.name = strdupW(english_family);
1434 subst->from.charset = -1;
1435 subst->to.name = strdupW(family_name);
1436 subst->to.charset = -1;
1437 add_font_subst(&font_subst_list, subst, 0);
1440 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1441 NULL, NULL, NULL, NULL);
1443 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1444 size = max_face_key_len + 1;
1445 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1446 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1448 HKEY hkey_face;
1450 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1451 load_face(hkey_face, face_name, family);
1452 RegCloseKey(hkey_face);
1453 size = max_face_key_len + 1;
1455 HeapFree(GetProcessHeap(), 0, face_name);
1456 RegCloseKey(hkey_family);
1457 size = max_family_key_len + 1;
1460 HeapFree(GetProcessHeap(), 0, family_name);
1463 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1465 LONG ret;
1466 HKEY hkey_wine_fonts;
1468 /* We don't want to create the fonts key as volatile, so open this first */
1469 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1470 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1471 if(ret != ERROR_SUCCESS)
1473 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1474 return ret;
1477 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1478 KEY_ALL_ACCESS, NULL, hkey, disposition);
1479 RegCloseKey(hkey_wine_fonts);
1480 return ret;
1483 static void add_face_to_cache(Face *face)
1485 HKEY hkey_font_cache, hkey_family, hkey_face;
1486 WCHAR *face_key_name;
1488 create_font_cache_key(&hkey_font_cache, NULL);
1490 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1491 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1492 if(face->family->EnglishName)
1493 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1494 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1496 if(face->scalable)
1497 face_key_name = face->StyleName;
1498 else
1500 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1501 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1502 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1504 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1505 &hkey_face, NULL);
1506 if(!face->scalable)
1507 HeapFree(GetProcessHeap(), 0, face_key_name);
1509 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1510 if (face->FullName)
1511 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1512 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1514 reg_save_dword(hkey_face, face_index_value, face->face_index);
1515 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1516 reg_save_dword(hkey_face, face_version_value, face->font_version);
1517 reg_save_dword(hkey_face, face_vertical_value, face->vertical);
1519 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1521 if(!face->scalable)
1523 reg_save_dword(hkey_face, face_height_value, face->size.height);
1524 reg_save_dword(hkey_face, face_width_value, face->size.width);
1525 reg_save_dword(hkey_face, face_size_value, face->size.size);
1526 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1527 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1528 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1530 RegCloseKey(hkey_face);
1531 RegCloseKey(hkey_family);
1532 RegCloseKey(hkey_font_cache);
1535 static WCHAR *prepend_at(WCHAR *family)
1537 WCHAR *str;
1539 if (!family)
1540 return NULL;
1542 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1543 str[0] = '@';
1544 strcpyW(str + 1, family);
1545 HeapFree(GetProcessHeap(), 0, family);
1546 return str;
1549 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1551 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1552 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1554 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1555 if (!*name)
1557 *name = *english;
1558 *english = NULL;
1560 else if (!strcmpiW( *name, *english ))
1562 HeapFree( GetProcessHeap(), 0, *english );
1563 *english = NULL;
1566 if (vertical)
1568 *name = prepend_at( *name );
1569 *english = prepend_at( *english );
1573 static Family *get_family( FT_Face ft_face, BOOL vertical )
1575 Family *family;
1576 WCHAR *name, *english_name;
1578 get_family_names( ft_face, &name, &english_name, vertical );
1580 family = find_family_from_name( name );
1582 if (!family)
1584 family = create_family( name, english_name );
1585 list_add_tail( &font_list, &family->entry );
1587 if (english_name)
1589 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1590 subst->from.name = strdupW( english_name );
1591 subst->from.charset = -1;
1592 subst->to.name = strdupW( name );
1593 subst->to.charset = -1;
1594 add_font_subst( &font_subst_list, subst, 0 );
1597 else
1599 HeapFree( GetProcessHeap(), 0, name );
1600 HeapFree( GetProcessHeap(), 0, english_name );
1603 return family;
1606 static inline FT_Fixed get_font_version( FT_Face ft_face )
1608 FT_Fixed version = 0;
1609 TT_Header *header;
1611 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1612 if (header) version = header->Font_Revision;
1614 return version;
1617 static inline DWORD get_ntm_flags( FT_Face ft_face )
1619 DWORD flags = 0;
1620 FT_ULong table_size = 0;
1622 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1623 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1624 if (flags == 0) flags = NTM_REGULAR;
1626 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1627 flags |= NTM_PS_OPENTYPE;
1629 return flags;
1632 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1634 int internal_leading = 0;
1635 FT_WinFNT_HeaderRec winfnt_header;
1637 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1638 internal_leading = winfnt_header.internal_leading;
1640 return internal_leading;
1643 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1645 TT_OS2 *os2;
1646 FT_UInt dummy;
1647 CHARSETINFO csi;
1648 FT_WinFNT_HeaderRec winfnt_header;
1649 int i;
1651 memset( fs, 0, sizeof(*fs) );
1653 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1654 if (os2)
1656 fs->fsUsb[0] = os2->ulUnicodeRange1;
1657 fs->fsUsb[1] = os2->ulUnicodeRange2;
1658 fs->fsUsb[2] = os2->ulUnicodeRange3;
1659 fs->fsUsb[3] = os2->ulUnicodeRange4;
1661 if (os2->version == 0)
1663 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1664 fs->fsCsb[0] = FS_LATIN1;
1665 else
1666 fs->fsCsb[0] = FS_SYMBOL;
1668 else
1670 fs->fsCsb[0] = os2->ulCodePageRange1;
1671 fs->fsCsb[1] = os2->ulCodePageRange2;
1674 else
1676 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1678 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1679 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1680 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1681 *fs = csi.fs;
1685 if (fs->fsCsb[0] == 0)
1687 /* let's see if we can find any interesting cmaps */
1688 for (i = 0; i < ft_face->num_charmaps; i++)
1690 switch (ft_face->charmaps[i]->encoding)
1692 case FT_ENCODING_UNICODE:
1693 case FT_ENCODING_APPLE_ROMAN:
1694 fs->fsCsb[0] |= FS_LATIN1;
1695 break;
1696 case FT_ENCODING_MS_SYMBOL:
1697 fs->fsCsb[0] |= FS_SYMBOL;
1698 break;
1699 default:
1700 break;
1706 #define ADDFONT_EXTERNAL_FONT 0x01
1707 #define ADDFONT_FORCE_BITMAP 0x02
1708 #define ADDFONT_ADD_TO_CACHE 0x04
1710 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1711 DWORD flags, BOOL vertical )
1713 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1714 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1716 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
1717 if (!face->StyleName)
1718 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1719 if (!face->StyleName)
1721 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1724 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
1725 if (!face->FullName)
1726 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1727 if (vertical)
1728 face->FullName = prepend_at( face->FullName );
1730 if (file)
1732 face->file = strdupA( file );
1733 face->font_data_ptr = NULL;
1734 face->font_data_size = 0;
1736 else
1738 face->file = NULL;
1739 face->font_data_ptr = font_data_ptr;
1740 face->font_data_size = font_data_size;
1743 face->face_index = face_index;
1744 get_fontsig( ft_face, &face->fs );
1745 face->ntmFlags = get_ntm_flags( ft_face );
1746 face->font_version = get_font_version( ft_face );
1748 if (FT_IS_SCALABLE( ft_face ))
1750 memset( &face->size, 0, sizeof(face->size) );
1751 face->scalable = TRUE;
1753 else
1755 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1756 size->height, size->width, size->size >> 6,
1757 size->x_ppem >> 6, size->y_ppem >> 6);
1758 face->size.height = size->height;
1759 face->size.width = size->width;
1760 face->size.size = size->size;
1761 face->size.x_ppem = size->x_ppem;
1762 face->size.y_ppem = size->y_ppem;
1763 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1764 face->scalable = FALSE;
1767 face->vertical = vertical;
1768 face->external = (flags & ADDFONT_EXTERNAL_FONT) != 0;
1769 face->family = NULL;
1770 face->cached_enum_data = NULL;
1772 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1773 face->fs.fsCsb[0], face->fs.fsCsb[1],
1774 face->fs.fsUsb[0], face->fs.fsUsb[1],
1775 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1777 return face;
1780 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1781 FT_Long face_index, DWORD flags, BOOL vertical)
1783 Face *face;
1784 Family *family;
1786 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags, vertical );
1787 family = get_family( ft_face, vertical );
1788 if (!insert_face_in_family_list( face, family ))
1790 free_face( face );
1791 return;
1794 if (flags & ADDFONT_ADD_TO_CACHE)
1795 add_face_to_cache( face );
1797 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1798 debugstr_w(face->StyleName));
1801 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1802 FT_Long face_index, BOOL allow_bitmap )
1804 FT_Error err;
1805 TT_OS2 *pOS2;
1806 FT_Face ft_face;
1808 if (file)
1810 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1811 err = pFT_New_Face(library, file, face_index, &ft_face);
1813 else
1815 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1816 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1819 if (err != 0)
1821 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1822 return NULL;
1825 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1826 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1828 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1829 goto fail;
1832 if (!FT_IS_SFNT( ft_face ))
1834 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1836 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1837 goto fail;
1840 else
1842 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1843 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1844 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1846 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1847 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1848 goto fail;
1851 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1852 we don't want to load these. */
1853 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1855 FT_ULong len = 0;
1857 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1859 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1860 goto fail;
1865 if (!ft_face->family_name || !ft_face->style_name)
1867 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1868 goto fail;
1871 return ft_face;
1872 fail:
1873 pFT_Done_Face( ft_face );
1874 return NULL;
1877 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1879 FT_Face ft_face;
1880 FT_Long face_index = 0, num_faces;
1881 INT ret = 0;
1883 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1884 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1886 #ifdef HAVE_CARBON_CARBON_H
1887 if(file)
1889 char **mac_list = expand_mac_font(file);
1890 if(mac_list)
1892 BOOL had_one = FALSE;
1893 char **cursor;
1894 for(cursor = mac_list; *cursor; cursor++)
1896 had_one = TRUE;
1897 AddFontToList(*cursor, NULL, 0, flags);
1898 HeapFree(GetProcessHeap(), 0, *cursor);
1900 HeapFree(GetProcessHeap(), 0, mac_list);
1901 if(had_one)
1902 return 1;
1905 #endif /* HAVE_CARBON_CARBON_H */
1907 do {
1908 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_FORCE_BITMAP );
1909 if (!ft_face) return 0;
1911 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1913 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1914 pFT_Done_Face(ft_face);
1915 return 0;
1918 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1919 ++ret;
1921 if (FT_HAS_VERTICAL(ft_face))
1923 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1924 ++ret;
1927 num_faces = ft_face->num_faces;
1928 pFT_Done_Face(ft_face);
1929 } while(num_faces > ++face_index);
1930 return ret;
1933 static void DumpFontList(void)
1935 Family *family;
1936 Face *face;
1937 struct list *family_elem_ptr, *face_elem_ptr;
1939 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1940 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1941 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1942 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1943 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1944 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1945 if(!face->scalable)
1946 TRACE(" %d", face->size.height);
1947 TRACE("\n");
1950 return;
1953 /***********************************************************
1954 * The replacement list is a way to map an entire font
1955 * family onto another family. For example adding
1957 * [HKCU\Software\Wine\Fonts\Replacements]
1958 * "Wingdings"="Winedings"
1960 * would enumerate the Winedings font both as Winedings and
1961 * Wingdings. However if a real Wingdings font is present the
1962 * replacement does not take place.
1965 static void LoadReplaceList(void)
1967 HKEY hkey;
1968 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1969 LPWSTR value;
1970 LPVOID data;
1971 CHAR familyA[400];
1973 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1974 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1976 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1977 &valuelen, &datalen, NULL, NULL);
1979 valuelen++; /* returned value doesn't include room for '\0' */
1980 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1981 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1983 dlen = datalen;
1984 vlen = valuelen;
1985 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1986 &dlen) == ERROR_SUCCESS) {
1987 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1988 /* "NewName"="Oldname" */
1989 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1991 if(!find_family_from_any_name(value))
1993 Family * const family = find_family_from_any_name(data);
1994 if (family != NULL)
1996 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
1997 if (new_family != NULL)
1999 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
2000 new_family->FamilyName = strdupW(value);
2001 new_family->EnglishName = NULL;
2002 list_init(&new_family->faces);
2003 new_family->replacement = &family->faces;
2004 list_add_tail(&font_list, &new_family->entry);
2007 else
2009 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2012 else
2014 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2016 /* reset dlen and vlen */
2017 dlen = datalen;
2018 vlen = valuelen;
2020 HeapFree(GetProcessHeap(), 0, data);
2021 HeapFree(GetProcessHeap(), 0, value);
2022 RegCloseKey(hkey);
2026 static const WCHAR *font_links_list[] =
2028 Lucida_Sans_Unicode,
2029 Microsoft_Sans_Serif,
2030 Tahoma
2033 static const struct font_links_defaults_list
2035 /* Keyed off substitution for "MS Shell Dlg" */
2036 const WCHAR *shelldlg;
2037 /* Maximum of four substitutes, plus terminating NULL pointer */
2038 const WCHAR *substitutes[5];
2039 } font_links_defaults_list[] =
2041 /* Non East-Asian */
2042 { Tahoma, /* FIXME unverified ordering */
2043 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2045 /* Below lists are courtesy of
2046 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2048 /* Japanese */
2049 { MS_UI_Gothic,
2050 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2052 /* Chinese Simplified */
2053 { SimSun,
2054 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2056 /* Korean */
2057 { Gulim,
2058 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2060 /* Chinese Traditional */
2061 { PMingLiU,
2062 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2067 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2069 SYSTEM_LINKS *font_link;
2071 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2073 if(!strcmpiW(font_link->font_name, name))
2074 return font_link;
2077 return NULL;
2080 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2082 const WCHAR *value;
2083 int i;
2084 FontSubst *psub;
2085 Family *family;
2086 Face *face;
2087 const char *file;
2088 WCHAR *fileW;
2090 if (values)
2092 SYSTEM_LINKS *font_link;
2094 psub = get_font_subst(&font_subst_list, name, -1);
2095 /* Don't store fonts that are only substitutes for other fonts */
2096 if(psub)
2098 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2099 return;
2102 font_link = find_font_link(name);
2103 if (font_link == NULL)
2105 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2106 font_link->font_name = strdupW(name);
2107 list_init(&font_link->links);
2108 list_add_tail(&system_links, &font_link->entry);
2111 memset(&font_link->fs, 0, sizeof font_link->fs);
2112 for (i = 0; values[i] != NULL; i++)
2114 const struct list *face_list;
2115 CHILD_FONT *child_font;
2117 value = values[i];
2118 if (!strcmpiW(name,value))
2119 continue;
2120 psub = get_font_subst(&font_subst_list, value, -1);
2121 if(psub)
2122 value = psub->to.name;
2123 family = find_family_from_name(value);
2124 if (!family)
2125 continue;
2126 file = NULL;
2127 /* Use first extant filename for this Family */
2128 face_list = get_face_list_from_family(family);
2129 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2131 if (!face->file)
2132 continue;
2133 file = strrchr(face->file, '/');
2134 if (!file)
2135 file = face->file;
2136 else
2137 file++;
2138 break;
2140 if (!file)
2141 continue;
2142 fileW = towstr(CP_UNIXCP, file);
2144 face = find_face_from_filename(fileW, value);
2145 if(!face)
2147 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2148 continue;
2151 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2152 child_font->face = face;
2153 child_font->font = NULL;
2154 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2155 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2156 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2157 list_add_tail(&font_link->links, &child_font->entry);
2159 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2160 HeapFree(GetProcessHeap(), 0, fileW);
2166 /*************************************************************
2167 * init_system_links
2169 static BOOL init_system_links(void)
2171 HKEY hkey;
2172 BOOL ret = FALSE;
2173 DWORD type, max_val, max_data, val_len, data_len, index;
2174 WCHAR *value, *data;
2175 WCHAR *entry, *next;
2176 SYSTEM_LINKS *font_link, *system_font_link;
2177 CHILD_FONT *child_font;
2178 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2179 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2180 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2181 Face *face;
2182 FontSubst *psub;
2183 UINT i, j;
2185 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2187 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2188 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2189 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2190 val_len = max_val + 1;
2191 data_len = max_data;
2192 index = 0;
2193 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2195 psub = get_font_subst(&font_subst_list, value, -1);
2196 /* Don't store fonts that are only substitutes for other fonts */
2197 if(psub)
2199 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2200 goto next;
2202 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2203 font_link->font_name = strdupW(value);
2204 memset(&font_link->fs, 0, sizeof font_link->fs);
2205 list_init(&font_link->links);
2206 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2208 WCHAR *face_name;
2209 CHILD_FONT *child_font;
2211 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2213 next = entry + strlenW(entry) + 1;
2215 face_name = strchrW(entry, ',');
2216 if(face_name)
2218 *face_name++ = 0;
2219 while(isspaceW(*face_name))
2220 face_name++;
2222 psub = get_font_subst(&font_subst_list, face_name, -1);
2223 if(psub)
2224 face_name = psub->to.name;
2226 face = find_face_from_filename(entry, face_name);
2227 if(!face)
2229 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2230 continue;
2233 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2234 child_font->face = face;
2235 child_font->font = NULL;
2236 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2237 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2238 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2239 list_add_tail(&font_link->links, &child_font->entry);
2241 list_add_tail(&system_links, &font_link->entry);
2242 next:
2243 val_len = max_val + 1;
2244 data_len = max_data;
2247 HeapFree(GetProcessHeap(), 0, value);
2248 HeapFree(GetProcessHeap(), 0, data);
2249 RegCloseKey(hkey);
2253 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2254 if (!psub) {
2255 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2256 goto skip_internal;
2259 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2261 const FontSubst *psub2;
2262 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2264 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2266 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2267 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2269 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2270 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2272 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2274 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2278 skip_internal:
2280 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2281 that Tahoma has */
2283 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2284 system_font_link->font_name = strdupW(System);
2285 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2286 list_init(&system_font_link->links);
2288 face = find_face_from_filename(tahoma_ttf, Tahoma);
2289 if(face)
2291 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2292 child_font->face = face;
2293 child_font->font = NULL;
2294 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2295 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2296 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2297 list_add_tail(&system_font_link->links, &child_font->entry);
2299 font_link = find_font_link(Tahoma);
2300 if (font_link != NULL)
2302 CHILD_FONT *font_link_entry;
2303 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2305 CHILD_FONT *new_child;
2306 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2307 new_child->face = font_link_entry->face;
2308 new_child->font = NULL;
2309 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2310 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2311 list_add_tail(&system_font_link->links, &new_child->entry);
2314 list_add_tail(&system_links, &system_font_link->entry);
2315 return ret;
2318 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2320 DIR *dir;
2321 struct dirent *dent;
2322 char path[MAX_PATH];
2324 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2326 dir = opendir(dirname);
2327 if(!dir) {
2328 WARN("Can't open directory %s\n", debugstr_a(dirname));
2329 return FALSE;
2331 while((dent = readdir(dir)) != NULL) {
2332 struct stat statbuf;
2334 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2335 continue;
2337 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2339 sprintf(path, "%s/%s", dirname, dent->d_name);
2341 if(stat(path, &statbuf) == -1)
2343 WARN("Can't stat %s\n", debugstr_a(path));
2344 continue;
2346 if(S_ISDIR(statbuf.st_mode))
2347 ReadFontDir(path, external_fonts);
2348 else
2350 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2351 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2352 AddFontToList(path, NULL, 0, addfont_flags);
2355 closedir(dir);
2356 return TRUE;
2359 #ifdef SONAME_LIBFONTCONFIG
2360 static void load_fontconfig_fonts(void)
2362 void *fc_handle = NULL;
2363 FcConfig *config;
2364 FcPattern *pat;
2365 FcObjectSet *os;
2366 FcFontSet *fontset;
2367 int i, len;
2368 char *file;
2369 const char *ext;
2371 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2372 if(!fc_handle) {
2373 TRACE("Wine cannot find the fontconfig library (%s).\n",
2374 SONAME_LIBFONTCONFIG);
2375 return;
2377 #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;}
2378 LOAD_FUNCPTR(FcConfigGetCurrent);
2379 LOAD_FUNCPTR(FcFontList);
2380 LOAD_FUNCPTR(FcFontSetDestroy);
2381 LOAD_FUNCPTR(FcInit);
2382 LOAD_FUNCPTR(FcObjectSetAdd);
2383 LOAD_FUNCPTR(FcObjectSetCreate);
2384 LOAD_FUNCPTR(FcObjectSetDestroy);
2385 LOAD_FUNCPTR(FcPatternCreate);
2386 LOAD_FUNCPTR(FcPatternDestroy);
2387 LOAD_FUNCPTR(FcPatternGetBool);
2388 LOAD_FUNCPTR(FcPatternGetString);
2389 #undef LOAD_FUNCPTR
2391 if(!pFcInit()) return;
2393 config = pFcConfigGetCurrent();
2394 pat = pFcPatternCreate();
2395 os = pFcObjectSetCreate();
2396 pFcObjectSetAdd(os, FC_FILE);
2397 pFcObjectSetAdd(os, FC_SCALABLE);
2398 fontset = pFcFontList(config, pat, os);
2399 if(!fontset) return;
2400 for(i = 0; i < fontset->nfont; i++) {
2401 FcBool scalable;
2403 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2404 continue;
2405 TRACE("fontconfig: %s\n", file);
2407 /* We're just interested in OT/TT fonts for now, so this hack just
2408 picks up the scalable fonts without extensions .pf[ab] to save time
2409 loading every other font */
2411 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2413 TRACE("not scalable\n");
2414 continue;
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, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2423 pFcFontSetDestroy(fontset);
2424 pFcObjectSetDestroy(os);
2425 pFcPatternDestroy(pat);
2426 sym_not_found:
2427 return;
2430 #elif defined(HAVE_CARBON_CARBON_H)
2432 static void load_mac_font_callback(const void *value, void *context)
2434 CFStringRef pathStr = value;
2435 CFIndex len;
2436 char* path;
2438 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2439 path = HeapAlloc(GetProcessHeap(), 0, len);
2440 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2442 TRACE("font file %s\n", path);
2443 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2445 HeapFree(GetProcessHeap(), 0, path);
2448 static void load_mac_fonts(void)
2450 CFStringRef removeDupesKey;
2451 CFBooleanRef removeDupesValue;
2452 CFDictionaryRef options;
2453 CTFontCollectionRef col;
2454 CFArrayRef descs;
2455 CFMutableSetRef paths;
2456 CFIndex i;
2458 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2459 removeDupesValue = kCFBooleanTrue;
2460 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2461 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2462 col = CTFontCollectionCreateFromAvailableFonts(options);
2463 if (options) CFRelease(options);
2464 if (!col)
2466 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2467 return;
2470 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2471 CFRelease(col);
2472 if (!descs)
2474 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2475 return;
2478 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2479 if (!paths)
2481 WARN("CFSetCreateMutable failed\n");
2482 CFRelease(descs);
2483 return;
2486 for (i = 0; i < CFArrayGetCount(descs); i++)
2488 CTFontDescriptorRef desc;
2489 CTFontRef font;
2490 ATSFontRef atsFont;
2491 OSStatus status;
2492 FSRef fsref;
2493 CFURLRef url;
2494 CFStringRef ext;
2495 CFStringRef path;
2497 desc = CFArrayGetValueAtIndex(descs, i);
2499 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2500 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2501 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2502 if (!font) continue;
2504 atsFont = CTFontGetPlatformFont(font, NULL);
2505 if (!atsFont)
2507 CFRelease(font);
2508 continue;
2511 status = ATSFontGetFileReference(atsFont, &fsref);
2512 CFRelease(font);
2513 if (status != noErr) continue;
2515 url = CFURLCreateFromFSRef(NULL, &fsref);
2516 if (!url) continue;
2518 ext = CFURLCopyPathExtension(url);
2519 if (ext)
2521 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2522 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2523 CFRelease(ext);
2524 if (skip)
2526 CFRelease(url);
2527 continue;
2531 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2532 CFRelease(url);
2533 if (!path) continue;
2535 CFSetAddValue(paths, path);
2536 CFRelease(path);
2539 CFRelease(descs);
2541 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2542 CFRelease(paths);
2545 #endif
2547 static BOOL load_font_from_data_dir(LPCWSTR file)
2549 BOOL ret = FALSE;
2550 const char *data_dir = wine_get_data_dir();
2552 if (!data_dir) data_dir = wine_get_build_dir();
2554 if (data_dir)
2556 INT len;
2557 char *unix_name;
2559 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2561 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2563 strcpy(unix_name, data_dir);
2564 strcat(unix_name, "/fonts/");
2566 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2568 EnterCriticalSection( &freetype_cs );
2569 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2570 LeaveCriticalSection( &freetype_cs );
2571 HeapFree(GetProcessHeap(), 0, unix_name);
2573 return ret;
2576 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2578 static const WCHAR slashW[] = {'\\','\0'};
2579 BOOL ret = FALSE;
2580 WCHAR windowsdir[MAX_PATH];
2581 char *unixname;
2583 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2584 strcatW(windowsdir, fontsW);
2585 strcatW(windowsdir, slashW);
2586 strcatW(windowsdir, file);
2587 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2588 EnterCriticalSection( &freetype_cs );
2589 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2590 LeaveCriticalSection( &freetype_cs );
2591 HeapFree(GetProcessHeap(), 0, unixname);
2593 return ret;
2596 static void load_system_fonts(void)
2598 HKEY hkey;
2599 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2600 const WCHAR * const *value;
2601 DWORD dlen, type;
2602 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2603 char *unixname;
2605 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2606 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2607 strcatW(windowsdir, fontsW);
2608 for(value = SystemFontValues; *value; value++) {
2609 dlen = sizeof(data);
2610 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2611 type == REG_SZ) {
2612 BOOL added = FALSE;
2614 sprintfW(pathW, fmtW, windowsdir, data);
2615 if((unixname = wine_get_unix_file_name(pathW))) {
2616 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2617 HeapFree(GetProcessHeap(), 0, unixname);
2619 if (!added)
2620 load_font_from_data_dir(data);
2623 RegCloseKey(hkey);
2627 /*************************************************************
2629 * This adds registry entries for any externally loaded fonts
2630 * (fonts from fontconfig or FontDirs). It also deletes entries
2631 * of no longer existing fonts.
2634 static void update_reg_entries(void)
2636 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2637 LPWSTR valueW;
2638 DWORD len;
2639 Family *family;
2640 Face *face;
2641 struct list *family_elem_ptr, *face_elem_ptr;
2642 WCHAR *file;
2643 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2644 char *path;
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 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2670 if(!face->external) continue;
2672 if(face->FullName)
2674 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2675 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2676 strcpyW(valueW, face->FullName);
2678 else
2680 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2681 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2682 strcpyW(valueW, family->FamilyName);
2685 file = wine_get_dos_file_name(face->file);
2686 if(file)
2687 len = strlenW(file) + 1;
2688 else
2690 if((path = strrchr(face->file, '/')) == NULL)
2691 path = face->file;
2692 else
2693 path++;
2694 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2696 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2697 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2699 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2700 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2701 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2703 HeapFree(GetProcessHeap(), 0, file);
2704 HeapFree(GetProcessHeap(), 0, valueW);
2707 end:
2708 if(external_key) RegCloseKey(external_key);
2709 if(win9x_key) RegCloseKey(win9x_key);
2710 if(winnt_key) RegCloseKey(winnt_key);
2711 return;
2714 static void delete_external_font_keys(void)
2716 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2717 DWORD dlen, vlen, datalen, valuelen, i, type;
2718 LPWSTR valueW;
2719 LPVOID data;
2721 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2722 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2723 ERR("Can't create Windows font reg key\n");
2724 goto end;
2727 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2728 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2729 ERR("Can't create Windows font reg key\n");
2730 goto end;
2733 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2734 ERR("Can't create external font reg key\n");
2735 goto end;
2738 /* Delete all external fonts added last time */
2740 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2741 &valuelen, &datalen, NULL, NULL);
2742 valuelen++; /* returned value doesn't include room for '\0' */
2743 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2744 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2746 dlen = datalen * sizeof(WCHAR);
2747 vlen = valuelen;
2748 i = 0;
2749 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2750 &dlen) == ERROR_SUCCESS) {
2752 RegDeleteValueW(winnt_key, valueW);
2753 RegDeleteValueW(win9x_key, valueW);
2754 /* reset dlen and vlen */
2755 dlen = datalen;
2756 vlen = valuelen;
2758 HeapFree(GetProcessHeap(), 0, data);
2759 HeapFree(GetProcessHeap(), 0, valueW);
2761 /* Delete the old external fonts key */
2762 RegCloseKey(external_key);
2763 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2765 end:
2766 if(win9x_key) RegCloseKey(win9x_key);
2767 if(winnt_key) RegCloseKey(winnt_key);
2770 /*************************************************************
2771 * WineEngAddFontResourceEx
2774 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2776 INT ret = 0;
2778 GDI_CheckNotLock();
2780 if (ft_handle) /* do it only if we have freetype up and running */
2782 char *unixname;
2784 if(flags)
2785 FIXME("Ignoring flags %x\n", flags);
2787 if((unixname = wine_get_unix_file_name(file)))
2789 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2791 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2792 EnterCriticalSection( &freetype_cs );
2793 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2794 LeaveCriticalSection( &freetype_cs );
2795 HeapFree(GetProcessHeap(), 0, unixname);
2797 if (!ret && !strchrW(file, '\\')) {
2798 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2799 ret = load_font_from_winfonts_dir(file);
2800 if (!ret) {
2801 /* Try in datadir/fonts (or builddir/fonts),
2802 * needed for Magic the Gathering Online
2804 ret = load_font_from_data_dir(file);
2808 return ret;
2811 /*************************************************************
2812 * WineEngAddFontMemResourceEx
2815 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2817 GDI_CheckNotLock();
2819 if (ft_handle) /* do it only if we have freetype up and running */
2821 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2823 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2824 memcpy(pFontCopy, pbFont, cbFont);
2826 EnterCriticalSection( &freetype_cs );
2827 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2828 LeaveCriticalSection( &freetype_cs );
2830 if (*pcFonts == 0)
2832 TRACE("AddFontToList failed\n");
2833 HeapFree(GetProcessHeap(), 0, pFontCopy);
2834 return 0;
2836 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2837 * For now return something unique but quite random
2839 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2840 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2843 *pcFonts = 0;
2844 return 0;
2847 /*************************************************************
2848 * WineEngRemoveFontResourceEx
2851 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2853 GDI_CheckNotLock();
2854 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2855 return TRUE;
2858 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
2860 WCHAR *fullname;
2861 char *unix_name;
2862 int file_len;
2864 if (!font_file) return NULL;
2866 file_len = strlenW( font_file );
2868 if (font_path && font_path[0])
2870 int path_len = strlenW( font_path );
2871 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
2872 if (!fullname) return NULL;
2873 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
2874 fullname[path_len] = '\\';
2875 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
2877 else
2879 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
2880 if (!len) return NULL;
2881 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2882 if (!fullname) return NULL;
2883 GetFullPathNameW( font_file, len, fullname, NULL );
2886 unix_name = wine_get_unix_file_name( fullname );
2887 HeapFree( GetProcessHeap(), 0, fullname );
2888 return unix_name;
2891 #include <pshpack1.h>
2892 struct fontdir
2894 WORD num_of_resources;
2895 WORD res_id;
2896 WORD dfVersion;
2897 DWORD dfSize;
2898 CHAR dfCopyright[60];
2899 WORD dfType;
2900 WORD dfPoints;
2901 WORD dfVertRes;
2902 WORD dfHorizRes;
2903 WORD dfAscent;
2904 WORD dfInternalLeading;
2905 WORD dfExternalLeading;
2906 BYTE dfItalic;
2907 BYTE dfUnderline;
2908 BYTE dfStrikeOut;
2909 WORD dfWeight;
2910 BYTE dfCharSet;
2911 WORD dfPixWidth;
2912 WORD dfPixHeight;
2913 BYTE dfPitchAndFamily;
2914 WORD dfAvgWidth;
2915 WORD dfMaxWidth;
2916 BYTE dfFirstChar;
2917 BYTE dfLastChar;
2918 BYTE dfDefaultChar;
2919 BYTE dfBreakChar;
2920 WORD dfWidthBytes;
2921 DWORD dfDevice;
2922 DWORD dfFace;
2923 DWORD dfReserved;
2924 CHAR szFaceName[LF_FACESIZE];
2927 #include <poppack.h>
2929 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2930 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
2932 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
2934 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
2935 Face *face;
2936 Family *family;
2937 WCHAR *name, *english_name;
2938 ENUMLOGFONTEXW elf;
2939 NEWTEXTMETRICEXW ntm;
2940 DWORD type;
2942 if (!ft_face) return FALSE;
2943 face = create_face( ft_face, 0, unix_name, NULL, 0, 0, FALSE );
2944 get_family_names( ft_face, &name, &english_name, FALSE );
2945 family = create_family( name, english_name );
2946 insert_face_in_family_list( face, family );
2947 pFT_Done_Face( ft_face );
2949 GetEnumStructs( face, &elf, &ntm, &type );
2950 free_family( family );
2952 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
2954 memset( fd, 0, sizeof(*fd) );
2956 fd->num_of_resources = 1;
2957 fd->res_id = 0;
2958 fd->dfVersion = 0x200;
2959 fd->dfSize = sizeof(*fd);
2960 strcpy( fd->dfCopyright, "Wine fontdir" );
2961 fd->dfType = 0x4003; /* 0x0080 set if private */
2962 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
2963 fd->dfVertRes = 72;
2964 fd->dfHorizRes = 72;
2965 fd->dfAscent = ntm.ntmTm.tmAscent;
2966 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
2967 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
2968 fd->dfItalic = ntm.ntmTm.tmItalic;
2969 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
2970 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
2971 fd->dfWeight = ntm.ntmTm.tmWeight;
2972 fd->dfCharSet = ntm.ntmTm.tmCharSet;
2973 fd->dfPixWidth = 0;
2974 fd->dfPixHeight = ntm.ntmTm.tmHeight;
2975 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
2976 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
2977 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
2978 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
2979 fd->dfLastChar = ntm.ntmTm.tmLastChar;
2980 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
2981 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
2982 fd->dfWidthBytes = 0;
2983 fd->dfDevice = 0;
2984 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
2985 fd->dfReserved = 0;
2986 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
2988 return TRUE;
2991 #define NE_FFLAGS_LIBMODULE 0x8000
2992 #define NE_OSFLAGS_WINDOWS 0x02
2994 static const char dos_string[0x40] = "This is a TrueType resource file";
2995 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
2997 #include <pshpack2.h>
2999 struct ne_typeinfo
3001 WORD type_id;
3002 WORD count;
3003 DWORD res;
3006 struct ne_nameinfo
3008 WORD off;
3009 WORD len;
3010 WORD flags;
3011 WORD id;
3012 DWORD res;
3015 struct rsrc_tab
3017 WORD align;
3018 struct ne_typeinfo fontdir_type;
3019 struct ne_nameinfo fontdir_name;
3020 struct ne_typeinfo scalable_type;
3021 struct ne_nameinfo scalable_name;
3022 WORD end_of_rsrc;
3023 BYTE fontdir_res_name[8];
3026 #include <poppack.h>
3028 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3030 BOOL ret = FALSE;
3031 HANDLE file;
3032 DWORD size, written;
3033 BYTE *ptr, *start;
3034 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3035 char *font_fileA, *last_part, *ext;
3036 IMAGE_DOS_HEADER dos;
3037 IMAGE_OS2_HEADER ne =
3039 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3040 0, 0, 0, 0, 0, 0,
3041 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3042 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3044 struct rsrc_tab rsrc_tab =
3047 { 0x8007, 1, 0 },
3048 { 0, 0, 0x0c50, 0x2c, 0 },
3049 { 0x80cc, 1, 0 },
3050 { 0, 0, 0x0c50, 0x8001, 0 },
3052 { 7,'F','O','N','T','D','I','R'}
3055 memset( &dos, 0, sizeof(dos) );
3056 dos.e_magic = IMAGE_DOS_SIGNATURE;
3057 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3059 /* import name is last part\0, resident name is last part without extension
3060 non-resident name is "FONTRES:" + lfFaceName */
3062 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3063 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3064 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3066 last_part = strrchr( font_fileA, '\\' );
3067 if (last_part) last_part++;
3068 else last_part = font_fileA;
3069 import_name_len = strlen( last_part ) + 1;
3071 ext = strchr( last_part, '.' );
3072 if (ext) res_name_len = ext - last_part;
3073 else res_name_len = import_name_len - 1;
3075 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3077 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3078 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3079 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3080 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3081 ne.ne_cbenttab = 2;
3082 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3084 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3085 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3086 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3087 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3089 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3090 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3092 if (!ptr)
3094 HeapFree( GetProcessHeap(), 0, font_fileA );
3095 return FALSE;
3098 memcpy( ptr, &dos, sizeof(dos) );
3099 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3100 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3102 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3103 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3105 ptr = start + dos.e_lfanew + ne.ne_restab;
3106 *ptr++ = res_name_len;
3107 memcpy( ptr, last_part, res_name_len );
3109 ptr = start + dos.e_lfanew + ne.ne_imptab;
3110 *ptr++ = import_name_len;
3111 memcpy( ptr, last_part, import_name_len );
3113 ptr = start + ne.ne_nrestab;
3114 *ptr++ = non_res_name_len;
3115 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3116 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3118 ptr = start + (rsrc_tab.scalable_name.off << 4);
3119 memcpy( ptr, font_fileA, font_file_len );
3121 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3122 memcpy( ptr, fontdir, fontdir->dfSize );
3124 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3125 if (file != INVALID_HANDLE_VALUE)
3127 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3128 ret = TRUE;
3129 CloseHandle( file );
3132 HeapFree( GetProcessHeap(), 0, start );
3133 HeapFree( GetProcessHeap(), 0, font_fileA );
3135 return ret;
3138 /*************************************************************
3139 * WineEngCreateScalableFontResource
3142 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3143 LPCWSTR font_file, LPCWSTR font_path )
3145 char *unix_name = get_ttf_file_name( font_file, font_path );
3146 struct fontdir fontdir;
3147 BOOL ret = FALSE;
3149 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3150 SetLastError( ERROR_INVALID_PARAMETER );
3151 else
3153 if (hidden) fontdir.dfType |= 0x80;
3154 ret = create_fot( resource, font_file, &fontdir );
3157 HeapFree( GetProcessHeap(), 0, unix_name );
3158 return ret;
3161 static const struct nls_update_font_list
3163 UINT ansi_cp, oem_cp;
3164 const char *oem, *fixed, *system;
3165 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3166 /* these are for font substitutes */
3167 const char *shelldlg, *tmsrmn;
3168 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3169 *helv_0, *tmsrmn_0;
3170 const struct subst
3172 const char *from, *to;
3173 } arial_0, courier_new_0, times_new_roman_0;
3174 } nls_update_font_list[] =
3176 /* Latin 1 (United States) */
3177 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3178 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3179 "Tahoma","Times New Roman",
3180 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3181 { 0 }, { 0 }, { 0 }
3183 /* Latin 1 (Multilingual) */
3184 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3185 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3186 "Tahoma","Times New Roman", /* FIXME unverified */
3187 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3188 { 0 }, { 0 }, { 0 }
3190 /* Eastern Europe */
3191 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3192 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3193 "Tahoma","Times New Roman", /* FIXME unverified */
3194 "Fixedsys,238", "System,238",
3195 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3196 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3197 { "Arial CE,0", "Arial,238" },
3198 { "Courier New CE,0", "Courier New,238" },
3199 { "Times New Roman CE,0", "Times New Roman,238" }
3201 /* Cyrillic */
3202 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3203 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3204 "Tahoma","Times New Roman", /* FIXME unverified */
3205 "Fixedsys,204", "System,204",
3206 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3207 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3208 { "Arial Cyr,0", "Arial,204" },
3209 { "Courier New Cyr,0", "Courier New,204" },
3210 { "Times New Roman Cyr,0", "Times New Roman,204" }
3212 /* Greek */
3213 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3214 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3215 "Tahoma","Times New Roman", /* FIXME unverified */
3216 "Fixedsys,161", "System,161",
3217 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3218 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3219 { "Arial Greek,0", "Arial,161" },
3220 { "Courier New Greek,0", "Courier New,161" },
3221 { "Times New Roman Greek,0", "Times New Roman,161" }
3223 /* Turkish */
3224 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3225 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3226 "Tahoma","Times New Roman", /* FIXME unverified */
3227 "Fixedsys,162", "System,162",
3228 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3229 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3230 { "Arial Tur,0", "Arial,162" },
3231 { "Courier New Tur,0", "Courier New,162" },
3232 { "Times New Roman Tur,0", "Times New Roman,162" }
3234 /* Hebrew */
3235 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3236 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3237 "Tahoma","Times New Roman", /* FIXME unverified */
3238 "Fixedsys,177", "System,177",
3239 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3240 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3241 { 0 }, { 0 }, { 0 }
3243 /* Arabic */
3244 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3245 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3246 "Tahoma","Times New Roman", /* FIXME unverified */
3247 "Fixedsys,178", "System,178",
3248 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3249 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3250 { 0 }, { 0 }, { 0 }
3252 /* Baltic */
3253 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3254 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3255 "Tahoma","Times New Roman", /* FIXME unverified */
3256 "Fixedsys,186", "System,186",
3257 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3258 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3259 { "Arial Baltic,0", "Arial,186" },
3260 { "Courier New Baltic,0", "Courier New,186" },
3261 { "Times New Roman Baltic,0", "Times New Roman,186" }
3263 /* Vietnamese */
3264 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3265 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3266 "Tahoma","Times New Roman", /* FIXME unverified */
3267 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3268 { 0 }, { 0 }, { 0 }
3270 /* Thai */
3271 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3272 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3273 "Tahoma","Times New Roman", /* FIXME unverified */
3274 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3275 { 0 }, { 0 }, { 0 }
3277 /* Japanese */
3278 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3279 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3280 "MS UI Gothic","MS Serif",
3281 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3282 { 0 }, { 0 }, { 0 }
3284 /* Chinese Simplified */
3285 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3286 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3287 "SimSun", "NSimSun",
3288 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3289 { 0 }, { 0 }, { 0 }
3291 /* Korean */
3292 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3293 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3294 "Gulim", "Batang",
3295 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3296 { 0 }, { 0 }, { 0 }
3298 /* Chinese Traditional */
3299 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3300 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3301 "PMingLiU", "MingLiU",
3302 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3303 { 0 }, { 0 }, { 0 }
3307 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3309 return ( ansi_cp == 932 /* CP932 for Japanese */
3310 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3311 || ansi_cp == 949 /* CP949 for Korean */
3312 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3315 static inline HKEY create_fonts_NT_registry_key(void)
3317 HKEY hkey = 0;
3319 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3320 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3321 return hkey;
3324 static inline HKEY create_fonts_9x_registry_key(void)
3326 HKEY hkey = 0;
3328 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3329 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3330 return hkey;
3333 static inline HKEY create_config_fonts_registry_key(void)
3335 HKEY hkey = 0;
3337 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3338 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3339 return hkey;
3342 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3344 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3346 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3347 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3348 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3349 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3352 static void set_value_key(HKEY hkey, const char *name, const char *value)
3354 if (value)
3355 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3356 else if (name)
3357 RegDeleteValueA(hkey, name);
3360 static void update_font_info(void)
3362 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3363 char buf[40], cpbuf[40];
3364 DWORD len, type;
3365 HKEY hkey = 0;
3366 UINT i, ansi_cp = 0, oem_cp = 0;
3367 DWORD screen_dpi = 96, font_dpi = 0;
3368 BOOL done = FALSE;
3370 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3371 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3372 &hkey) == ERROR_SUCCESS)
3374 reg_load_dword(hkey, logpixels, &screen_dpi);
3375 RegCloseKey(hkey);
3378 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3379 return;
3381 reg_load_dword(hkey, logpixels, &font_dpi);
3383 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3384 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3385 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3386 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3387 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3389 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3390 if (is_dbcs_ansi_cp(ansi_cp))
3391 use_default_fallback = TRUE;
3393 len = sizeof(buf);
3394 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3396 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3398 RegCloseKey(hkey);
3399 return;
3401 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3402 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3404 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3405 ansi_cp, oem_cp, screen_dpi);
3407 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3408 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3409 RegCloseKey(hkey);
3411 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3413 HKEY hkey;
3415 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3416 nls_update_font_list[i].oem_cp == oem_cp)
3418 hkey = create_config_fonts_registry_key();
3419 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3420 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3421 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3422 RegCloseKey(hkey);
3424 hkey = create_fonts_NT_registry_key();
3425 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3426 RegCloseKey(hkey);
3428 hkey = create_fonts_9x_registry_key();
3429 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3430 RegCloseKey(hkey);
3432 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3434 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3435 strlen(nls_update_font_list[i].shelldlg)+1);
3436 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3437 strlen(nls_update_font_list[i].tmsrmn)+1);
3439 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3440 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3441 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3442 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3443 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3444 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3445 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3446 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3448 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3449 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3450 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3452 RegCloseKey(hkey);
3454 done = TRUE;
3456 else
3458 /* Delete the FontSubstitutes from other locales */
3459 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3461 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3462 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3463 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3464 RegCloseKey(hkey);
3468 if (!done)
3469 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3472 static BOOL init_freetype(void)
3474 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3475 if(!ft_handle) {
3476 WINE_MESSAGE(
3477 "Wine cannot find the FreeType font library. To enable Wine to\n"
3478 "use TrueType fonts please install a version of FreeType greater than\n"
3479 "or equal to 2.0.5.\n"
3480 "http://www.freetype.org\n");
3481 return FALSE;
3484 #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;}
3486 LOAD_FUNCPTR(FT_Done_Face)
3487 LOAD_FUNCPTR(FT_Get_Char_Index)
3488 LOAD_FUNCPTR(FT_Get_First_Char)
3489 LOAD_FUNCPTR(FT_Get_Module)
3490 LOAD_FUNCPTR(FT_Get_Next_Char)
3491 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3492 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3493 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3494 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3495 LOAD_FUNCPTR(FT_Init_FreeType)
3496 LOAD_FUNCPTR(FT_Library_Version)
3497 LOAD_FUNCPTR(FT_Load_Glyph)
3498 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3499 LOAD_FUNCPTR(FT_Matrix_Multiply)
3500 #ifndef FT_MULFIX_INLINED
3501 LOAD_FUNCPTR(FT_MulFix)
3502 #endif
3503 LOAD_FUNCPTR(FT_New_Face)
3504 LOAD_FUNCPTR(FT_New_Memory_Face)
3505 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3506 LOAD_FUNCPTR(FT_Outline_Transform)
3507 LOAD_FUNCPTR(FT_Outline_Translate)
3508 LOAD_FUNCPTR(FT_Render_Glyph)
3509 LOAD_FUNCPTR(FT_Select_Charmap)
3510 LOAD_FUNCPTR(FT_Set_Charmap)
3511 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3512 LOAD_FUNCPTR(FT_Vector_Transform)
3513 LOAD_FUNCPTR(FT_Vector_Unit)
3514 #undef LOAD_FUNCPTR
3515 /* Don't warn if these ones are missing */
3516 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3517 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3518 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3519 #endif
3521 if(pFT_Init_FreeType(&library) != 0) {
3522 ERR("Can't init FreeType library\n");
3523 wine_dlclose(ft_handle, NULL, 0);
3524 ft_handle = NULL;
3525 return FALSE;
3527 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3529 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3530 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3531 ((FT_Version.minor << 8) & 0x00ff00) |
3532 ((FT_Version.patch ) & 0x0000ff);
3534 font_driver = &freetype_funcs;
3535 return TRUE;
3537 sym_not_found:
3538 WINE_MESSAGE(
3539 "Wine cannot find certain functions that it needs inside the FreeType\n"
3540 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3541 "FreeType to at least version 2.1.4.\n"
3542 "http://www.freetype.org\n");
3543 wine_dlclose(ft_handle, NULL, 0);
3544 ft_handle = NULL;
3545 return FALSE;
3548 static void init_font_list(void)
3550 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3551 static const WCHAR pathW[] = {'P','a','t','h',0};
3552 HKEY hkey;
3553 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3554 WCHAR windowsdir[MAX_PATH];
3555 char *unixname;
3556 const char *data_dir;
3558 delete_external_font_keys();
3560 /* load the system bitmap fonts */
3561 load_system_fonts();
3563 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3564 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3565 strcatW(windowsdir, fontsW);
3566 if((unixname = wine_get_unix_file_name(windowsdir)))
3568 ReadFontDir(unixname, FALSE);
3569 HeapFree(GetProcessHeap(), 0, unixname);
3572 /* load the system truetype fonts */
3573 data_dir = wine_get_data_dir();
3574 if (!data_dir) data_dir = wine_get_build_dir();
3575 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3577 strcpy(unixname, data_dir);
3578 strcat(unixname, "/fonts/");
3579 ReadFontDir(unixname, TRUE);
3580 HeapFree(GetProcessHeap(), 0, unixname);
3583 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3584 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3585 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3586 will skip these. */
3587 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3588 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3589 &hkey) == ERROR_SUCCESS)
3591 LPWSTR data, valueW;
3592 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3593 &valuelen, &datalen, NULL, NULL);
3595 valuelen++; /* returned value doesn't include room for '\0' */
3596 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3597 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3598 if (valueW && data)
3600 dlen = datalen * sizeof(WCHAR);
3601 vlen = valuelen;
3602 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3603 &dlen) == ERROR_SUCCESS)
3605 if(data[0] && (data[1] == ':'))
3607 if((unixname = wine_get_unix_file_name(data)))
3609 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3610 HeapFree(GetProcessHeap(), 0, unixname);
3613 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3615 WCHAR pathW[MAX_PATH];
3616 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3617 BOOL added = FALSE;
3619 sprintfW(pathW, fmtW, windowsdir, data);
3620 if((unixname = wine_get_unix_file_name(pathW)))
3622 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3623 HeapFree(GetProcessHeap(), 0, unixname);
3625 if (!added)
3626 load_font_from_data_dir(data);
3628 /* reset dlen and vlen */
3629 dlen = datalen;
3630 vlen = valuelen;
3633 HeapFree(GetProcessHeap(), 0, data);
3634 HeapFree(GetProcessHeap(), 0, valueW);
3635 RegCloseKey(hkey);
3638 #ifdef SONAME_LIBFONTCONFIG
3639 load_fontconfig_fonts();
3640 #elif defined(HAVE_CARBON_CARBON_H)
3641 load_mac_fonts();
3642 #endif
3644 /* then look in any directories that we've specified in the config file */
3645 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3646 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3648 DWORD len;
3649 LPWSTR valueW;
3650 LPSTR valueA, ptr;
3652 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3654 len += sizeof(WCHAR);
3655 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3656 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3658 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3659 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3660 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3661 TRACE( "got font path %s\n", debugstr_a(valueA) );
3662 ptr = valueA;
3663 while (ptr)
3665 const char* home;
3666 LPSTR next = strchr( ptr, ':' );
3667 if (next) *next++ = 0;
3668 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3669 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3671 strcpy( unixname, home );
3672 strcat( unixname, ptr + 1 );
3673 ReadFontDir( unixname, TRUE );
3674 HeapFree( GetProcessHeap(), 0, unixname );
3676 else
3677 ReadFontDir( ptr, TRUE );
3678 ptr = next;
3680 HeapFree( GetProcessHeap(), 0, valueA );
3682 HeapFree( GetProcessHeap(), 0, valueW );
3684 RegCloseKey(hkey);
3688 static BOOL move_to_front(const WCHAR *name)
3690 Family *family, *cursor2;
3691 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3693 if(!strcmpiW(family->FamilyName, name))
3695 list_remove(&family->entry);
3696 list_add_head(&font_list, &family->entry);
3697 return TRUE;
3700 return FALSE;
3703 static BOOL set_default(const WCHAR **name_list)
3705 while (*name_list)
3707 if (move_to_front(*name_list)) return TRUE;
3708 name_list++;
3711 return FALSE;
3714 static void reorder_font_list(void)
3716 set_default( default_serif_list );
3717 set_default( default_fixed_list );
3718 set_default( default_sans_list );
3721 /*************************************************************
3722 * WineEngInit
3724 * Initialize FreeType library and create a list of available faces
3726 BOOL WineEngInit(void)
3728 HKEY hkey_font_cache;
3729 DWORD disposition;
3730 HANDLE font_mutex;
3732 /* update locale dependent font info in registry */
3733 update_font_info();
3735 if(!init_freetype()) return FALSE;
3737 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3739 ERR("Failed to create font mutex\n");
3740 return FALSE;
3742 WaitForSingleObject(font_mutex, INFINITE);
3744 create_font_cache_key(&hkey_font_cache, &disposition);
3746 if(disposition == REG_CREATED_NEW_KEY)
3747 init_font_list();
3748 else
3749 load_font_list_from_cache(hkey_font_cache);
3751 RegCloseKey(hkey_font_cache);
3753 reorder_font_list();
3755 DumpFontList();
3756 LoadSubstList();
3757 DumpSubstList();
3758 LoadReplaceList();
3760 if(disposition == REG_CREATED_NEW_KEY)
3761 update_reg_entries();
3763 init_system_links();
3765 ReleaseMutex(font_mutex);
3766 return TRUE;
3770 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3772 TT_OS2 *pOS2;
3773 TT_HoriHeader *pHori;
3775 LONG ppem;
3777 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3778 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3780 if(height == 0) height = 16;
3782 /* Calc. height of EM square:
3784 * For +ve lfHeight we have
3785 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3786 * Re-arranging gives:
3787 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3789 * For -ve lfHeight we have
3790 * |lfHeight| = ppem
3791 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3792 * with il = winAscent + winDescent - units_per_em]
3796 if(height > 0) {
3797 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3798 ppem = MulDiv(ft_face->units_per_EM, height,
3799 pHori->Ascender - pHori->Descender);
3800 else
3801 ppem = MulDiv(ft_face->units_per_EM, height,
3802 pOS2->usWinAscent + pOS2->usWinDescent);
3804 else
3805 ppem = -height;
3807 return ppem;
3810 static struct font_mapping *map_font_file( const char *name )
3812 struct font_mapping *mapping;
3813 struct stat st;
3814 int fd;
3816 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3817 if (fstat( fd, &st ) == -1) goto error;
3819 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3821 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3823 mapping->refcount++;
3824 close( fd );
3825 return mapping;
3828 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3829 goto error;
3831 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3832 close( fd );
3834 if (mapping->data == MAP_FAILED)
3836 HeapFree( GetProcessHeap(), 0, mapping );
3837 return NULL;
3839 mapping->refcount = 1;
3840 mapping->dev = st.st_dev;
3841 mapping->ino = st.st_ino;
3842 mapping->size = st.st_size;
3843 list_add_tail( &mappings_list, &mapping->entry );
3844 return mapping;
3846 error:
3847 close( fd );
3848 return NULL;
3851 static void unmap_font_file( struct font_mapping *mapping )
3853 if (!--mapping->refcount)
3855 list_remove( &mapping->entry );
3856 munmap( mapping->data, mapping->size );
3857 HeapFree( GetProcessHeap(), 0, mapping );
3861 static LONG load_VDMX(GdiFont*, LONG);
3863 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3865 FT_Error err;
3866 FT_Face ft_face;
3867 void *data_ptr;
3868 DWORD data_size;
3870 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3872 if (face->file)
3874 if (!(font->mapping = map_font_file( face->file )))
3876 WARN("failed to map %s\n", debugstr_a(face->file));
3877 return 0;
3879 data_ptr = font->mapping->data;
3880 data_size = font->mapping->size;
3882 else
3884 data_ptr = face->font_data_ptr;
3885 data_size = face->font_data_size;
3888 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3889 if(err) {
3890 ERR("FT_New_Face rets %d\n", err);
3891 return 0;
3894 /* set it here, as load_VDMX needs it */
3895 font->ft_face = ft_face;
3897 if(FT_IS_SCALABLE(ft_face)) {
3898 /* load the VDMX table if we have one */
3899 font->ppem = load_VDMX(font, height);
3900 if(font->ppem == 0)
3901 font->ppem = calc_ppem_for_height(ft_face, height);
3902 TRACE("height %d => ppem %d\n", height, font->ppem);
3904 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3905 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3906 } else {
3907 font->ppem = height;
3908 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3909 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3911 return ft_face;
3915 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3917 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3918 a single face with the requested charset. The idea is to check if
3919 the selected font supports the current ANSI codepage, if it does
3920 return the corresponding charset, else return the first charset */
3922 CHARSETINFO csi;
3923 int acp = GetACP(), i;
3924 DWORD fs0;
3926 *cp = acp;
3927 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3929 const SYSTEM_LINKS *font_link;
3931 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
3932 return csi.ciCharset;
3934 font_link = find_font_link(family_name);
3935 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
3936 return csi.ciCharset;
3939 for(i = 0; i < 32; i++) {
3940 fs0 = 1L << i;
3941 if(face->fs.fsCsb[0] & fs0) {
3942 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3943 *cp = csi.ciACP;
3944 return csi.ciCharset;
3946 else
3947 FIXME("TCI failing on %x\n", fs0);
3951 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3952 face->fs.fsCsb[0], face->file);
3953 *cp = acp;
3954 return DEFAULT_CHARSET;
3957 static GdiFont *alloc_font(void)
3959 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3960 ret->gmsize = 1;
3961 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3962 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3963 ret->potm = NULL;
3964 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3965 ret->total_kern_pairs = (DWORD)-1;
3966 ret->kern_pairs = NULL;
3967 list_init(&ret->hfontlist);
3968 list_init(&ret->child_fonts);
3969 return ret;
3972 static void free_font(GdiFont *font)
3974 struct list *cursor, *cursor2;
3975 DWORD i;
3977 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3979 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3980 list_remove(cursor);
3981 if(child->font)
3982 free_font(child->font);
3983 HeapFree(GetProcessHeap(), 0, child);
3986 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3988 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3989 DeleteObject(hfontlist->hfont);
3990 list_remove(&hfontlist->entry);
3991 HeapFree(GetProcessHeap(), 0, hfontlist);
3994 if (font->ft_face) pFT_Done_Face(font->ft_face);
3995 if (font->mapping) unmap_font_file( font->mapping );
3996 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3997 HeapFree(GetProcessHeap(), 0, font->potm);
3998 HeapFree(GetProcessHeap(), 0, font->name);
3999 for (i = 0; i < font->gmsize; i++)
4000 HeapFree(GetProcessHeap(),0,font->gm[i]);
4001 HeapFree(GetProcessHeap(), 0, font->gm);
4002 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4003 HeapFree(GetProcessHeap(), 0, font);
4007 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4009 FT_Face ft_face = font->ft_face;
4010 FT_ULong len;
4011 FT_Error err;
4013 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4015 if(!buf)
4016 len = 0;
4017 else
4018 len = cbData;
4020 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4022 /* make sure value of len is the value freetype says it needs */
4023 if (buf && len)
4025 FT_ULong needed = 0;
4026 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4027 if( !err && needed < len) len = needed;
4029 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4030 if (err)
4032 TRACE("Can't find table %c%c%c%c\n",
4033 /* bytes were reversed */
4034 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4035 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4036 return GDI_ERROR;
4038 return len;
4041 /*************************************************************
4042 * load_VDMX
4044 * load the vdmx entry for the specified height
4047 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4048 ( ( (FT_ULong)_x4 << 24 ) | \
4049 ( (FT_ULong)_x3 << 16 ) | \
4050 ( (FT_ULong)_x2 << 8 ) | \
4051 (FT_ULong)_x1 )
4053 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4055 typedef struct {
4056 BYTE bCharSet;
4057 BYTE xRatio;
4058 BYTE yStartRatio;
4059 BYTE yEndRatio;
4060 } Ratios;
4062 typedef struct {
4063 WORD recs;
4064 BYTE startsz;
4065 BYTE endsz;
4066 } VDMX_group;
4068 static LONG load_VDMX(GdiFont *font, LONG height)
4070 WORD hdr[3], tmp;
4071 VDMX_group group;
4072 BYTE devXRatio, devYRatio;
4073 USHORT numRecs, numRatios;
4074 DWORD result, offset = -1;
4075 LONG ppem = 0;
4076 int i;
4078 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
4080 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4081 return ppem;
4083 /* FIXME: need the real device aspect ratio */
4084 devXRatio = 1;
4085 devYRatio = 1;
4087 numRecs = GET_BE_WORD(hdr[1]);
4088 numRatios = GET_BE_WORD(hdr[2]);
4090 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4091 for(i = 0; i < numRatios; i++) {
4092 Ratios ratio;
4094 offset = (3 * 2) + (i * sizeof(Ratios));
4095 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4096 offset = -1;
4098 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4100 if((ratio.xRatio == 0 &&
4101 ratio.yStartRatio == 0 &&
4102 ratio.yEndRatio == 0) ||
4103 (devXRatio == ratio.xRatio &&
4104 devYRatio >= ratio.yStartRatio &&
4105 devYRatio <= ratio.yEndRatio))
4107 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4108 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4109 offset = GET_BE_WORD(tmp);
4110 break;
4114 if(offset == -1) {
4115 FIXME("No suitable ratio found\n");
4116 return ppem;
4119 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4120 USHORT recs;
4121 BYTE startsz, endsz;
4122 WORD *vTable;
4124 recs = GET_BE_WORD(group.recs);
4125 startsz = group.startsz;
4126 endsz = group.endsz;
4128 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4130 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4131 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4132 if(result == GDI_ERROR) {
4133 FIXME("Failed to retrieve vTable\n");
4134 goto end;
4137 if(height > 0) {
4138 for(i = 0; i < recs; i++) {
4139 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4140 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4141 ppem = GET_BE_WORD(vTable[i * 3]);
4143 if(yMax + -yMin == height) {
4144 font->yMax = yMax;
4145 font->yMin = yMin;
4146 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4147 break;
4149 if(yMax + -yMin > height) {
4150 if(--i < 0) {
4151 ppem = 0;
4152 goto end; /* failed */
4154 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4155 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4156 ppem = GET_BE_WORD(vTable[i * 3]);
4157 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4158 break;
4161 if(!font->yMax) {
4162 ppem = 0;
4163 TRACE("ppem not found for height %d\n", height);
4166 end:
4167 HeapFree(GetProcessHeap(), 0, vTable);
4170 return ppem;
4173 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4175 if(font->font_desc.hash != fd->hash) return TRUE;
4176 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4177 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4178 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4179 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4182 static void calc_hash(FONT_DESC *pfd)
4184 DWORD hash = 0, *ptr, two_chars;
4185 WORD *pwc;
4186 unsigned int i;
4188 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4189 hash ^= *ptr;
4190 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4191 hash ^= *ptr;
4192 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4193 two_chars = *ptr;
4194 pwc = (WCHAR *)&two_chars;
4195 if(!*pwc) break;
4196 *pwc = toupperW(*pwc);
4197 pwc++;
4198 *pwc = toupperW(*pwc);
4199 hash ^= two_chars;
4200 if(!*pwc) break;
4202 hash ^= !pfd->can_use_bitmap;
4203 pfd->hash = hash;
4204 return;
4207 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4209 GdiFont *ret;
4210 FONT_DESC fd;
4211 HFONTLIST *hflist;
4212 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4214 fd.lf = *plf;
4215 fd.matrix = *pmat;
4216 fd.can_use_bitmap = can_use_bitmap;
4217 calc_hash(&fd);
4219 /* try the child list */
4220 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
4221 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4222 if(!fontcmp(ret, &fd)) {
4223 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4224 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4225 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4226 if(hflist->hfont == hfont)
4227 return ret;
4232 /* try the in-use list */
4233 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
4234 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4235 if(!fontcmp(ret, &fd)) {
4236 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4237 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4238 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4239 if(hflist->hfont == hfont)
4240 return ret;
4242 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4243 hflist->hfont = hfont;
4244 list_add_head(&ret->hfontlist, &hflist->entry);
4245 return ret;
4249 /* then the unused list */
4250 font_elem_ptr = list_head(&unused_gdi_font_list);
4251 while(font_elem_ptr) {
4252 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4253 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4254 if(!fontcmp(ret, &fd)) {
4255 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4256 assert(list_empty(&ret->hfontlist));
4257 TRACE("Found %p in unused list\n", ret);
4258 list_remove(&ret->entry);
4259 list_add_head(&gdi_font_list, &ret->entry);
4260 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4261 hflist->hfont = hfont;
4262 list_add_head(&ret->hfontlist, &hflist->entry);
4263 return ret;
4266 return NULL;
4269 static void add_to_cache(GdiFont *font)
4271 static DWORD cache_num = 1;
4273 font->cache_num = cache_num++;
4274 list_add_head(&gdi_font_list, &font->entry);
4277 /*************************************************************
4278 * create_child_font_list
4280 static BOOL create_child_font_list(GdiFont *font)
4282 BOOL ret = FALSE;
4283 SYSTEM_LINKS *font_link;
4284 CHILD_FONT *font_link_entry, *new_child;
4285 FontSubst *psub;
4286 WCHAR* font_name;
4288 psub = get_font_subst(&font_subst_list, font->name, -1);
4289 font_name = psub ? psub->to.name : font->name;
4290 font_link = find_font_link(font_name);
4291 if (font_link != NULL)
4293 TRACE("found entry in system list\n");
4294 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4296 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4297 new_child->face = font_link_entry->face;
4298 new_child->font = NULL;
4299 list_add_tail(&font->child_fonts, &new_child->entry);
4300 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
4302 ret = TRUE;
4305 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4306 * Sans Serif. This is how asian windows get default fallbacks for fonts
4308 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4309 font->charset != OEM_CHARSET &&
4310 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4312 font_link = find_font_link(szDefaultFallbackLink);
4313 if (font_link != NULL)
4315 TRACE("found entry in default fallback list\n");
4316 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4318 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4319 new_child->face = font_link_entry->face;
4320 new_child->font = NULL;
4321 list_add_tail(&font->child_fonts, &new_child->entry);
4322 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
4324 ret = TRUE;
4328 return ret;
4331 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4333 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4335 if (pFT_Set_Charmap)
4337 FT_Int i;
4338 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4340 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4342 for (i = 0; i < ft_face->num_charmaps; i++)
4344 if (ft_face->charmaps[i]->encoding == encoding)
4346 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4347 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4349 switch (ft_face->charmaps[i]->platform_id)
4351 default:
4352 cmap_def = ft_face->charmaps[i];
4353 break;
4354 case 0: /* Apple Unicode */
4355 cmap0 = ft_face->charmaps[i];
4356 break;
4357 case 1: /* Macintosh */
4358 cmap1 = ft_face->charmaps[i];
4359 break;
4360 case 2: /* ISO */
4361 cmap2 = ft_face->charmaps[i];
4362 break;
4363 case 3: /* Microsoft */
4364 cmap3 = ft_face->charmaps[i];
4365 break;
4369 if (cmap3) /* prefer Microsoft cmap table */
4370 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4371 else if (cmap1)
4372 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4373 else if (cmap2)
4374 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4375 else if (cmap0)
4376 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4377 else if (cmap_def)
4378 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4380 return ft_err == FT_Err_Ok;
4383 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4387 /*************************************************************
4388 * freetype_CreateDC
4390 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4391 LPCWSTR output, const DEVMODEW *devmode )
4393 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4395 if (!physdev) return FALSE;
4396 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4397 return TRUE;
4401 /*************************************************************
4402 * freetype_DeleteDC
4404 static BOOL freetype_DeleteDC( PHYSDEV dev )
4406 struct freetype_physdev *physdev = get_freetype_dev( dev );
4407 HeapFree( GetProcessHeap(), 0, physdev );
4408 return TRUE;
4412 /*************************************************************
4413 * freetype_SelectFont
4415 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
4417 struct freetype_physdev *physdev = get_freetype_dev( dev );
4418 GdiFont *ret;
4419 Face *face, *best, *best_bitmap;
4420 Family *family, *last_resort_family;
4421 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
4422 INT height, width = 0;
4423 unsigned int score = 0, new_score;
4424 signed int diff = 0, newdiff;
4425 BOOL bd, it, can_use_bitmap, want_vertical;
4426 LOGFONTW lf;
4427 CHARSETINFO csi;
4428 HFONTLIST *hflist;
4429 FMAT2 dcmat;
4430 FontSubst *psub = NULL;
4431 DC *dc = get_dc_ptr( dev->hdc );
4432 const SYSTEM_LINKS *font_link;
4434 if (!hfont) /* notification that the font has been changed by another driver */
4436 dc->gdiFont = NULL;
4437 physdev->font = NULL;
4438 release_dc_ptr( dc );
4439 return 0;
4442 GetObjectW( hfont, sizeof(lf), &lf );
4443 lf.lfWidth = abs(lf.lfWidth);
4445 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4447 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4448 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4449 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4450 lf.lfEscapement);
4452 if(dc->GraphicsMode == GM_ADVANCED)
4454 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4455 /* Try to avoid not necessary glyph transformations */
4456 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4458 lf.lfHeight *= fabs(dcmat.eM11);
4459 lf.lfWidth *= fabs(dcmat.eM11);
4460 dcmat.eM11 = dcmat.eM22 = 1.0;
4463 else
4465 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4466 font scaling abilities. */
4467 dcmat.eM11 = dcmat.eM22 = 1.0;
4468 dcmat.eM21 = dcmat.eM12 = 0;
4469 if (dc->vport2WorldValid)
4471 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4472 lf.lfOrientation = -lf.lfOrientation;
4473 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4474 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4478 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4479 dcmat.eM21, dcmat.eM22);
4481 GDI_CheckNotLock();
4482 EnterCriticalSection( &freetype_cs );
4484 /* check the cache first */
4485 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4486 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4487 goto done;
4490 if(list_empty(&font_list)) /* No fonts installed */
4492 TRACE("No fonts installed\n");
4493 goto done;
4496 TRACE("not in cache\n");
4497 ret = alloc_font();
4499 ret->font_desc.matrix = dcmat;
4500 ret->font_desc.lf = lf;
4501 ret->font_desc.can_use_bitmap = can_use_bitmap;
4502 calc_hash(&ret->font_desc);
4503 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4504 hflist->hfont = hfont;
4505 list_add_head(&ret->hfontlist, &hflist->entry);
4507 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4508 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4509 original value lfCharSet. Note this is a special case for
4510 Symbol and doesn't happen at least for "Wingdings*" */
4512 if(!strcmpiW(lf.lfFaceName, SymbolW))
4513 lf.lfCharSet = SYMBOL_CHARSET;
4515 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4516 switch(lf.lfCharSet) {
4517 case DEFAULT_CHARSET:
4518 csi.fs.fsCsb[0] = 0;
4519 break;
4520 default:
4521 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4522 csi.fs.fsCsb[0] = 0;
4523 break;
4527 family = NULL;
4528 if(lf.lfFaceName[0] != '\0') {
4529 CHILD_FONT *font_link_entry;
4530 LPWSTR FaceName = lf.lfFaceName;
4532 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4534 if(psub) {
4535 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4536 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4537 if (psub->to.charset != -1)
4538 lf.lfCharSet = psub->to.charset;
4541 /* We want a match on name and charset or just name if
4542 charset was DEFAULT_CHARSET. If the latter then
4543 we fixup the returned charset later in get_nearest_charset
4544 where we'll either use the charset of the current ansi codepage
4545 or if that's unavailable the first charset that the font supports.
4547 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4548 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4549 if (!strcmpiW(family->FamilyName, FaceName) ||
4550 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4552 font_link = find_font_link(family->FamilyName);
4553 face_list = get_face_list_from_family(family);
4554 LIST_FOR_EACH(face_elem_ptr, face_list) {
4555 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4556 if (!(face->scalable || can_use_bitmap))
4557 continue;
4558 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4559 goto found;
4560 if (font_link != NULL &&
4561 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4562 goto found;
4563 if (!csi.fs.fsCsb[0])
4564 goto found;
4569 /* Search by full face name. */
4570 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4571 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4572 face_list = get_face_list_from_family(family);
4573 LIST_FOR_EACH(face_elem_ptr, face_list) {
4574 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4575 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4576 (face->scalable || can_use_bitmap))
4578 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4579 goto found_face;
4580 font_link = find_font_link(family->FamilyName);
4581 if (font_link != NULL &&
4582 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4583 goto found_face;
4589 * Try check the SystemLink list first for a replacement font.
4590 * We may find good replacements there.
4592 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4594 if(!strcmpiW(font_link->font_name, FaceName) ||
4595 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4597 TRACE("found entry in system list\n");
4598 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4600 const SYSTEM_LINKS *links;
4602 face = font_link_entry->face;
4603 if (!(face->scalable || can_use_bitmap))
4604 continue;
4605 family = face->family;
4606 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4607 goto found;
4608 links = find_font_link(family->FamilyName);
4609 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4610 goto found;
4616 psub = NULL; /* substitution is no more relevant */
4618 /* If requested charset was DEFAULT_CHARSET then try using charset
4619 corresponding to the current ansi codepage */
4620 if (!csi.fs.fsCsb[0])
4622 INT acp = GetACP();
4623 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4624 FIXME("TCI failed on codepage %d\n", acp);
4625 csi.fs.fsCsb[0] = 0;
4626 } else
4627 lf.lfCharSet = csi.ciCharset;
4630 want_vertical = (lf.lfFaceName[0] == '@');
4632 /* Face families are in the top 4 bits of lfPitchAndFamily,
4633 so mask with 0xF0 before testing */
4635 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4636 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4637 strcpyW(lf.lfFaceName, defFixed);
4638 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4639 strcpyW(lf.lfFaceName, defSerif);
4640 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4641 strcpyW(lf.lfFaceName, defSans);
4642 else
4643 strcpyW(lf.lfFaceName, defSans);
4644 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4645 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4646 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4647 font_link = find_font_link(family->FamilyName);
4648 face_list = get_face_list_from_family(family);
4649 LIST_FOR_EACH(face_elem_ptr, face_list) {
4650 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4651 if (!(face->scalable || can_use_bitmap))
4652 continue;
4653 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4654 goto found;
4655 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4656 goto found;
4661 last_resort_family = NULL;
4662 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4663 family = LIST_ENTRY(family_elem_ptr, Family, entry);
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->vertical == want_vertical &&
4669 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4670 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4671 if(face->scalable)
4672 goto found;
4673 if(can_use_bitmap && !last_resort_family)
4674 last_resort_family = family;
4679 if(last_resort_family) {
4680 family = last_resort_family;
4681 csi.fs.fsCsb[0] = 0;
4682 goto found;
4685 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4686 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4687 face_list = get_face_list_from_family(family);
4688 LIST_FOR_EACH(face_elem_ptr, face_list) {
4689 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4690 if(face->scalable && face->vertical == want_vertical) {
4691 csi.fs.fsCsb[0] = 0;
4692 WARN("just using first face for now\n");
4693 goto found;
4695 if(can_use_bitmap && !last_resort_family)
4696 last_resort_family = family;
4699 if(!last_resort_family) {
4700 FIXME("can't find a single appropriate font - bailing\n");
4701 free_font(ret);
4702 ret = NULL;
4703 goto done;
4706 WARN("could only find a bitmap font - this will probably look awful!\n");
4707 family = last_resort_family;
4708 csi.fs.fsCsb[0] = 0;
4710 found:
4711 it = lf.lfItalic ? 1 : 0;
4712 bd = lf.lfWeight > 550 ? 1 : 0;
4714 height = lf.lfHeight;
4716 face = best = best_bitmap = NULL;
4717 font_link = find_font_link(family->FamilyName);
4718 face_list = get_face_list_from_family(family);
4719 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4721 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4722 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4723 !csi.fs.fsCsb[0])
4725 BOOL italic, bold;
4727 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4728 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4729 new_score = (italic ^ it) + (bold ^ bd);
4730 if(!best || new_score <= score)
4732 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4733 italic, bold, it, bd);
4734 score = new_score;
4735 best = face;
4736 if(best->scalable && score == 0) break;
4737 if(!best->scalable)
4739 if(height > 0)
4740 newdiff = height - (signed int)(best->size.height);
4741 else
4742 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4743 if(!best_bitmap || new_score < score ||
4744 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4746 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4747 diff = newdiff;
4748 best_bitmap = best;
4749 if(score == 0 && diff == 0) break;
4755 if(best)
4756 face = best->scalable ? best : best_bitmap;
4757 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4758 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4760 found_face:
4761 height = lf.lfHeight;
4763 ret->fs = face->fs;
4765 if(csi.fs.fsCsb[0]) {
4766 ret->charset = lf.lfCharSet;
4767 ret->codepage = csi.ciACP;
4769 else
4770 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4772 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4773 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4775 ret->aveWidth = height ? lf.lfWidth : 0;
4777 if(!face->scalable) {
4778 /* Windows uses integer scaling factors for bitmap fonts */
4779 INT scale, scaled_height;
4780 GdiFont *cachedfont;
4782 /* FIXME: rotation of bitmap fonts is ignored */
4783 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4784 if (ret->aveWidth)
4785 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4786 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4787 dcmat.eM11 = dcmat.eM22 = 1.0;
4788 /* As we changed the matrix, we need to search the cache for the font again,
4789 * otherwise we might explode the cache. */
4790 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4791 TRACE("Found cached font after non-scalable matrix rescale!\n");
4792 free_font( ret );
4793 ret = cachedfont;
4794 goto done;
4796 calc_hash(&ret->font_desc);
4798 if (height != 0) height = diff;
4799 height += face->size.height;
4801 scale = (height + face->size.height - 1) / face->size.height;
4802 scaled_height = scale * face->size.height;
4803 /* Only jump to the next height if the difference <= 25% original height */
4804 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4805 /* The jump between unscaled and doubled is delayed by 1 */
4806 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4807 ret->scale_y = scale;
4809 width = face->size.x_ppem >> 6;
4810 height = face->size.y_ppem >> 6;
4812 else
4813 ret->scale_y = 1.0;
4814 TRACE("font scale y: %f\n", ret->scale_y);
4816 ret->ft_face = OpenFontFace(ret, face, width, height);
4818 if (!ret->ft_face)
4820 free_font( ret );
4821 ret = NULL;
4822 goto done;
4825 ret->ntmFlags = face->ntmFlags;
4827 if (ret->charset == SYMBOL_CHARSET &&
4828 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4829 /* No ops */
4831 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4832 /* No ops */
4834 else {
4835 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4838 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4839 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4840 ret->underline = lf.lfUnderline ? 0xff : 0;
4841 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4842 create_child_font_list(ret);
4844 if (face->vertical) /* We need to try to load the GSUB table */
4846 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4847 if (length != GDI_ERROR)
4849 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4850 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4851 TRACE("Loaded GSUB table of %i bytes\n",length);
4855 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4857 add_to_cache(ret);
4858 done:
4859 if (ret)
4861 dc->gdiFont = ret;
4862 physdev->font = ret;
4864 LeaveCriticalSection( &freetype_cs );
4865 release_dc_ptr( dc );
4866 return ret ? hfont : 0;
4869 static void dump_gdi_font_list(void)
4871 GdiFont *gdiFont;
4872 struct list *elem_ptr;
4874 TRACE("---------- gdiFont Cache ----------\n");
4875 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4876 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4877 TRACE("gdiFont=%p %s %d\n",
4878 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4881 TRACE("---------- Unused gdiFont Cache ----------\n");
4882 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4883 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4884 TRACE("gdiFont=%p %s %d\n",
4885 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4888 TRACE("---------- Child gdiFont Cache ----------\n");
4889 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4890 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4891 TRACE("gdiFont=%p %s %d\n",
4892 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4896 /*************************************************************
4897 * WineEngDestroyFontInstance
4899 * free the gdiFont associated with this handle
4902 BOOL WineEngDestroyFontInstance(HFONT handle)
4904 GdiFont *gdiFont;
4905 HFONTLIST *hflist;
4906 BOOL ret = FALSE;
4907 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4908 int i = 0;
4910 GDI_CheckNotLock();
4911 EnterCriticalSection( &freetype_cs );
4913 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4915 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4916 while(hfontlist_elem_ptr) {
4917 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4918 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4919 if(hflist->hfont == handle) {
4920 TRACE("removing child font %p from child list\n", gdiFont);
4921 list_remove(&gdiFont->entry);
4922 LeaveCriticalSection( &freetype_cs );
4923 return TRUE;
4928 TRACE("destroying hfont=%p\n", handle);
4929 if(TRACE_ON(font))
4930 dump_gdi_font_list();
4932 font_elem_ptr = list_head(&gdi_font_list);
4933 while(font_elem_ptr) {
4934 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4935 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4937 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4938 while(hfontlist_elem_ptr) {
4939 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4940 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4941 if(hflist->hfont == handle) {
4942 list_remove(&hflist->entry);
4943 HeapFree(GetProcessHeap(), 0, hflist);
4944 ret = TRUE;
4947 if(list_empty(&gdiFont->hfontlist)) {
4948 TRACE("Moving to Unused list\n");
4949 list_remove(&gdiFont->entry);
4950 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4955 font_elem_ptr = list_head(&unused_gdi_font_list);
4956 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4957 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4958 while(font_elem_ptr) {
4959 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4960 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4961 TRACE("freeing %p\n", gdiFont);
4962 list_remove(&gdiFont->entry);
4963 free_font(gdiFont);
4965 LeaveCriticalSection( &freetype_cs );
4966 return ret;
4969 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4971 HRSRC rsrc;
4972 HGLOBAL hMem;
4973 WCHAR *p;
4974 int i;
4976 id += IDS_FIRST_SCRIPT;
4977 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4978 if (!rsrc) return 0;
4979 hMem = LoadResource( gdi32_module, rsrc );
4980 if (!hMem) return 0;
4982 p = LockResource( hMem );
4983 id &= 0x000f;
4984 while (id--) p += *p + 1;
4986 i = min(LF_FACESIZE - 1, *p);
4987 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4988 buffer[i] = 0;
4989 return i;
4993 /***************************************************
4994 * create_enum_charset_list
4996 * This function creates charset enumeration list because in DEFAULT_CHARSET
4997 * case, the ANSI codepage's charset takes precedence over other charsets.
4998 * This function works as a filter other than DEFAULT_CHARSET case.
5000 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5002 CHARSETINFO csi;
5003 DWORD n = 0;
5005 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5006 csi.fs.fsCsb[0] != 0) {
5007 list->element[n].mask = csi.fs.fsCsb[0];
5008 list->element[n].charset = csi.ciCharset;
5009 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5010 n++;
5012 else { /* charset is DEFAULT_CHARSET or invalid. */
5013 INT acp, i;
5014 DWORD mask = 0;
5016 /* Set the current codepage's charset as the first element. */
5017 acp = GetACP();
5018 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5019 csi.fs.fsCsb[0] != 0) {
5020 list->element[n].mask = csi.fs.fsCsb[0];
5021 list->element[n].charset = csi.ciCharset;
5022 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5023 mask |= csi.fs.fsCsb[0];
5024 n++;
5027 /* Fill out left elements. */
5028 for (i = 0; i < 32; i++) {
5029 FONTSIGNATURE fs;
5030 fs.fsCsb[0] = 1L << i;
5031 fs.fsCsb[1] = 0;
5032 if (fs.fsCsb[0] & mask)
5033 continue; /* skip, already added. */
5034 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5035 continue; /* skip, this is an invalid fsCsb bit. */
5037 list->element[n].mask = fs.fsCsb[0];
5038 list->element[n].charset = csi.ciCharset;
5039 load_script_name( i, list->element[n].name );
5040 mask |= fs.fsCsb[0];
5041 n++;
5044 /* add catch all mask for remaining bits */
5045 if (~mask)
5047 list->element[n].mask = ~mask;
5048 list->element[n].charset = DEFAULT_CHARSET;
5049 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5050 n++;
5053 list->total = n;
5055 return n;
5058 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
5059 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5061 GdiFont *font;
5062 LONG width, height;
5064 if (face->cached_enum_data)
5066 TRACE("Cached\n");
5067 *pelf = face->cached_enum_data->elf;
5068 *pntm = face->cached_enum_data->ntm;
5069 *ptype = face->cached_enum_data->type;
5070 return;
5073 font = alloc_font();
5075 if(face->scalable) {
5076 height = 100;
5077 width = 0;
5078 } else {
5079 height = face->size.y_ppem >> 6;
5080 width = face->size.x_ppem >> 6;
5082 font->scale_y = 1.0;
5084 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5086 free_font(font);
5087 return;
5090 font->name = strdupW(face->family->FamilyName);
5091 font->ntmFlags = face->ntmFlags;
5093 if (get_outline_text_metrics(font))
5095 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5097 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5098 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5099 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5101 lstrcpynW(pelf->elfLogFont.lfFaceName,
5102 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5103 LF_FACESIZE);
5104 lstrcpynW(pelf->elfFullName,
5105 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5106 LF_FULLFACESIZE);
5107 lstrcpynW(pelf->elfStyle,
5108 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5109 LF_FACESIZE);
5111 else
5113 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5115 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5116 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5117 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5119 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
5120 if (face->FullName)
5121 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5122 else
5123 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
5124 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5127 pntm->ntmTm.ntmFlags = face->ntmFlags;
5128 pntm->ntmFontSig = face->fs;
5130 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5132 pelf->elfLogFont.lfEscapement = 0;
5133 pelf->elfLogFont.lfOrientation = 0;
5134 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5135 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5136 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5137 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5138 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5139 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5140 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5141 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5142 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5143 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5144 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5146 *ptype = 0;
5147 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5148 *ptype |= TRUETYPE_FONTTYPE;
5149 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5150 *ptype |= DEVICE_FONTTYPE;
5151 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5152 *ptype |= RASTER_FONTTYPE;
5154 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5155 if (face->cached_enum_data)
5157 face->cached_enum_data->elf = *pelf;
5158 face->cached_enum_data->ntm = *pntm;
5159 face->cached_enum_data->type = *ptype;
5162 free_font(font);
5165 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5167 const struct list *face_list, *face_elem_ptr;
5169 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5171 face_list = get_face_list_from_family(family);
5172 LIST_FOR_EACH(face_elem_ptr, face_list)
5174 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
5176 if (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName)) return TRUE;
5179 return FALSE;
5182 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5184 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5186 return (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName));
5189 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5190 FONTENUMPROCW proc, LPARAM lparam)
5192 ENUMLOGFONTEXW elf;
5193 NEWTEXTMETRICEXW ntm;
5194 DWORD type = 0;
5195 int i;
5197 GetEnumStructs(face, &elf, &ntm, &type);
5198 for(i = 0; i < list->total; i++) {
5199 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5200 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5201 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
5202 i = list->total; /* break out of loop after enumeration */
5204 else
5206 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
5207 /* use the DEFAULT_CHARSET case only if no other charset is present */
5208 if (list->element[i].charset == DEFAULT_CHARSET &&
5209 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
5210 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5211 strcpyW(elf.elfScript, list->element[i].name);
5212 if (!elf.elfScript[0])
5213 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5215 /* Font Replacement */
5216 if (family != face->family)
5218 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5219 if (face->FullName)
5220 strcpyW(elf.elfFullName, face->FullName);
5221 else
5222 strcpyW(elf.elfFullName, family->FamilyName);
5224 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5225 debugstr_w(elf.elfLogFont.lfFaceName),
5226 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5227 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5228 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5229 ntm.ntmTm.ntmFlags);
5230 /* release section before callback (FIXME) */
5231 LeaveCriticalSection( &freetype_cs );
5232 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5233 EnterCriticalSection( &freetype_cs );
5235 return TRUE;
5238 /*************************************************************
5239 * freetype_EnumFonts
5241 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5243 Family *family;
5244 Face *face;
5245 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
5246 LOGFONTW lf;
5247 struct enum_charset_list enum_charsets;
5249 if (!plf)
5251 lf.lfCharSet = DEFAULT_CHARSET;
5252 lf.lfPitchAndFamily = 0;
5253 lf.lfFaceName[0] = 0;
5254 plf = &lf;
5257 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5259 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5261 GDI_CheckNotLock();
5262 EnterCriticalSection( &freetype_cs );
5263 if(plf->lfFaceName[0]) {
5264 FontSubst *psub;
5265 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5267 if(psub) {
5268 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5269 debugstr_w(psub->to.name));
5270 lf = *plf;
5271 strcpyW(lf.lfFaceName, psub->to.name);
5272 plf = &lf;
5275 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5276 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5277 if(family_matches(family, plf)) {
5278 face_list = get_face_list_from_family(family);
5279 LIST_FOR_EACH(face_elem_ptr, face_list) {
5280 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5281 if (!face_matches(family->FamilyName, face, plf)) continue;
5282 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5286 } else {
5287 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5288 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5289 face_list = get_face_list_from_family(family);
5290 face_elem_ptr = list_head(face_list);
5291 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5292 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5295 LeaveCriticalSection( &freetype_cs );
5296 return TRUE;
5299 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5301 pt->x.value = vec->x >> 6;
5302 pt->x.fract = (vec->x & 0x3f) << 10;
5303 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5304 pt->y.value = vec->y >> 6;
5305 pt->y.fract = (vec->y & 0x3f) << 10;
5306 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5307 return;
5310 /***************************************************
5311 * According to the MSDN documentation on WideCharToMultiByte,
5312 * certain codepages cannot set the default_used parameter.
5313 * This returns TRUE if the codepage can set that parameter, false else
5314 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5316 static BOOL codepage_sets_default_used(UINT codepage)
5318 switch (codepage)
5320 case CP_UTF7:
5321 case CP_UTF8:
5322 case CP_SYMBOL:
5323 return FALSE;
5324 default:
5325 return TRUE;
5330 * GSUB Table handling functions
5333 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5335 const GSUB_CoverageFormat1* cf1;
5337 cf1 = table;
5339 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5341 int count = GET_BE_WORD(cf1->GlyphCount);
5342 int i;
5343 TRACE("Coverage Format 1, %i glyphs\n",count);
5344 for (i = 0; i < count; i++)
5345 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5346 return i;
5347 return -1;
5349 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5351 const GSUB_CoverageFormat2* cf2;
5352 int i;
5353 int count;
5354 cf2 = (const GSUB_CoverageFormat2*)cf1;
5356 count = GET_BE_WORD(cf2->RangeCount);
5357 TRACE("Coverage Format 2, %i ranges\n",count);
5358 for (i = 0; i < count; i++)
5360 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5361 return -1;
5362 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5363 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5365 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5366 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5369 return -1;
5371 else
5372 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5374 return -1;
5377 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5379 const GSUB_ScriptList *script;
5380 const GSUB_Script *deflt = NULL;
5381 int i;
5382 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5384 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5385 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5387 const GSUB_Script *scr;
5388 int offset;
5390 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5391 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5393 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5394 return scr;
5395 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5396 deflt = scr;
5398 return deflt;
5401 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5403 int i;
5404 int offset;
5405 const GSUB_LangSys *Lang;
5407 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5409 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5411 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5412 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5414 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5415 return Lang;
5417 offset = GET_BE_WORD(script->DefaultLangSys);
5418 if (offset)
5420 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5421 return Lang;
5423 return NULL;
5426 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5428 int i;
5429 const GSUB_FeatureList *feature;
5430 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5432 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5433 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5435 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5436 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5438 const GSUB_Feature *feat;
5439 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5440 return feat;
5443 return NULL;
5446 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5448 int i;
5449 int offset;
5450 const GSUB_LookupList *lookup;
5451 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5453 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5454 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5456 const GSUB_LookupTable *look;
5457 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5458 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5459 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5460 if (GET_BE_WORD(look->LookupType) != 1)
5461 FIXME("We only handle SubType 1\n");
5462 else
5464 int j;
5466 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5468 const GSUB_SingleSubstFormat1 *ssf1;
5469 offset = GET_BE_WORD(look->SubTable[j]);
5470 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5471 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5473 int offset = GET_BE_WORD(ssf1->Coverage);
5474 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5475 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5477 TRACE(" Glyph 0x%x ->",glyph);
5478 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5479 TRACE(" 0x%x\n",glyph);
5482 else
5484 const GSUB_SingleSubstFormat2 *ssf2;
5485 INT index;
5486 INT offset;
5488 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5489 offset = GET_BE_WORD(ssf1->Coverage);
5490 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5491 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5492 TRACE(" Coverage index %i\n",index);
5493 if (index != -1)
5495 TRACE(" Glyph is 0x%x ->",glyph);
5496 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5497 TRACE("0x%x\n",glyph);
5503 return glyph;
5506 static const char* get_opentype_script(const GdiFont *font)
5509 * I am not sure if this is the correct way to generate our script tag
5512 switch (font->charset)
5514 case ANSI_CHARSET: return "latn";
5515 case BALTIC_CHARSET: return "latn"; /* ?? */
5516 case CHINESEBIG5_CHARSET: return "hani";
5517 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5518 case GB2312_CHARSET: return "hani";
5519 case GREEK_CHARSET: return "grek";
5520 case HANGUL_CHARSET: return "hang";
5521 case RUSSIAN_CHARSET: return "cyrl";
5522 case SHIFTJIS_CHARSET: return "kana";
5523 case TURKISH_CHARSET: return "latn"; /* ?? */
5524 case VIETNAMESE_CHARSET: return "latn";
5525 case JOHAB_CHARSET: return "latn"; /* ?? */
5526 case ARABIC_CHARSET: return "arab";
5527 case HEBREW_CHARSET: return "hebr";
5528 case THAI_CHARSET: return "thai";
5529 default: return "latn";
5533 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5535 const GSUB_Header *header;
5536 const GSUB_Script *script;
5537 const GSUB_LangSys *language;
5538 const GSUB_Feature *feature;
5540 if (!font->GSUB_Table)
5541 return glyph;
5543 header = font->GSUB_Table;
5545 script = GSUB_get_script_table(header, get_opentype_script(font));
5546 if (!script)
5548 TRACE("Script not found\n");
5549 return glyph;
5551 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5552 if (!language)
5554 TRACE("Language not found\n");
5555 return glyph;
5557 feature = GSUB_get_feature(header, language, "vrt2");
5558 if (!feature)
5559 feature = GSUB_get_feature(header, language, "vert");
5560 if (!feature)
5562 TRACE("vrt2/vert feature not found\n");
5563 return glyph;
5565 return GSUB_apply_feature(header, feature, glyph);
5568 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5570 FT_UInt glyphId;
5572 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5573 WCHAR wc = (WCHAR)glyph;
5574 BOOL default_used;
5575 BOOL *default_used_pointer;
5576 FT_UInt ret;
5577 char buf;
5578 default_used_pointer = NULL;
5579 default_used = FALSE;
5580 if (codepage_sets_default_used(font->codepage))
5581 default_used_pointer = &default_used;
5582 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5583 ret = 0;
5584 else
5585 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5586 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5587 return ret;
5590 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5592 if (glyph < 0x100) glyph += 0xf000;
5593 /* there is a number of old pre-Unicode "broken" TTFs, which
5594 do have symbols at U+00XX instead of U+f0XX */
5595 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5596 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5598 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5600 return glyphId;
5603 /*************************************************************
5604 * freetype_GetGlyphIndices
5606 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5608 struct freetype_physdev *physdev = get_freetype_dev( dev );
5609 int i;
5610 WORD default_char;
5611 BOOL got_default = FALSE;
5613 if (!physdev->font)
5615 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5616 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5619 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5621 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5622 got_default = TRUE;
5625 GDI_CheckNotLock();
5626 EnterCriticalSection( &freetype_cs );
5628 for(i = 0; i < count; i++)
5630 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5631 if (pgi[i] == 0)
5633 if (!got_default)
5635 if (FT_IS_SFNT(physdev->font->ft_face))
5637 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5638 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5640 else
5642 TEXTMETRICW textm;
5643 get_text_metrics(physdev->font, &textm);
5644 default_char = textm.tmDefaultChar;
5646 got_default = TRUE;
5648 pgi[i] = default_char;
5651 LeaveCriticalSection( &freetype_cs );
5652 return count;
5655 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5657 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5658 return !memcmp(matrix, &identity, sizeof(FMAT2));
5661 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5663 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5664 return !memcmp(matrix, &identity, sizeof(MAT2));
5667 static inline BYTE get_max_level( UINT format )
5669 switch( format )
5671 case GGO_GRAY2_BITMAP: return 4;
5672 case GGO_GRAY4_BITMAP: return 16;
5673 case GGO_GRAY8_BITMAP: return 64;
5675 return 255;
5678 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5680 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5681 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5682 const MAT2* lpmat)
5684 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5685 FT_Face ft_face = incoming_font->ft_face;
5686 GdiFont *font = incoming_font;
5687 FT_UInt glyph_index;
5688 DWORD width, height, pitch, needed = 0;
5689 FT_Bitmap ft_bitmap;
5690 FT_Error err;
5691 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5692 FT_Angle angle = 0;
5693 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5694 double widthRatio = 1.0;
5695 FT_Matrix transMat = identityMat;
5696 FT_Matrix transMatUnrotated;
5697 BOOL needsTransform = FALSE;
5698 BOOL tategaki = (font->GSUB_Table != NULL);
5699 UINT original_index;
5701 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5702 buflen, buf, lpmat);
5704 TRACE("font transform %f %f %f %f\n",
5705 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5706 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5708 if(format & GGO_GLYPH_INDEX) {
5709 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5710 original_index = glyph;
5711 format &= ~GGO_GLYPH_INDEX;
5712 } else {
5713 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5714 ft_face = font->ft_face;
5715 original_index = glyph_index;
5718 if(format & GGO_UNHINTED) {
5719 load_flags |= FT_LOAD_NO_HINTING;
5720 format &= ~GGO_UNHINTED;
5723 /* tategaki never appears to happen to lower glyph index */
5724 if (glyph_index < TATEGAKI_LOWER_BOUND )
5725 tategaki = FALSE;
5727 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5728 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5729 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5730 font->gmsize * sizeof(GM*));
5731 } else {
5732 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5733 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5735 *lpgm = FONT_GM(font,original_index)->gm;
5736 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5737 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5738 lpgm->gmCellIncX, lpgm->gmCellIncY);
5739 return 1; /* FIXME */
5743 if (!font->gm[original_index / GM_BLOCK_SIZE])
5744 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5746 /* Scaling factor */
5747 if (font->aveWidth)
5749 TEXTMETRICW tm;
5751 get_text_metrics(font, &tm);
5753 widthRatio = (double)font->aveWidth;
5754 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5756 else
5757 widthRatio = font->scale_y;
5759 /* Scaling transform */
5760 if (widthRatio != 1.0 || font->scale_y != 1.0)
5762 FT_Matrix scaleMat;
5763 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5764 scaleMat.xy = 0;
5765 scaleMat.yx = 0;
5766 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5768 pFT_Matrix_Multiply(&scaleMat, &transMat);
5769 needsTransform = TRUE;
5772 /* Slant transform */
5773 if (font->fake_italic) {
5774 FT_Matrix slantMat;
5776 slantMat.xx = (1 << 16);
5777 slantMat.xy = ((1 << 16) >> 2);
5778 slantMat.yx = 0;
5779 slantMat.yy = (1 << 16);
5780 pFT_Matrix_Multiply(&slantMat, &transMat);
5781 needsTransform = TRUE;
5784 /* Rotation transform */
5785 transMatUnrotated = transMat;
5786 if(font->orientation && !tategaki) {
5787 FT_Matrix rotationMat;
5788 FT_Vector vecAngle;
5789 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5790 pFT_Vector_Unit(&vecAngle, angle);
5791 rotationMat.xx = vecAngle.x;
5792 rotationMat.xy = -vecAngle.y;
5793 rotationMat.yx = -rotationMat.xy;
5794 rotationMat.yy = rotationMat.xx;
5796 pFT_Matrix_Multiply(&rotationMat, &transMat);
5797 needsTransform = TRUE;
5800 /* World transform */
5801 if (!is_identity_FMAT2(&font->font_desc.matrix))
5803 FT_Matrix worldMat;
5804 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5805 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5806 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5807 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5808 pFT_Matrix_Multiply(&worldMat, &transMat);
5809 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5810 needsTransform = TRUE;
5813 /* Extra transformation specified by caller */
5814 if (!is_identity_MAT2(lpmat))
5816 FT_Matrix extraMat;
5817 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5818 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5819 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5820 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5821 pFT_Matrix_Multiply(&extraMat, &transMat);
5822 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5823 needsTransform = TRUE;
5826 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5827 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5828 format == GGO_GRAY8_BITMAP))
5830 load_flags |= FT_LOAD_NO_BITMAP;
5833 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5835 if(err) {
5836 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5837 return GDI_ERROR;
5840 if(!needsTransform) {
5841 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5842 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5843 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5845 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5846 bottom = (ft_face->glyph->metrics.horiBearingY -
5847 ft_face->glyph->metrics.height) & -64;
5848 lpgm->gmCellIncX = adv;
5849 lpgm->gmCellIncY = 0;
5850 } else {
5851 INT xc, yc;
5852 FT_Vector vec;
5854 left = right = 0;
5856 for(xc = 0; xc < 2; xc++) {
5857 for(yc = 0; yc < 2; yc++) {
5858 vec.x = (ft_face->glyph->metrics.horiBearingX +
5859 xc * ft_face->glyph->metrics.width);
5860 vec.y = ft_face->glyph->metrics.horiBearingY -
5861 yc * ft_face->glyph->metrics.height;
5862 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5863 pFT_Vector_Transform(&vec, &transMat);
5864 if(xc == 0 && yc == 0) {
5865 left = right = vec.x;
5866 top = bottom = vec.y;
5867 } else {
5868 if(vec.x < left) left = vec.x;
5869 else if(vec.x > right) right = vec.x;
5870 if(vec.y < bottom) bottom = vec.y;
5871 else if(vec.y > top) top = vec.y;
5875 left = left & -64;
5876 right = (right + 63) & -64;
5877 bottom = bottom & -64;
5878 top = (top + 63) & -64;
5880 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5881 vec.x = ft_face->glyph->metrics.horiAdvance;
5882 vec.y = 0;
5883 pFT_Vector_Transform(&vec, &transMat);
5884 lpgm->gmCellIncX = (vec.x+63) >> 6;
5885 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5887 vec.x = ft_face->glyph->metrics.horiAdvance;
5888 vec.y = 0;
5889 pFT_Vector_Transform(&vec, &transMatUnrotated);
5890 adv = (vec.x+63) >> 6;
5893 lsb = left >> 6;
5894 bbx = (right - left) >> 6;
5895 lpgm->gmBlackBoxX = (right - left) >> 6;
5896 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5897 lpgm->gmptGlyphOrigin.x = left >> 6;
5898 lpgm->gmptGlyphOrigin.y = top >> 6;
5900 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5901 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5902 lpgm->gmCellIncX, lpgm->gmCellIncY);
5904 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5905 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5907 FONT_GM(font,original_index)->gm = *lpgm;
5908 FONT_GM(font,original_index)->adv = adv;
5909 FONT_GM(font,original_index)->lsb = lsb;
5910 FONT_GM(font,original_index)->bbx = bbx;
5911 FONT_GM(font,original_index)->init = TRUE;
5914 if(format == GGO_METRICS)
5916 return 1; /* FIXME */
5919 if(ft_face->glyph->format != ft_glyph_format_outline &&
5920 (format == GGO_NATIVE || format == GGO_BEZIER))
5922 TRACE("loaded a bitmap\n");
5923 return GDI_ERROR;
5926 switch(format) {
5927 case GGO_BITMAP:
5928 width = lpgm->gmBlackBoxX;
5929 height = lpgm->gmBlackBoxY;
5930 pitch = ((width + 31) >> 5) << 2;
5931 needed = pitch * height;
5933 if(!buf || !buflen) break;
5935 switch(ft_face->glyph->format) {
5936 case ft_glyph_format_bitmap:
5938 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5939 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5940 INT h = ft_face->glyph->bitmap.rows;
5941 while(h--) {
5942 memcpy(dst, src, w);
5943 src += ft_face->glyph->bitmap.pitch;
5944 dst += pitch;
5946 break;
5949 case ft_glyph_format_outline:
5950 ft_bitmap.width = width;
5951 ft_bitmap.rows = height;
5952 ft_bitmap.pitch = pitch;
5953 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5954 ft_bitmap.buffer = buf;
5956 if(needsTransform)
5957 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5959 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5961 /* Note: FreeType will only set 'black' bits for us. */
5962 memset(buf, 0, needed);
5963 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5964 break;
5966 default:
5967 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5968 return GDI_ERROR;
5970 break;
5972 case GGO_GRAY2_BITMAP:
5973 case GGO_GRAY4_BITMAP:
5974 case GGO_GRAY8_BITMAP:
5975 case WINE_GGO_GRAY16_BITMAP:
5977 unsigned int max_level, row, col;
5978 BYTE *start, *ptr;
5980 width = lpgm->gmBlackBoxX;
5981 height = lpgm->gmBlackBoxY;
5982 pitch = (width + 3) / 4 * 4;
5983 needed = pitch * height;
5985 if(!buf || !buflen) break;
5987 max_level = get_max_level( format );
5989 switch(ft_face->glyph->format) {
5990 case ft_glyph_format_bitmap:
5992 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5993 INT h = ft_face->glyph->bitmap.rows;
5994 INT x;
5995 memset( buf, 0, needed );
5996 while(h--) {
5997 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5998 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5999 src += ft_face->glyph->bitmap.pitch;
6000 dst += pitch;
6002 return needed;
6004 case ft_glyph_format_outline:
6006 ft_bitmap.width = width;
6007 ft_bitmap.rows = height;
6008 ft_bitmap.pitch = pitch;
6009 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6010 ft_bitmap.buffer = buf;
6012 if(needsTransform)
6013 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6015 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6017 memset(ft_bitmap.buffer, 0, buflen);
6019 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6021 if (max_level != 255)
6023 for (row = 0, start = buf; row < height; row++)
6025 for (col = 0, ptr = start; col < width; col++, ptr++)
6026 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6027 start += pitch;
6030 return needed;
6033 default:
6034 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6035 return GDI_ERROR;
6037 break;
6040 case WINE_GGO_HRGB_BITMAP:
6041 case WINE_GGO_HBGR_BITMAP:
6042 case WINE_GGO_VRGB_BITMAP:
6043 case WINE_GGO_VBGR_BITMAP:
6044 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6046 switch (ft_face->glyph->format)
6048 case FT_GLYPH_FORMAT_BITMAP:
6050 BYTE *src, *dst;
6051 INT src_pitch, x;
6053 width = lpgm->gmBlackBoxX;
6054 height = lpgm->gmBlackBoxY;
6055 pitch = width * 4;
6056 needed = pitch * height;
6058 if (!buf || !buflen) break;
6060 memset(buf, 0, buflen);
6061 dst = buf;
6062 src = ft_face->glyph->bitmap.buffer;
6063 src_pitch = ft_face->glyph->bitmap.pitch;
6065 height = min( height, ft_face->glyph->bitmap.rows );
6066 while ( height-- )
6068 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6070 if ( src[x / 8] & masks[x % 8] )
6071 ((unsigned int *)dst)[x] = ~0u;
6073 src += src_pitch;
6074 dst += pitch;
6077 break;
6080 case FT_GLYPH_FORMAT_OUTLINE:
6082 unsigned int *dst;
6083 BYTE *src;
6084 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6085 INT x_shift, y_shift;
6086 BOOL rgb;
6087 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6088 FT_Render_Mode render_mode =
6089 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6090 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6092 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6094 if ( render_mode == FT_RENDER_MODE_LCD)
6096 lpgm->gmBlackBoxX += 2;
6097 lpgm->gmptGlyphOrigin.x -= 1;
6099 else
6101 lpgm->gmBlackBoxY += 2;
6102 lpgm->gmptGlyphOrigin.y += 1;
6106 width = lpgm->gmBlackBoxX;
6107 height = lpgm->gmBlackBoxY;
6108 pitch = width * 4;
6109 needed = pitch * height;
6111 if (!buf || !buflen) break;
6113 memset(buf, 0, buflen);
6114 dst = buf;
6115 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6117 if ( needsTransform )
6118 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
6120 if ( pFT_Library_SetLcdFilter )
6121 pFT_Library_SetLcdFilter( library, lcdfilter );
6122 pFT_Render_Glyph (ft_face->glyph, render_mode);
6124 src = ft_face->glyph->bitmap.buffer;
6125 src_pitch = ft_face->glyph->bitmap.pitch;
6126 src_width = ft_face->glyph->bitmap.width;
6127 src_height = ft_face->glyph->bitmap.rows;
6129 if ( render_mode == FT_RENDER_MODE_LCD)
6131 rgb_interval = 1;
6132 hmul = 3;
6133 vmul = 1;
6135 else
6137 rgb_interval = src_pitch;
6138 hmul = 1;
6139 vmul = 3;
6142 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6143 if ( x_shift < 0 ) x_shift = 0;
6144 if ( x_shift + (src_width / hmul) > width )
6145 x_shift = width - (src_width / hmul);
6147 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6148 if ( y_shift < 0 ) y_shift = 0;
6149 if ( y_shift + (src_height / vmul) > height )
6150 y_shift = height - (src_height / vmul);
6152 dst += x_shift + y_shift * ( pitch / 4 );
6153 while ( src_height )
6155 for ( x = 0; x < src_width / hmul; x++ )
6157 if ( rgb )
6159 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6160 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6161 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6162 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6164 else
6166 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6167 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6168 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6169 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6172 src += src_pitch * vmul;
6173 dst += pitch / 4;
6174 src_height -= vmul;
6177 break;
6180 default:
6181 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6182 return GDI_ERROR;
6185 break;
6187 #else
6188 return GDI_ERROR;
6189 #endif
6191 case GGO_NATIVE:
6193 int contour, point = 0, first_pt;
6194 FT_Outline *outline = &ft_face->glyph->outline;
6195 TTPOLYGONHEADER *pph;
6196 TTPOLYCURVE *ppc;
6197 DWORD pph_start, cpfx, type;
6199 if(buflen == 0) buf = NULL;
6201 if (needsTransform && buf) {
6202 pFT_Outline_Transform(outline, &transMat);
6205 for(contour = 0; contour < outline->n_contours; contour++) {
6206 pph_start = needed;
6207 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6208 first_pt = point;
6209 if(buf) {
6210 pph->dwType = TT_POLYGON_TYPE;
6211 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6213 needed += sizeof(*pph);
6214 point++;
6215 while(point <= outline->contours[contour]) {
6216 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6217 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6218 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6219 cpfx = 0;
6220 do {
6221 if(buf)
6222 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6223 cpfx++;
6224 point++;
6225 } while(point <= outline->contours[contour] &&
6226 (outline->tags[point] & FT_Curve_Tag_On) ==
6227 (outline->tags[point-1] & FT_Curve_Tag_On));
6228 /* At the end of a contour Windows adds the start point, but
6229 only for Beziers */
6230 if(point > outline->contours[contour] &&
6231 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6232 if(buf)
6233 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6234 cpfx++;
6235 } else if(point <= outline->contours[contour] &&
6236 outline->tags[point] & FT_Curve_Tag_On) {
6237 /* add closing pt for bezier */
6238 if(buf)
6239 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6240 cpfx++;
6241 point++;
6243 if(buf) {
6244 ppc->wType = type;
6245 ppc->cpfx = cpfx;
6247 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6249 if(buf)
6250 pph->cb = needed - pph_start;
6252 break;
6254 case GGO_BEZIER:
6256 /* Convert the quadratic Beziers to cubic Beziers.
6257 The parametric eqn for a cubic Bezier is, from PLRM:
6258 r(t) = at^3 + bt^2 + ct + r0
6259 with the control points:
6260 r1 = r0 + c/3
6261 r2 = r1 + (c + b)/3
6262 r3 = r0 + c + b + a
6264 A quadratic Bezier has the form:
6265 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6267 So equating powers of t leads to:
6268 r1 = 2/3 p1 + 1/3 p0
6269 r2 = 2/3 p1 + 1/3 p2
6270 and of course r0 = p0, r3 = p2
6273 int contour, point = 0, first_pt;
6274 FT_Outline *outline = &ft_face->glyph->outline;
6275 TTPOLYGONHEADER *pph;
6276 TTPOLYCURVE *ppc;
6277 DWORD pph_start, cpfx, type;
6278 FT_Vector cubic_control[4];
6279 if(buflen == 0) buf = NULL;
6281 if (needsTransform && buf) {
6282 pFT_Outline_Transform(outline, &transMat);
6285 for(contour = 0; contour < outline->n_contours; contour++) {
6286 pph_start = needed;
6287 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6288 first_pt = point;
6289 if(buf) {
6290 pph->dwType = TT_POLYGON_TYPE;
6291 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6293 needed += sizeof(*pph);
6294 point++;
6295 while(point <= outline->contours[contour]) {
6296 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6297 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6298 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6299 cpfx = 0;
6300 do {
6301 if(type == TT_PRIM_LINE) {
6302 if(buf)
6303 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6304 cpfx++;
6305 point++;
6306 } else {
6307 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6308 so cpfx = 3n */
6310 /* FIXME: Possible optimization in endpoint calculation
6311 if there are two consecutive curves */
6312 cubic_control[0] = outline->points[point-1];
6313 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6314 cubic_control[0].x += outline->points[point].x + 1;
6315 cubic_control[0].y += outline->points[point].y + 1;
6316 cubic_control[0].x >>= 1;
6317 cubic_control[0].y >>= 1;
6319 if(point+1 > outline->contours[contour])
6320 cubic_control[3] = outline->points[first_pt];
6321 else {
6322 cubic_control[3] = outline->points[point+1];
6323 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6324 cubic_control[3].x += outline->points[point].x + 1;
6325 cubic_control[3].y += outline->points[point].y + 1;
6326 cubic_control[3].x >>= 1;
6327 cubic_control[3].y >>= 1;
6330 /* r1 = 1/3 p0 + 2/3 p1
6331 r2 = 1/3 p2 + 2/3 p1 */
6332 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6333 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6334 cubic_control[2] = cubic_control[1];
6335 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6336 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6337 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6338 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6339 if(buf) {
6340 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6341 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6342 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6344 cpfx += 3;
6345 point++;
6347 } while(point <= outline->contours[contour] &&
6348 (outline->tags[point] & FT_Curve_Tag_On) ==
6349 (outline->tags[point-1] & FT_Curve_Tag_On));
6350 /* At the end of a contour Windows adds the start point,
6351 but only for Beziers and we've already done that.
6353 if(point <= outline->contours[contour] &&
6354 outline->tags[point] & FT_Curve_Tag_On) {
6355 /* This is the closing pt of a bezier, but we've already
6356 added it, so just inc point and carry on */
6357 point++;
6359 if(buf) {
6360 ppc->wType = type;
6361 ppc->cpfx = cpfx;
6363 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6365 if(buf)
6366 pph->cb = needed - pph_start;
6368 break;
6371 default:
6372 FIXME("Unsupported format %d\n", format);
6373 return GDI_ERROR;
6375 return needed;
6378 static BOOL get_bitmap_text_metrics(GdiFont *font)
6380 FT_Face ft_face = font->ft_face;
6381 FT_WinFNT_HeaderRec winfnt_header;
6382 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6383 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6384 font->potm->otmSize = size;
6386 #define TM font->potm->otmTextMetrics
6387 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6389 TM.tmHeight = winfnt_header.pixel_height;
6390 TM.tmAscent = winfnt_header.ascent;
6391 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6392 TM.tmInternalLeading = winfnt_header.internal_leading;
6393 TM.tmExternalLeading = winfnt_header.external_leading;
6394 TM.tmAveCharWidth = winfnt_header.avg_width;
6395 TM.tmMaxCharWidth = winfnt_header.max_width;
6396 TM.tmWeight = winfnt_header.weight;
6397 TM.tmOverhang = 0;
6398 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6399 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6400 TM.tmFirstChar = winfnt_header.first_char;
6401 TM.tmLastChar = winfnt_header.last_char;
6402 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6403 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6404 TM.tmItalic = winfnt_header.italic;
6405 TM.tmUnderlined = font->underline;
6406 TM.tmStruckOut = font->strikeout;
6407 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6408 TM.tmCharSet = winfnt_header.charset;
6410 else
6412 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6413 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6414 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6415 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6416 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6417 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6418 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6419 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6420 TM.tmOverhang = 0;
6421 TM.tmDigitizedAspectX = 96; /* FIXME */
6422 TM.tmDigitizedAspectY = 96; /* FIXME */
6423 TM.tmFirstChar = 1;
6424 TM.tmLastChar = 255;
6425 TM.tmDefaultChar = 32;
6426 TM.tmBreakChar = 32;
6427 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6428 TM.tmUnderlined = font->underline;
6429 TM.tmStruckOut = font->strikeout;
6430 /* NB inverted meaning of TMPF_FIXED_PITCH */
6431 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6432 TM.tmCharSet = font->charset;
6434 #undef TM
6436 return TRUE;
6440 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6442 double scale_x, scale_y;
6444 if (font->aveWidth)
6446 scale_x = (double)font->aveWidth;
6447 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6449 else
6450 scale_x = font->scale_y;
6452 scale_x *= fabs(font->font_desc.matrix.eM11);
6453 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6455 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6456 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6458 SCALE_Y(ptm->tmHeight);
6459 SCALE_Y(ptm->tmAscent);
6460 SCALE_Y(ptm->tmDescent);
6461 SCALE_Y(ptm->tmInternalLeading);
6462 SCALE_Y(ptm->tmExternalLeading);
6463 SCALE_Y(ptm->tmOverhang);
6465 SCALE_X(ptm->tmAveCharWidth);
6466 SCALE_X(ptm->tmMaxCharWidth);
6468 #undef SCALE_X
6469 #undef SCALE_Y
6472 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6474 double scale_x, scale_y;
6476 if (font->aveWidth)
6478 scale_x = (double)font->aveWidth;
6479 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6481 else
6482 scale_x = font->scale_y;
6484 scale_x *= fabs(font->font_desc.matrix.eM11);
6485 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6487 scale_font_metrics(font, &potm->otmTextMetrics);
6489 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6490 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6492 SCALE_Y(potm->otmAscent);
6493 SCALE_Y(potm->otmDescent);
6494 SCALE_Y(potm->otmLineGap);
6495 SCALE_Y(potm->otmsCapEmHeight);
6496 SCALE_Y(potm->otmsXHeight);
6497 SCALE_Y(potm->otmrcFontBox.top);
6498 SCALE_Y(potm->otmrcFontBox.bottom);
6499 SCALE_X(potm->otmrcFontBox.left);
6500 SCALE_X(potm->otmrcFontBox.right);
6501 SCALE_Y(potm->otmMacAscent);
6502 SCALE_Y(potm->otmMacDescent);
6503 SCALE_Y(potm->otmMacLineGap);
6504 SCALE_X(potm->otmptSubscriptSize.x);
6505 SCALE_Y(potm->otmptSubscriptSize.y);
6506 SCALE_X(potm->otmptSubscriptOffset.x);
6507 SCALE_Y(potm->otmptSubscriptOffset.y);
6508 SCALE_X(potm->otmptSuperscriptSize.x);
6509 SCALE_Y(potm->otmptSuperscriptSize.y);
6510 SCALE_X(potm->otmptSuperscriptOffset.x);
6511 SCALE_Y(potm->otmptSuperscriptOffset.y);
6512 SCALE_Y(potm->otmsStrikeoutSize);
6513 SCALE_Y(potm->otmsStrikeoutPosition);
6514 SCALE_Y(potm->otmsUnderscoreSize);
6515 SCALE_Y(potm->otmsUnderscorePosition);
6517 #undef SCALE_X
6518 #undef SCALE_Y
6521 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6523 if(!font->potm)
6525 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6527 /* Make sure that the font has sane width/height ratio */
6528 if (font->aveWidth)
6530 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6532 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6533 font->aveWidth = 0;
6537 *ptm = font->potm->otmTextMetrics;
6538 scale_font_metrics(font, ptm);
6539 return TRUE;
6542 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6544 int i;
6546 for(i = 0; i < ft_face->num_charmaps; i++)
6548 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6549 return TRUE;
6551 return FALSE;
6554 static BOOL get_outline_text_metrics(GdiFont *font)
6556 BOOL ret = FALSE;
6557 FT_Face ft_face = font->ft_face;
6558 UINT needed, lenfam, lensty, lenface, lenfull;
6559 TT_OS2 *pOS2;
6560 TT_HoriHeader *pHori;
6561 TT_Postscript *pPost;
6562 FT_Fixed x_scale, y_scale;
6563 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
6564 char *cp;
6565 INT ascent, descent;
6567 TRACE("font=%p\n", font);
6569 if(!FT_IS_SCALABLE(ft_face))
6570 return FALSE;
6572 needed = sizeof(*font->potm);
6574 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6575 family_nameW = strdupW(font->name);
6577 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
6578 if (!style_nameW)
6579 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6580 if (!style_nameW)
6582 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
6583 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0) * sizeof(WCHAR);
6584 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6585 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, style_nameW, lensty/sizeof(WCHAR));
6587 else
6588 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
6590 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
6591 if (!face_nameW)
6592 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6593 if (!face_nameW)
6595 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
6596 face_nameW = strdupW(font->name);
6598 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
6599 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
6601 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
6602 if (!full_nameW)
6603 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6604 if (!full_nameW)
6606 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
6607 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
6608 full_nameW = strdupW(fake_nameW);
6610 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
6612 /* These names should be read from the TT name table */
6614 /* length of otmpFamilyName */
6615 needed += lenfam;
6617 /* length of otmpFaceName */
6618 needed += lenface;
6620 /* length of otmpStyleName */
6621 needed += lensty;
6623 /* length of otmpFullName */
6624 needed += lenfull;
6627 x_scale = ft_face->size->metrics.x_scale;
6628 y_scale = ft_face->size->metrics.y_scale;
6630 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6631 if(!pOS2) {
6632 FIXME("Can't find OS/2 table - not TT font?\n");
6633 goto end;
6636 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6637 if(!pHori) {
6638 FIXME("Can't find HHEA table - not TT font?\n");
6639 goto end;
6642 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6644 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",
6645 pOS2->usWinAscent, pOS2->usWinDescent,
6646 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6647 pOS2->xAvgCharWidth,
6648 ft_face->ascender, ft_face->descender, ft_face->height,
6649 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6650 ft_face->bbox.yMax, ft_face->bbox.yMin);
6652 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6653 font->potm->otmSize = needed;
6655 #define TM font->potm->otmTextMetrics
6657 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6658 ascent = pHori->Ascender;
6659 descent = -pHori->Descender;
6660 } else {
6661 ascent = pOS2->usWinAscent;
6662 descent = pOS2->usWinDescent;
6665 font->ntmCellHeight = ascent + descent;
6666 font->ntmAvgWidth = pOS2->xAvgCharWidth;
6668 if(font->yMax) {
6669 TM.tmAscent = font->yMax;
6670 TM.tmDescent = -font->yMin;
6671 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6672 } else {
6673 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6674 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6675 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6676 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6679 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6681 /* MSDN says:
6682 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6684 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6685 ((ascent + descent) -
6686 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6688 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6689 if (TM.tmAveCharWidth == 0) {
6690 TM.tmAveCharWidth = 1;
6692 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6693 TM.tmWeight = FW_REGULAR;
6694 if (font->fake_bold)
6695 TM.tmWeight = FW_BOLD;
6696 else
6698 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6700 if (pOS2->usWeightClass > FW_MEDIUM)
6701 TM.tmWeight = pOS2->usWeightClass;
6703 else if (pOS2->usWeightClass <= FW_MEDIUM)
6704 TM.tmWeight = pOS2->usWeightClass;
6706 TM.tmOverhang = 0;
6707 TM.tmDigitizedAspectX = 96; /* FIXME */
6708 TM.tmDigitizedAspectY = 96; /* FIXME */
6709 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6710 * symbol range to 0 - f0ff
6713 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6715 TM.tmFirstChar = 0;
6716 switch(GetACP())
6718 case 1257: /* Baltic */
6719 TM.tmLastChar = 0xf8fd;
6720 break;
6721 default:
6722 TM.tmLastChar = 0xf0ff;
6724 TM.tmBreakChar = 0x20;
6725 TM.tmDefaultChar = 0x1f;
6727 else
6729 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6730 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6732 if(pOS2->usFirstCharIndex <= 1)
6733 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6734 else if (pOS2->usFirstCharIndex > 0xff)
6735 TM.tmBreakChar = 0x20;
6736 else
6737 TM.tmBreakChar = pOS2->usFirstCharIndex;
6738 TM.tmDefaultChar = TM.tmBreakChar - 1;
6740 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6741 TM.tmUnderlined = font->underline;
6742 TM.tmStruckOut = font->strikeout;
6744 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6745 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6746 (pOS2->version == 0xFFFFU ||
6747 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6748 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6749 else
6750 TM.tmPitchAndFamily = 0;
6752 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6754 case PAN_FAMILY_SCRIPT:
6755 TM.tmPitchAndFamily |= FF_SCRIPT;
6756 break;
6758 case PAN_FAMILY_DECORATIVE:
6759 TM.tmPitchAndFamily |= FF_DECORATIVE;
6760 break;
6762 case PAN_ANY:
6763 case PAN_NO_FIT:
6764 case PAN_FAMILY_TEXT_DISPLAY:
6765 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6766 /* which is clearly not what the panose spec says. */
6767 default:
6768 if(TM.tmPitchAndFamily == 0 || /* fixed */
6769 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6770 TM.tmPitchAndFamily = FF_MODERN;
6771 else
6773 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6775 case PAN_ANY:
6776 case PAN_NO_FIT:
6777 default:
6778 TM.tmPitchAndFamily |= FF_DONTCARE;
6779 break;
6781 case PAN_SERIF_COVE:
6782 case PAN_SERIF_OBTUSE_COVE:
6783 case PAN_SERIF_SQUARE_COVE:
6784 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6785 case PAN_SERIF_SQUARE:
6786 case PAN_SERIF_THIN:
6787 case PAN_SERIF_BONE:
6788 case PAN_SERIF_EXAGGERATED:
6789 case PAN_SERIF_TRIANGLE:
6790 TM.tmPitchAndFamily |= FF_ROMAN;
6791 break;
6793 case PAN_SERIF_NORMAL_SANS:
6794 case PAN_SERIF_OBTUSE_SANS:
6795 case PAN_SERIF_PERP_SANS:
6796 case PAN_SERIF_FLARED:
6797 case PAN_SERIF_ROUNDED:
6798 TM.tmPitchAndFamily |= FF_SWISS;
6799 break;
6802 break;
6805 if(FT_IS_SCALABLE(ft_face))
6806 TM.tmPitchAndFamily |= TMPF_VECTOR;
6808 if(FT_IS_SFNT(ft_face))
6810 if (font->ntmFlags & NTM_PS_OPENTYPE)
6811 TM.tmPitchAndFamily |= TMPF_DEVICE;
6812 else
6813 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6816 TM.tmCharSet = font->charset;
6818 font->potm->otmFiller = 0;
6819 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6820 font->potm->otmfsSelection = pOS2->fsSelection;
6821 font->potm->otmfsType = pOS2->fsType;
6822 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6823 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6824 font->potm->otmItalicAngle = 0; /* POST table */
6825 font->potm->otmEMSquare = ft_face->units_per_EM;
6826 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6827 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6828 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6829 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6830 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6831 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6832 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6833 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6834 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6835 font->potm->otmMacAscent = TM.tmAscent;
6836 font->potm->otmMacDescent = -TM.tmDescent;
6837 font->potm->otmMacLineGap = font->potm->otmLineGap;
6838 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6839 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6840 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6841 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6842 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6843 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6844 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6845 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6846 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6847 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6848 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6849 if(!pPost) {
6850 font->potm->otmsUnderscoreSize = 0;
6851 font->potm->otmsUnderscorePosition = 0;
6852 } else {
6853 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6854 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6856 #undef TM
6858 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6859 cp = (char*)font->potm + sizeof(*font->potm);
6860 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6861 strcpyW((WCHAR*)cp, family_nameW);
6862 cp += lenfam;
6863 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6864 strcpyW((WCHAR*)cp, style_nameW);
6865 cp += lensty;
6866 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6867 strcpyW((WCHAR*)cp, face_nameW);
6868 cp += lenface;
6869 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6870 strcpyW((WCHAR*)cp, full_nameW);
6871 ret = TRUE;
6873 end:
6874 HeapFree(GetProcessHeap(), 0, style_nameW);
6875 HeapFree(GetProcessHeap(), 0, family_nameW);
6876 HeapFree(GetProcessHeap(), 0, face_nameW);
6877 HeapFree(GetProcessHeap(), 0, full_nameW);
6878 return ret;
6881 /*************************************************************
6882 * freetype_GetGlyphOutline
6884 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6885 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6887 struct freetype_physdev *physdev = get_freetype_dev( dev );
6888 DWORD ret;
6890 if (!physdev->font)
6892 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6893 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6896 GDI_CheckNotLock();
6897 EnterCriticalSection( &freetype_cs );
6898 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6899 LeaveCriticalSection( &freetype_cs );
6900 return ret;
6903 /*************************************************************
6904 * freetype_GetTextMetrics
6906 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6908 struct freetype_physdev *physdev = get_freetype_dev( dev );
6909 BOOL ret;
6911 if (!physdev->font)
6913 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6914 return dev->funcs->pGetTextMetrics( dev, metrics );
6917 GDI_CheckNotLock();
6918 EnterCriticalSection( &freetype_cs );
6919 ret = get_text_metrics( physdev->font, metrics );
6920 LeaveCriticalSection( &freetype_cs );
6921 return ret;
6924 /*************************************************************
6925 * freetype_GetOutlineTextMetrics
6927 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6929 struct freetype_physdev *physdev = get_freetype_dev( dev );
6930 UINT ret = 0;
6932 if (!physdev->font)
6934 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6935 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6938 TRACE("font=%p\n", physdev->font);
6940 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6942 GDI_CheckNotLock();
6943 EnterCriticalSection( &freetype_cs );
6945 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6947 if(cbSize >= physdev->font->potm->otmSize)
6949 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6950 scale_outline_font_metrics(physdev->font, potm);
6952 ret = physdev->font->potm->otmSize;
6954 LeaveCriticalSection( &freetype_cs );
6955 return ret;
6958 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6960 HFONTLIST *hfontlist;
6961 child->font = alloc_font();
6962 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6963 if(!child->font->ft_face)
6965 free_font(child->font);
6966 child->font = NULL;
6967 return FALSE;
6970 child->font->font_desc = font->font_desc;
6971 child->font->ntmFlags = child->face->ntmFlags;
6972 child->font->orientation = font->orientation;
6973 child->font->scale_y = font->scale_y;
6974 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6975 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6976 child->font->name = strdupW(child->face->family->FamilyName);
6977 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6978 child->font->base_font = font;
6979 list_add_head(&child_font_list, &child->font->entry);
6980 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6981 return TRUE;
6984 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6986 FT_UInt g;
6987 CHILD_FONT *child_font;
6989 if(font->base_font)
6990 font = font->base_font;
6992 *linked_font = font;
6994 if((*glyph = get_glyph_index(font, c)))
6996 *glyph = get_GSUB_vert_glyph(font, *glyph);
6997 return TRUE;
7000 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7002 if(!child_font->font)
7003 if(!load_child_font(font, child_font))
7004 continue;
7006 if(!child_font->font->ft_face)
7007 continue;
7008 g = get_glyph_index(child_font->font, c);
7009 g = get_GSUB_vert_glyph(child_font->font, g);
7010 if(g)
7012 *glyph = g;
7013 *linked_font = child_font->font;
7014 return TRUE;
7017 return FALSE;
7020 /*************************************************************
7021 * freetype_GetCharWidth
7023 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7025 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7026 UINT c;
7027 GLYPHMETRICS gm;
7028 FT_UInt glyph_index;
7029 GdiFont *linked_font;
7030 struct freetype_physdev *physdev = get_freetype_dev( dev );
7032 if (!physdev->font)
7034 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7035 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7038 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7040 GDI_CheckNotLock();
7041 EnterCriticalSection( &freetype_cs );
7042 for(c = firstChar; c <= lastChar; c++) {
7043 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
7044 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7045 &gm, 0, NULL, &identity);
7046 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
7048 LeaveCriticalSection( &freetype_cs );
7049 return TRUE;
7052 /*************************************************************
7053 * freetype_GetCharABCWidths
7055 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7057 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7058 UINT c;
7059 GLYPHMETRICS gm;
7060 FT_UInt glyph_index;
7061 GdiFont *linked_font;
7062 struct freetype_physdev *physdev = get_freetype_dev( dev );
7064 if (!physdev->font)
7066 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7067 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7070 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7072 GDI_CheckNotLock();
7073 EnterCriticalSection( &freetype_cs );
7075 for(c = firstChar; c <= lastChar; c++) {
7076 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
7077 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7078 &gm, 0, NULL, &identity);
7079 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
7080 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
7081 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
7082 FONT_GM(linked_font,glyph_index)->bbx;
7084 LeaveCriticalSection( &freetype_cs );
7085 return TRUE;
7088 /*************************************************************
7089 * freetype_GetCharABCWidthsI
7091 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7093 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7094 UINT c;
7095 GLYPHMETRICS gm;
7096 FT_UInt glyph_index;
7097 GdiFont *linked_font;
7098 struct freetype_physdev *physdev = get_freetype_dev( dev );
7100 if (!physdev->font)
7102 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7103 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7106 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7107 return FALSE;
7109 GDI_CheckNotLock();
7110 EnterCriticalSection( &freetype_cs );
7112 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
7113 if (!pgi)
7114 for(c = firstChar; c < firstChar+count; c++) {
7115 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
7116 &gm, 0, NULL, &identity);
7117 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
7118 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
7119 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
7120 - FONT_GM(linked_font,c)->bbx;
7122 else
7123 for(c = 0; c < count; c++) {
7124 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
7125 &gm, 0, NULL, &identity);
7126 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
7127 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
7128 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
7129 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
7132 LeaveCriticalSection( &freetype_cs );
7133 return TRUE;
7136 /*************************************************************
7137 * freetype_GetTextExtentExPoint
7139 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
7140 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
7142 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7143 INT idx;
7144 INT nfit = 0, ext;
7145 GLYPHMETRICS gm;
7146 TEXTMETRICW tm;
7147 FT_UInt glyph_index;
7148 GdiFont *linked_font;
7149 struct freetype_physdev *physdev = get_freetype_dev( dev );
7151 if (!physdev->font)
7153 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7154 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
7157 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
7159 GDI_CheckNotLock();
7160 EnterCriticalSection( &freetype_cs );
7162 size->cx = 0;
7163 get_text_metrics( physdev->font, &tm );
7164 size->cy = tm.tmHeight;
7166 for(idx = 0; idx < count; idx++) {
7167 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
7168 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7169 &gm, 0, NULL, &identity);
7170 size->cx += FONT_GM(linked_font,glyph_index)->adv;
7171 ext = size->cx;
7172 if (! pnfit || ext <= max_ext) {
7173 ++nfit;
7174 if (dxs)
7175 dxs[idx] = ext;
7179 if (pnfit)
7180 *pnfit = nfit;
7182 LeaveCriticalSection( &freetype_cs );
7183 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7184 return TRUE;
7187 /*************************************************************
7188 * freetype_GetTextExtentExPointI
7190 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
7191 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
7193 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7194 INT idx;
7195 INT nfit = 0, ext;
7196 GLYPHMETRICS gm;
7197 TEXTMETRICW tm;
7198 struct freetype_physdev *physdev = get_freetype_dev( dev );
7200 if (!physdev->font)
7202 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7203 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
7206 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
7208 GDI_CheckNotLock();
7209 EnterCriticalSection( &freetype_cs );
7211 size->cx = 0;
7212 get_text_metrics(physdev->font, &tm);
7213 size->cy = tm.tmHeight;
7215 for(idx = 0; idx < count; idx++) {
7216 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
7217 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
7218 ext = size->cx;
7219 if (! pnfit || ext <= max_ext) {
7220 ++nfit;
7221 if (dxs)
7222 dxs[idx] = ext;
7226 if (pnfit)
7227 *pnfit = nfit;
7229 LeaveCriticalSection( &freetype_cs );
7230 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7231 return TRUE;
7234 /*************************************************************
7235 * freetype_GetFontData
7237 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7239 struct freetype_physdev *physdev = get_freetype_dev( dev );
7241 if (!physdev->font)
7243 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7244 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7247 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7248 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7249 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7251 return get_font_data( physdev->font, table, offset, buf, cbData );
7254 /*************************************************************
7255 * freetype_GetTextFace
7257 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7259 INT n;
7260 struct freetype_physdev *physdev = get_freetype_dev( dev );
7262 if (!physdev->font)
7264 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7265 return dev->funcs->pGetTextFace( dev, count, str );
7268 n = strlenW(physdev->font->name) + 1;
7269 if (str)
7271 lstrcpynW(str, physdev->font->name, count);
7272 n = min(count, n);
7274 return n;
7277 /*************************************************************
7278 * freetype_GetTextCharsetInfo
7280 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7282 struct freetype_physdev *physdev = get_freetype_dev( dev );
7284 if (!physdev->font)
7286 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7287 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7289 if (fs) *fs = physdev->font->fs;
7290 return physdev->font->charset;
7293 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7295 GdiFont *font = dc->gdiFont, *linked_font;
7296 struct list *first_hfont;
7297 BOOL ret;
7299 GDI_CheckNotLock();
7300 EnterCriticalSection( &freetype_cs );
7301 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
7302 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
7303 if(font == linked_font)
7304 *new_hfont = dc->hFont;
7305 else
7307 first_hfont = list_head(&linked_font->hfontlist);
7308 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
7310 LeaveCriticalSection( &freetype_cs );
7311 return ret;
7314 /* Retrieve a list of supported Unicode ranges for a given font.
7315 * Can be called with NULL gs to calculate the buffer size. Returns
7316 * the number of ranges found.
7318 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7320 DWORD num_ranges = 0;
7322 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7324 FT_UInt glyph_code;
7325 FT_ULong char_code, char_code_prev;
7327 glyph_code = 0;
7328 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7330 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7331 face->num_glyphs, glyph_code, char_code);
7333 if (!glyph_code) return 0;
7335 if (gs)
7337 gs->ranges[0].wcLow = (USHORT)char_code;
7338 gs->ranges[0].cGlyphs = 0;
7339 gs->cGlyphsSupported = 0;
7342 num_ranges = 1;
7343 while (glyph_code)
7345 if (char_code < char_code_prev)
7347 ERR("expected increasing char code from FT_Get_Next_Char\n");
7348 return 0;
7350 if (char_code - char_code_prev > 1)
7352 num_ranges++;
7353 if (gs)
7355 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7356 gs->ranges[num_ranges - 1].cGlyphs = 1;
7357 gs->cGlyphsSupported++;
7360 else if (gs)
7362 gs->ranges[num_ranges - 1].cGlyphs++;
7363 gs->cGlyphsSupported++;
7365 char_code_prev = char_code;
7366 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7369 else
7370 FIXME("encoding %u not supported\n", face->charmap->encoding);
7372 return num_ranges;
7375 /*************************************************************
7376 * freetype_GetFontUnicodeRanges
7378 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7380 struct freetype_physdev *physdev = get_freetype_dev( dev );
7381 DWORD size, num_ranges;
7383 if (!physdev->font)
7385 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7386 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7389 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7390 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7391 if (glyphset)
7393 glyphset->cbThis = size;
7394 glyphset->cRanges = num_ranges;
7395 glyphset->flAccel = 0;
7397 return size;
7400 /*************************************************************
7401 * freetype_FontIsLinked
7403 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7405 struct freetype_physdev *physdev = get_freetype_dev( dev );
7406 BOOL ret;
7408 if (!physdev->font)
7410 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7411 return dev->funcs->pFontIsLinked( dev );
7414 GDI_CheckNotLock();
7415 EnterCriticalSection( &freetype_cs );
7416 ret = !list_empty(&physdev->font->child_fonts);
7417 LeaveCriticalSection( &freetype_cs );
7418 return ret;
7421 static BOOL is_hinting_enabled(void)
7423 /* Use the >= 2.2.0 function if available */
7424 if(pFT_Get_TrueType_Engine_Type)
7426 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
7427 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
7429 #ifdef FT_DRIVER_HAS_HINTER
7430 else
7432 FT_Module mod;
7434 /* otherwise if we've been compiled with < 2.2.0 headers
7435 use the internal macro */
7436 mod = pFT_Get_Module(library, "truetype");
7437 if(mod && FT_DRIVER_HAS_HINTER(mod))
7438 return TRUE;
7440 #endif
7442 return FALSE;
7445 static BOOL is_subpixel_rendering_enabled( void )
7447 #ifdef HAVE_FREETYPE_FTLCDFIL_H
7448 return pFT_Library_SetLcdFilter &&
7449 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
7450 #else
7451 return FALSE;
7452 #endif
7455 /*************************************************************************
7456 * GetRasterizerCaps (GDI32.@)
7458 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7460 static int hinting = -1;
7461 static int subpixel = -1;
7463 if(hinting == -1)
7465 hinting = is_hinting_enabled();
7466 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
7469 if ( subpixel == -1 )
7471 subpixel = is_subpixel_rendering_enabled();
7472 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
7475 lprs->nSize = sizeof(RASTERIZER_STATUS);
7476 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
7477 if ( subpixel )
7478 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
7479 lprs->nLanguageID = 0;
7480 return TRUE;
7483 /*************************************************************
7484 * freetype_GdiRealizationInfo
7486 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7488 struct freetype_physdev *physdev = get_freetype_dev( dev );
7489 realization_info_t *info = ptr;
7491 if (!physdev->font)
7493 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7494 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7497 FIXME("(%p, %p): stub!\n", physdev->font, info);
7499 info->flags = 1;
7500 if(FT_IS_SCALABLE(physdev->font->ft_face))
7501 info->flags |= 2;
7503 info->cache_num = physdev->font->cache_num;
7504 info->unknown2 = -1;
7505 return TRUE;
7508 /*************************************************************************
7509 * Kerning support for TrueType fonts
7511 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7513 struct TT_kern_table
7515 USHORT version;
7516 USHORT nTables;
7519 struct TT_kern_subtable
7521 USHORT version;
7522 USHORT length;
7523 union
7525 USHORT word;
7526 struct
7528 USHORT horizontal : 1;
7529 USHORT minimum : 1;
7530 USHORT cross_stream: 1;
7531 USHORT override : 1;
7532 USHORT reserved1 : 4;
7533 USHORT format : 8;
7534 } bits;
7535 } coverage;
7538 struct TT_format0_kern_subtable
7540 USHORT nPairs;
7541 USHORT searchRange;
7542 USHORT entrySelector;
7543 USHORT rangeShift;
7546 struct TT_kern_pair
7548 USHORT left;
7549 USHORT right;
7550 short value;
7553 static DWORD parse_format0_kern_subtable(GdiFont *font,
7554 const struct TT_format0_kern_subtable *tt_f0_ks,
7555 const USHORT *glyph_to_char,
7556 KERNINGPAIR *kern_pair, DWORD cPairs)
7558 USHORT i, nPairs;
7559 const struct TT_kern_pair *tt_kern_pair;
7561 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7563 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7565 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7566 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7567 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7569 if (!kern_pair || !cPairs)
7570 return nPairs;
7572 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7574 nPairs = min(nPairs, cPairs);
7576 for (i = 0; i < nPairs; i++)
7578 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7579 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7580 /* this algorithm appears to better match what Windows does */
7581 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7582 if (kern_pair->iKernAmount < 0)
7584 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7585 kern_pair->iKernAmount -= font->ppem;
7587 else if (kern_pair->iKernAmount > 0)
7589 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7590 kern_pair->iKernAmount += font->ppem;
7592 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7594 TRACE("left %u right %u value %d\n",
7595 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7597 kern_pair++;
7599 TRACE("copied %u entries\n", nPairs);
7600 return nPairs;
7603 /*************************************************************
7604 * freetype_GetKerningPairs
7606 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7608 DWORD length;
7609 void *buf;
7610 const struct TT_kern_table *tt_kern_table;
7611 const struct TT_kern_subtable *tt_kern_subtable;
7612 USHORT i, nTables;
7613 USHORT *glyph_to_char;
7614 GdiFont *font;
7615 struct freetype_physdev *physdev = get_freetype_dev( dev );
7617 if (!(font = physdev->font))
7619 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7620 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7623 GDI_CheckNotLock();
7624 EnterCriticalSection( &freetype_cs );
7625 if (font->total_kern_pairs != (DWORD)-1)
7627 if (cPairs && kern_pair)
7629 cPairs = min(cPairs, font->total_kern_pairs);
7630 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7632 else cPairs = font->total_kern_pairs;
7634 LeaveCriticalSection( &freetype_cs );
7635 return cPairs;
7638 font->total_kern_pairs = 0;
7640 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7642 if (length == GDI_ERROR)
7644 TRACE("no kerning data in the font\n");
7645 LeaveCriticalSection( &freetype_cs );
7646 return 0;
7649 buf = HeapAlloc(GetProcessHeap(), 0, length);
7650 if (!buf)
7652 WARN("Out of memory\n");
7653 LeaveCriticalSection( &freetype_cs );
7654 return 0;
7657 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7659 /* build a glyph index to char code map */
7660 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7661 if (!glyph_to_char)
7663 WARN("Out of memory allocating a glyph index to char code map\n");
7664 HeapFree(GetProcessHeap(), 0, buf);
7665 LeaveCriticalSection( &freetype_cs );
7666 return 0;
7669 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7671 FT_UInt glyph_code;
7672 FT_ULong char_code;
7674 glyph_code = 0;
7675 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7677 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7678 font->ft_face->num_glyphs, glyph_code, char_code);
7680 while (glyph_code)
7682 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7684 /* FIXME: This doesn't match what Windows does: it does some fancy
7685 * things with duplicate glyph index to char code mappings, while
7686 * we just avoid overriding existing entries.
7688 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7689 glyph_to_char[glyph_code] = (USHORT)char_code;
7691 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7694 else
7696 ULONG n;
7698 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7699 for (n = 0; n <= 65535; n++)
7700 glyph_to_char[n] = (USHORT)n;
7703 tt_kern_table = buf;
7704 nTables = GET_BE_WORD(tt_kern_table->nTables);
7705 TRACE("version %u, nTables %u\n",
7706 GET_BE_WORD(tt_kern_table->version), nTables);
7708 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7710 for (i = 0; i < nTables; i++)
7712 struct TT_kern_subtable tt_kern_subtable_copy;
7714 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7715 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7716 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7718 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7719 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7720 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7722 /* According to the TrueType specification this is the only format
7723 * that will be properly interpreted by Windows and OS/2
7725 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7727 DWORD new_chunk, old_total = font->total_kern_pairs;
7729 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7730 glyph_to_char, NULL, 0);
7731 font->total_kern_pairs += new_chunk;
7733 if (!font->kern_pairs)
7734 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7735 font->total_kern_pairs * sizeof(*font->kern_pairs));
7736 else
7737 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7738 font->total_kern_pairs * sizeof(*font->kern_pairs));
7740 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7741 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7743 else
7744 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7746 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7749 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7750 HeapFree(GetProcessHeap(), 0, buf);
7752 if (cPairs && kern_pair)
7754 cPairs = min(cPairs, font->total_kern_pairs);
7755 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7757 else cPairs = font->total_kern_pairs;
7759 LeaveCriticalSection( &freetype_cs );
7760 return cPairs;
7763 static const struct gdi_dc_funcs freetype_funcs =
7765 NULL, /* pAbortDoc */
7766 NULL, /* pAbortPath */
7767 NULL, /* pAlphaBlend */
7768 NULL, /* pAngleArc */
7769 NULL, /* pArc */
7770 NULL, /* pArcTo */
7771 NULL, /* pBeginPath */
7772 NULL, /* pBlendImage */
7773 NULL, /* pChord */
7774 NULL, /* pCloseFigure */
7775 NULL, /* pCreateCompatibleDC */
7776 freetype_CreateDC, /* pCreateDC */
7777 freetype_DeleteDC, /* pDeleteDC */
7778 NULL, /* pDeleteObject */
7779 NULL, /* pDeviceCapabilities */
7780 NULL, /* pEllipse */
7781 NULL, /* pEndDoc */
7782 NULL, /* pEndPage */
7783 NULL, /* pEndPath */
7784 freetype_EnumFonts, /* pEnumFonts */
7785 NULL, /* pEnumICMProfiles */
7786 NULL, /* pExcludeClipRect */
7787 NULL, /* pExtDeviceMode */
7788 NULL, /* pExtEscape */
7789 NULL, /* pExtFloodFill */
7790 NULL, /* pExtSelectClipRgn */
7791 NULL, /* pExtTextOut */
7792 NULL, /* pFillPath */
7793 NULL, /* pFillRgn */
7794 NULL, /* pFlattenPath */
7795 freetype_FontIsLinked, /* pFontIsLinked */
7796 NULL, /* pFrameRgn */
7797 NULL, /* pGdiComment */
7798 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7799 NULL, /* pGetBoundsRect */
7800 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7801 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7802 freetype_GetCharWidth, /* pGetCharWidth */
7803 NULL, /* pGetDeviceCaps */
7804 NULL, /* pGetDeviceGammaRamp */
7805 freetype_GetFontData, /* pGetFontData */
7806 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7807 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7808 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7809 NULL, /* pGetICMProfile */
7810 NULL, /* pGetImage */
7811 freetype_GetKerningPairs, /* pGetKerningPairs */
7812 NULL, /* pGetNearestColor */
7813 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7814 NULL, /* pGetPixel */
7815 NULL, /* pGetSystemPaletteEntries */
7816 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7817 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7818 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7819 freetype_GetTextFace, /* pGetTextFace */
7820 freetype_GetTextMetrics, /* pGetTextMetrics */
7821 NULL, /* pGradientFill */
7822 NULL, /* pIntersectClipRect */
7823 NULL, /* pInvertRgn */
7824 NULL, /* pLineTo */
7825 NULL, /* pModifyWorldTransform */
7826 NULL, /* pMoveTo */
7827 NULL, /* pOffsetClipRgn */
7828 NULL, /* pOffsetViewportOrg */
7829 NULL, /* pOffsetWindowOrg */
7830 NULL, /* pPaintRgn */
7831 NULL, /* pPatBlt */
7832 NULL, /* pPie */
7833 NULL, /* pPolyBezier */
7834 NULL, /* pPolyBezierTo */
7835 NULL, /* pPolyDraw */
7836 NULL, /* pPolyPolygon */
7837 NULL, /* pPolyPolyline */
7838 NULL, /* pPolygon */
7839 NULL, /* pPolyline */
7840 NULL, /* pPolylineTo */
7841 NULL, /* pPutImage */
7842 NULL, /* pRealizeDefaultPalette */
7843 NULL, /* pRealizePalette */
7844 NULL, /* pRectangle */
7845 NULL, /* pResetDC */
7846 NULL, /* pRestoreDC */
7847 NULL, /* pRoundRect */
7848 NULL, /* pSaveDC */
7849 NULL, /* pScaleViewportExt */
7850 NULL, /* pScaleWindowExt */
7851 NULL, /* pSelectBitmap */
7852 NULL, /* pSelectBrush */
7853 NULL, /* pSelectClipPath */
7854 freetype_SelectFont, /* pSelectFont */
7855 NULL, /* pSelectPalette */
7856 NULL, /* pSelectPen */
7857 NULL, /* pSetArcDirection */
7858 NULL, /* pSetBkColor */
7859 NULL, /* pSetBkMode */
7860 NULL, /* pSetDCBrushColor */
7861 NULL, /* pSetDCPenColor */
7862 NULL, /* pSetDIBColorTable */
7863 NULL, /* pSetDIBitsToDevice */
7864 NULL, /* pSetDeviceClipping */
7865 NULL, /* pSetDeviceGammaRamp */
7866 NULL, /* pSetLayout */
7867 NULL, /* pSetMapMode */
7868 NULL, /* pSetMapperFlags */
7869 NULL, /* pSetPixel */
7870 NULL, /* pSetPolyFillMode */
7871 NULL, /* pSetROP2 */
7872 NULL, /* pSetRelAbs */
7873 NULL, /* pSetStretchBltMode */
7874 NULL, /* pSetTextAlign */
7875 NULL, /* pSetTextCharacterExtra */
7876 NULL, /* pSetTextColor */
7877 NULL, /* pSetTextJustification */
7878 NULL, /* pSetViewportExt */
7879 NULL, /* pSetViewportOrg */
7880 NULL, /* pSetWindowExt */
7881 NULL, /* pSetWindowOrg */
7882 NULL, /* pSetWorldTransform */
7883 NULL, /* pStartDoc */
7884 NULL, /* pStartPage */
7885 NULL, /* pStretchBlt */
7886 NULL, /* pStretchDIBits */
7887 NULL, /* pStrokeAndFillPath */
7888 NULL, /* pStrokePath */
7889 NULL, /* pUnrealizePalette */
7890 NULL, /* pWidenPath */
7891 NULL, /* wine_get_wgl_driver */
7892 GDI_PRIORITY_FONT_DRV /* priority */
7895 #else /* HAVE_FREETYPE */
7897 /*************************************************************************/
7899 BOOL WineEngInit(void)
7901 return FALSE;
7903 BOOL WineEngDestroyFontInstance(HFONT hfont)
7905 return FALSE;
7908 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7910 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7911 return 1;
7914 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7916 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7917 return TRUE;
7920 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7922 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7923 return NULL;
7926 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
7927 LPCWSTR font_file, LPCWSTR font_path )
7929 FIXME("stub\n");
7930 return FALSE;
7933 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7935 return FALSE;
7938 /*************************************************************************
7939 * GetRasterizerCaps (GDI32.@)
7941 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7943 lprs->nSize = sizeof(RASTERIZER_STATUS);
7944 lprs->wFlags = 0;
7945 lprs->nLanguageID = 0;
7946 return TRUE;
7949 #endif /* HAVE_FREETYPE */