gdi32: Avoid TRUE:FALSE conditional expressions.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blob8222a1879c982d69a5a126c63dc3733441a3e161
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 == req->encoding_id) &&
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.encoding_id = TT_MS_ID_UNICODE_CS;
1172 name.language_id = language_id;
1173 name.name_id = name_id;
1175 if(get_name_table_entry(ft_face, &name))
1177 FT_UInt i;
1179 /* String is not nul terminated and string_len is a byte length. */
1180 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1181 for(i = 0; i < name.string_len / 2; i++)
1183 WORD *tmp = (WORD *)&name.string[i * 2];
1184 ret[i] = GET_BE_WORD(*tmp);
1186 ret[i] = 0;
1187 TRACE("Got localised name %s\n", debugstr_w(ret));
1190 return ret;
1193 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1195 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1196 if (f1->scalable) return TRUE;
1197 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1198 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1201 static inline void free_face( Face *face )
1203 HeapFree( GetProcessHeap(), 0, face->file );
1204 HeapFree( GetProcessHeap(), 0, face->StyleName );
1205 HeapFree( GetProcessHeap(), 0, face->FullName );
1206 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1207 HeapFree( GetProcessHeap(), 0, face );
1210 static inline void free_family( Family *family )
1212 Face *face, *cursor2;
1214 LIST_FOR_EACH_ENTRY_SAFE( face, cursor2, &family->faces, Face, entry )
1216 list_remove( &face->entry );
1217 free_face( face );
1219 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1220 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1221 HeapFree( GetProcessHeap(), 0, family );
1224 static inline int style_order(const Face *face)
1226 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1228 case NTM_REGULAR:
1229 return 0;
1230 case NTM_BOLD:
1231 return 1;
1232 case NTM_ITALIC:
1233 return 2;
1234 case NTM_BOLD | NTM_ITALIC:
1235 return 3;
1236 default:
1237 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1238 debugstr_w(face->family->FamilyName),
1239 debugstr_w(face->StyleName),
1240 face->ntmFlags);
1241 return 9999;
1245 static BOOL insert_face_in_family_list( Face *face, Family *family )
1247 Face *cursor;
1249 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1251 if (faces_equal( face, cursor ))
1253 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1254 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1255 cursor->font_version, face->font_version);
1257 if (face->font_version <= cursor->font_version)
1259 TRACE("Original font %s is newer so skipping %s\n",
1260 debugstr_a(cursor->file), debugstr_a(face->file));
1261 return FALSE;
1263 else
1265 TRACE("Replacing original %s with %s\n",
1266 debugstr_a(cursor->file), debugstr_a(face->file));
1267 list_add_before( &cursor->entry, &face->entry );
1268 face->family = family;
1269 list_remove( &cursor->entry);
1270 free_face( cursor );
1271 return TRUE;
1274 else
1275 TRACE("Adding new %s\n", debugstr_a(face->file));
1277 if (style_order( face ) < style_order( cursor )) break;
1280 list_add_before( &cursor->entry, &face->entry );
1281 face->family = family;
1282 return TRUE;
1285 /****************************************************************
1286 * NB This function stores the ptrs to the strings to save copying.
1287 * Don't free them after calling.
1289 static Family *create_family( WCHAR *name, WCHAR *english_name )
1291 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1292 family->FamilyName = name;
1293 family->EnglishName = english_name;
1294 list_init( &family->faces );
1295 family->replacement = &family->faces;
1297 return family;
1300 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1302 DWORD type, needed;
1303 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1304 if(r != ERROR_SUCCESS) return r;
1305 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1306 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1309 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1311 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1314 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1316 DWORD needed;
1317 DWORD num_strikes, max_strike_key_len;
1319 /* If we have a File Name key then this is a real font, not just the parent
1320 key of a bunch of non-scalable strikes */
1321 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1323 Face *face;
1324 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1325 face->cached_enum_data = NULL;
1327 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1328 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1330 face->StyleName = strdupW(face_name);
1332 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1334 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1335 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1336 face->FullName = fullName;
1338 else
1339 face->FullName = NULL;
1341 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1342 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1343 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1344 reg_load_dword(hkey_face, face_vertical_value, (DWORD*)&face->vertical);
1346 needed = sizeof(face->fs);
1347 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1349 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1351 face->scalable = TRUE;
1352 memset(&face->size, 0, sizeof(face->size));
1354 else
1356 face->scalable = FALSE;
1357 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1358 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1359 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1360 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1361 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1363 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1364 face->size.height, face->size.width, face->size.size >> 6,
1365 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1368 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1369 face->fs.fsCsb[0], face->fs.fsCsb[1],
1370 face->fs.fsUsb[0], face->fs.fsUsb[1],
1371 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1373 insert_face_in_family_list(face, family);
1375 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1378 /* do we have any bitmap strikes? */
1379 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1380 NULL, NULL, NULL, NULL);
1381 if(num_strikes != 0)
1383 WCHAR strike_name[10];
1384 DWORD strike_index = 0;
1386 needed = sizeof(strike_name) / sizeof(WCHAR);
1387 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1388 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1390 HKEY hkey_strike;
1391 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1392 load_face(hkey_strike, face_name, family);
1393 RegCloseKey(hkey_strike);
1394 needed = sizeof(strike_name) / sizeof(WCHAR);
1399 static void load_font_list_from_cache(HKEY hkey_font_cache)
1401 DWORD max_family_key_len, size;
1402 WCHAR *family_name;
1403 DWORD family_index = 0;
1404 Family *family;
1405 HKEY hkey_family;
1407 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1408 NULL, NULL, NULL, NULL);
1409 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1411 size = max_family_key_len + 1;
1412 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1413 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1415 WCHAR *english_family = NULL;
1416 DWORD face_index = 0;
1417 WCHAR *face_name;
1418 DWORD max_face_key_len;
1420 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1421 TRACE("opened family key %s\n", debugstr_w(family_name));
1422 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1424 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1425 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1428 family = create_family(strdupW(family_name), english_family);
1429 list_add_tail(&font_list, &family->entry);
1431 if(english_family)
1433 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1434 subst->from.name = strdupW(english_family);
1435 subst->from.charset = -1;
1436 subst->to.name = strdupW(family_name);
1437 subst->to.charset = -1;
1438 add_font_subst(&font_subst_list, subst, 0);
1441 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1442 NULL, NULL, NULL, NULL);
1444 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1445 size = max_face_key_len + 1;
1446 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1447 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1449 HKEY hkey_face;
1451 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1452 load_face(hkey_face, face_name, family);
1453 RegCloseKey(hkey_face);
1454 size = max_face_key_len + 1;
1456 HeapFree(GetProcessHeap(), 0, face_name);
1457 RegCloseKey(hkey_family);
1458 size = max_family_key_len + 1;
1461 HeapFree(GetProcessHeap(), 0, family_name);
1464 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1466 LONG ret;
1467 HKEY hkey_wine_fonts;
1469 /* We don't want to create the fonts key as volatile, so open this first */
1470 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1471 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1472 if(ret != ERROR_SUCCESS)
1474 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1475 return ret;
1478 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1479 KEY_ALL_ACCESS, NULL, hkey, disposition);
1480 RegCloseKey(hkey_wine_fonts);
1481 return ret;
1484 static void add_face_to_cache(Face *face)
1486 HKEY hkey_font_cache, hkey_family, hkey_face;
1487 WCHAR *face_key_name;
1489 create_font_cache_key(&hkey_font_cache, NULL);
1491 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1492 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1493 if(face->family->EnglishName)
1494 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1495 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1497 if(face->scalable)
1498 face_key_name = face->StyleName;
1499 else
1501 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1502 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1503 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1505 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1506 &hkey_face, NULL);
1507 if(!face->scalable)
1508 HeapFree(GetProcessHeap(), 0, face_key_name);
1510 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1511 if (face->FullName)
1512 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1513 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1515 reg_save_dword(hkey_face, face_index_value, face->face_index);
1516 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1517 reg_save_dword(hkey_face, face_version_value, face->font_version);
1518 reg_save_dword(hkey_face, face_vertical_value, face->vertical);
1520 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1522 if(!face->scalable)
1524 reg_save_dword(hkey_face, face_height_value, face->size.height);
1525 reg_save_dword(hkey_face, face_width_value, face->size.width);
1526 reg_save_dword(hkey_face, face_size_value, face->size.size);
1527 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1528 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1529 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1531 RegCloseKey(hkey_face);
1532 RegCloseKey(hkey_family);
1533 RegCloseKey(hkey_font_cache);
1536 static WCHAR *prepend_at(WCHAR *family)
1538 WCHAR *str;
1540 if (!family)
1541 return NULL;
1543 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1544 str[0] = '@';
1545 strcpyW(str + 1, family);
1546 HeapFree(GetProcessHeap(), 0, family);
1547 return str;
1550 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1552 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1553 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1555 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID() );
1556 if (!*name)
1558 *name = *english;
1559 *english = NULL;
1561 else if (!strcmpiW( *name, *english ))
1563 HeapFree( GetProcessHeap(), 0, *english );
1564 *english = NULL;
1567 if (vertical)
1569 *name = prepend_at( *name );
1570 *english = prepend_at( *english );
1574 static Family *get_family( FT_Face ft_face, BOOL vertical )
1576 Family *family;
1577 WCHAR *name, *english_name;
1579 get_family_names( ft_face, &name, &english_name, vertical );
1581 family = find_family_from_name( name );
1583 if (!family)
1585 family = create_family( name, english_name );
1586 list_add_tail( &font_list, &family->entry );
1588 if (english_name)
1590 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1591 subst->from.name = strdupW( english_name );
1592 subst->from.charset = -1;
1593 subst->to.name = strdupW( name );
1594 subst->to.charset = -1;
1595 add_font_subst( &font_subst_list, subst, 0 );
1598 else
1600 HeapFree( GetProcessHeap(), 0, name );
1601 HeapFree( GetProcessHeap(), 0, english_name );
1604 return family;
1607 static inline FT_Fixed get_font_version( FT_Face ft_face )
1609 FT_Fixed version = 0;
1610 TT_Header *header;
1612 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1613 if (header) version = header->Font_Revision;
1615 return version;
1618 static inline DWORD get_ntm_flags( FT_Face ft_face )
1620 DWORD flags = 0;
1621 FT_ULong table_size = 0;
1623 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1624 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1625 if (flags == 0) flags = NTM_REGULAR;
1627 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1628 flags |= NTM_PS_OPENTYPE;
1630 return flags;
1633 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1635 int internal_leading = 0;
1636 FT_WinFNT_HeaderRec winfnt_header;
1638 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1639 internal_leading = winfnt_header.internal_leading;
1641 return internal_leading;
1644 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1646 TT_OS2 *os2;
1647 FT_UInt dummy;
1648 CHARSETINFO csi;
1649 FT_WinFNT_HeaderRec winfnt_header;
1650 int i;
1652 memset( fs, 0, sizeof(*fs) );
1654 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1655 if (os2)
1657 fs->fsUsb[0] = os2->ulUnicodeRange1;
1658 fs->fsUsb[1] = os2->ulUnicodeRange2;
1659 fs->fsUsb[2] = os2->ulUnicodeRange3;
1660 fs->fsUsb[3] = os2->ulUnicodeRange4;
1662 if (os2->version == 0)
1664 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1665 fs->fsCsb[0] = FS_LATIN1;
1666 else
1667 fs->fsCsb[0] = FS_SYMBOL;
1669 else
1671 fs->fsCsb[0] = os2->ulCodePageRange1;
1672 fs->fsCsb[1] = os2->ulCodePageRange2;
1675 else
1677 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1679 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1680 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1681 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1682 *fs = csi.fs;
1686 if (fs->fsCsb[0] == 0)
1688 /* let's see if we can find any interesting cmaps */
1689 for (i = 0; i < ft_face->num_charmaps; i++)
1691 switch (ft_face->charmaps[i]->encoding)
1693 case FT_ENCODING_UNICODE:
1694 case FT_ENCODING_APPLE_ROMAN:
1695 fs->fsCsb[0] |= FS_LATIN1;
1696 break;
1697 case FT_ENCODING_MS_SYMBOL:
1698 fs->fsCsb[0] |= FS_SYMBOL;
1699 break;
1700 default:
1701 break;
1707 #define ADDFONT_EXTERNAL_FONT 0x01
1708 #define ADDFONT_FORCE_BITMAP 0x02
1709 #define ADDFONT_ADD_TO_CACHE 0x04
1711 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1712 DWORD flags, BOOL vertical )
1714 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1715 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1717 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1718 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1719 if (file)
1721 face->file = strdupA( file );
1722 face->font_data_ptr = NULL;
1723 face->font_data_size = 0;
1725 else
1727 face->file = NULL;
1728 face->font_data_ptr = font_data_ptr;
1729 face->font_data_size = font_data_size;
1732 face->face_index = face_index;
1733 get_fontsig( ft_face, &face->fs );
1734 face->ntmFlags = get_ntm_flags( ft_face );
1735 face->font_version = get_font_version( ft_face );
1737 if (FT_IS_SCALABLE( ft_face ))
1739 memset( &face->size, 0, sizeof(face->size) );
1740 face->scalable = TRUE;
1742 else
1744 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1745 size->height, size->width, size->size >> 6,
1746 size->x_ppem >> 6, size->y_ppem >> 6);
1747 face->size.height = size->height;
1748 face->size.width = size->width;
1749 face->size.size = size->size;
1750 face->size.x_ppem = size->x_ppem;
1751 face->size.y_ppem = size->y_ppem;
1752 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1753 face->scalable = FALSE;
1756 face->vertical = vertical;
1757 face->external = (flags & ADDFONT_EXTERNAL_FONT) != 0;
1758 face->family = NULL;
1759 face->cached_enum_data = NULL;
1761 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1762 face->fs.fsCsb[0], face->fs.fsCsb[1],
1763 face->fs.fsUsb[0], face->fs.fsUsb[1],
1764 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1766 return face;
1769 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1770 FT_Long face_index, DWORD flags, BOOL vertical)
1772 Face *face;
1773 Family *family;
1775 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags, vertical );
1776 family = get_family( ft_face, vertical );
1777 if (!insert_face_in_family_list( face, family ))
1779 free_face( face );
1780 return;
1783 if (flags & ADDFONT_ADD_TO_CACHE)
1784 add_face_to_cache( face );
1786 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1787 debugstr_w(face->StyleName));
1790 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1791 FT_Long face_index, BOOL allow_bitmap )
1793 FT_Error err;
1794 TT_OS2 *pOS2;
1795 FT_Face ft_face;
1797 if (file)
1799 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1800 err = pFT_New_Face(library, file, face_index, &ft_face);
1802 else
1804 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1805 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1808 if (err != 0)
1810 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1811 return NULL;
1814 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1815 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1817 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1818 goto fail;
1821 if (!FT_IS_SFNT( ft_face ))
1823 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1825 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1826 goto fail;
1829 else
1831 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1832 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1833 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1835 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1836 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1837 goto fail;
1840 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1841 we don't want to load these. */
1842 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1844 FT_ULong len = 0;
1846 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1848 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1849 goto fail;
1854 if (!ft_face->family_name || !ft_face->style_name)
1856 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1857 goto fail;
1860 return ft_face;
1861 fail:
1862 pFT_Done_Face( ft_face );
1863 return NULL;
1866 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1868 FT_Face ft_face;
1869 FT_Long face_index = 0, num_faces;
1870 INT ret = 0;
1872 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1873 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1875 #ifdef HAVE_CARBON_CARBON_H
1876 if(file)
1878 char **mac_list = expand_mac_font(file);
1879 if(mac_list)
1881 BOOL had_one = FALSE;
1882 char **cursor;
1883 for(cursor = mac_list; *cursor; cursor++)
1885 had_one = TRUE;
1886 AddFontToList(*cursor, NULL, 0, flags);
1887 HeapFree(GetProcessHeap(), 0, *cursor);
1889 HeapFree(GetProcessHeap(), 0, mac_list);
1890 if(had_one)
1891 return 1;
1894 #endif /* HAVE_CARBON_CARBON_H */
1896 do {
1897 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_FORCE_BITMAP );
1898 if (!ft_face) return 0;
1900 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1902 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1903 pFT_Done_Face(ft_face);
1904 return 0;
1907 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1908 ++ret;
1910 if (FT_HAS_VERTICAL(ft_face))
1912 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1913 ++ret;
1916 num_faces = ft_face->num_faces;
1917 pFT_Done_Face(ft_face);
1918 } while(num_faces > ++face_index);
1919 return ret;
1922 static void DumpFontList(void)
1924 Family *family;
1925 Face *face;
1926 struct list *family_elem_ptr, *face_elem_ptr;
1928 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1929 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1930 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1931 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1932 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1933 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1934 if(!face->scalable)
1935 TRACE(" %d", face->size.height);
1936 TRACE("\n");
1939 return;
1942 /***********************************************************
1943 * The replacement list is a way to map an entire font
1944 * family onto another family. For example adding
1946 * [HKCU\Software\Wine\Fonts\Replacements]
1947 * "Wingdings"="Winedings"
1949 * would enumerate the Winedings font both as Winedings and
1950 * Wingdings. However if a real Wingdings font is present the
1951 * replacement does not take place.
1954 static void LoadReplaceList(void)
1956 HKEY hkey;
1957 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1958 LPWSTR value;
1959 LPVOID data;
1960 CHAR familyA[400];
1962 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1963 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1965 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1966 &valuelen, &datalen, NULL, NULL);
1968 valuelen++; /* returned value doesn't include room for '\0' */
1969 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1970 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1972 dlen = datalen;
1973 vlen = valuelen;
1974 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1975 &dlen) == ERROR_SUCCESS) {
1976 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1977 /* "NewName"="Oldname" */
1978 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1980 if(!find_family_from_any_name(value))
1982 Family * const family = find_family_from_any_name(data);
1983 if (family != NULL)
1985 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
1986 if (new_family != NULL)
1988 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
1989 new_family->FamilyName = strdupW(value);
1990 new_family->EnglishName = NULL;
1991 list_init(&new_family->faces);
1992 new_family->replacement = &family->faces;
1993 list_add_tail(&font_list, &new_family->entry);
1996 else
1998 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2001 else
2003 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2005 /* reset dlen and vlen */
2006 dlen = datalen;
2007 vlen = valuelen;
2009 HeapFree(GetProcessHeap(), 0, data);
2010 HeapFree(GetProcessHeap(), 0, value);
2011 RegCloseKey(hkey);
2015 static const WCHAR *font_links_list[] =
2017 Lucida_Sans_Unicode,
2018 Microsoft_Sans_Serif,
2019 Tahoma
2022 static const struct font_links_defaults_list
2024 /* Keyed off substitution for "MS Shell Dlg" */
2025 const WCHAR *shelldlg;
2026 /* Maximum of four substitutes, plus terminating NULL pointer */
2027 const WCHAR *substitutes[5];
2028 } font_links_defaults_list[] =
2030 /* Non East-Asian */
2031 { Tahoma, /* FIXME unverified ordering */
2032 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2034 /* Below lists are courtesy of
2035 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2037 /* Japanese */
2038 { MS_UI_Gothic,
2039 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2041 /* Chinese Simplified */
2042 { SimSun,
2043 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2045 /* Korean */
2046 { Gulim,
2047 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2049 /* Chinese Traditional */
2050 { PMingLiU,
2051 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2056 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2058 SYSTEM_LINKS *font_link;
2060 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2062 if(!strcmpiW(font_link->font_name, name))
2063 return font_link;
2066 return NULL;
2069 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2071 const WCHAR *value;
2072 int i;
2073 FontSubst *psub;
2074 Family *family;
2075 Face *face;
2076 const char *file;
2077 WCHAR *fileW;
2079 if (values)
2081 SYSTEM_LINKS *font_link;
2083 psub = get_font_subst(&font_subst_list, name, -1);
2084 /* Don't store fonts that are only substitutes for other fonts */
2085 if(psub)
2087 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2088 return;
2091 font_link = find_font_link(name);
2092 if (font_link == NULL)
2094 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2095 font_link->font_name = strdupW(name);
2096 list_init(&font_link->links);
2097 list_add_tail(&system_links, &font_link->entry);
2100 memset(&font_link->fs, 0, sizeof font_link->fs);
2101 for (i = 0; values[i] != NULL; i++)
2103 const struct list *face_list;
2104 CHILD_FONT *child_font;
2106 value = values[i];
2107 if (!strcmpiW(name,value))
2108 continue;
2109 psub = get_font_subst(&font_subst_list, value, -1);
2110 if(psub)
2111 value = psub->to.name;
2112 family = find_family_from_name(value);
2113 if (!family)
2114 continue;
2115 file = NULL;
2116 /* Use first extant filename for this Family */
2117 face_list = get_face_list_from_family(family);
2118 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2120 if (!face->file)
2121 continue;
2122 file = strrchr(face->file, '/');
2123 if (!file)
2124 file = face->file;
2125 else
2126 file++;
2127 break;
2129 if (!file)
2130 continue;
2131 fileW = towstr(CP_UNIXCP, file);
2133 face = find_face_from_filename(fileW, value);
2134 if(!face)
2136 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2137 continue;
2140 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2141 child_font->face = face;
2142 child_font->font = NULL;
2143 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2144 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2145 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2146 list_add_tail(&font_link->links, &child_font->entry);
2148 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2149 HeapFree(GetProcessHeap(), 0, fileW);
2155 /*************************************************************
2156 * init_system_links
2158 static BOOL init_system_links(void)
2160 HKEY hkey;
2161 BOOL ret = FALSE;
2162 DWORD type, max_val, max_data, val_len, data_len, index;
2163 WCHAR *value, *data;
2164 WCHAR *entry, *next;
2165 SYSTEM_LINKS *font_link, *system_font_link;
2166 CHILD_FONT *child_font;
2167 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2168 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2169 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2170 Face *face;
2171 FontSubst *psub;
2172 UINT i, j;
2174 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2176 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2177 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2178 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2179 val_len = max_val + 1;
2180 data_len = max_data;
2181 index = 0;
2182 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2184 psub = get_font_subst(&font_subst_list, value, -1);
2185 /* Don't store fonts that are only substitutes for other fonts */
2186 if(psub)
2188 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2189 goto next;
2191 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2192 font_link->font_name = strdupW(value);
2193 memset(&font_link->fs, 0, sizeof font_link->fs);
2194 list_init(&font_link->links);
2195 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2197 WCHAR *face_name;
2198 CHILD_FONT *child_font;
2200 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2202 next = entry + strlenW(entry) + 1;
2204 face_name = strchrW(entry, ',');
2205 if(face_name)
2207 *face_name++ = 0;
2208 while(isspaceW(*face_name))
2209 face_name++;
2211 psub = get_font_subst(&font_subst_list, face_name, -1);
2212 if(psub)
2213 face_name = psub->to.name;
2215 face = find_face_from_filename(entry, face_name);
2216 if(!face)
2218 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2219 continue;
2222 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2223 child_font->face = face;
2224 child_font->font = NULL;
2225 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2226 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2227 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2228 list_add_tail(&font_link->links, &child_font->entry);
2230 list_add_tail(&system_links, &font_link->entry);
2231 next:
2232 val_len = max_val + 1;
2233 data_len = max_data;
2236 HeapFree(GetProcessHeap(), 0, value);
2237 HeapFree(GetProcessHeap(), 0, data);
2238 RegCloseKey(hkey);
2242 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2243 if (!psub) {
2244 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2245 goto skip_internal;
2248 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2250 const FontSubst *psub2;
2251 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2253 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2255 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2256 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2258 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2259 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2261 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2263 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2267 skip_internal:
2269 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2270 that Tahoma has */
2272 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2273 system_font_link->font_name = strdupW(System);
2274 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2275 list_init(&system_font_link->links);
2277 face = find_face_from_filename(tahoma_ttf, Tahoma);
2278 if(face)
2280 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2281 child_font->face = face;
2282 child_font->font = NULL;
2283 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2284 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2285 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2286 list_add_tail(&system_font_link->links, &child_font->entry);
2288 font_link = find_font_link(Tahoma);
2289 if (font_link != NULL)
2291 CHILD_FONT *font_link_entry;
2292 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2294 CHILD_FONT *new_child;
2295 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2296 new_child->face = font_link_entry->face;
2297 new_child->font = NULL;
2298 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2299 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2300 list_add_tail(&system_font_link->links, &new_child->entry);
2303 list_add_tail(&system_links, &system_font_link->entry);
2304 return ret;
2307 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2309 DIR *dir;
2310 struct dirent *dent;
2311 char path[MAX_PATH];
2313 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2315 dir = opendir(dirname);
2316 if(!dir) {
2317 WARN("Can't open directory %s\n", debugstr_a(dirname));
2318 return FALSE;
2320 while((dent = readdir(dir)) != NULL) {
2321 struct stat statbuf;
2323 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2324 continue;
2326 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2328 sprintf(path, "%s/%s", dirname, dent->d_name);
2330 if(stat(path, &statbuf) == -1)
2332 WARN("Can't stat %s\n", debugstr_a(path));
2333 continue;
2335 if(S_ISDIR(statbuf.st_mode))
2336 ReadFontDir(path, external_fonts);
2337 else
2339 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2340 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2341 AddFontToList(path, NULL, 0, addfont_flags);
2344 closedir(dir);
2345 return TRUE;
2348 #ifdef SONAME_LIBFONTCONFIG
2349 static void load_fontconfig_fonts(void)
2351 void *fc_handle = NULL;
2352 FcConfig *config;
2353 FcPattern *pat;
2354 FcObjectSet *os;
2355 FcFontSet *fontset;
2356 int i, len;
2357 char *file;
2358 const char *ext;
2360 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2361 if(!fc_handle) {
2362 TRACE("Wine cannot find the fontconfig library (%s).\n",
2363 SONAME_LIBFONTCONFIG);
2364 return;
2366 #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;}
2367 LOAD_FUNCPTR(FcConfigGetCurrent);
2368 LOAD_FUNCPTR(FcFontList);
2369 LOAD_FUNCPTR(FcFontSetDestroy);
2370 LOAD_FUNCPTR(FcInit);
2371 LOAD_FUNCPTR(FcObjectSetAdd);
2372 LOAD_FUNCPTR(FcObjectSetCreate);
2373 LOAD_FUNCPTR(FcObjectSetDestroy);
2374 LOAD_FUNCPTR(FcPatternCreate);
2375 LOAD_FUNCPTR(FcPatternDestroy);
2376 LOAD_FUNCPTR(FcPatternGetBool);
2377 LOAD_FUNCPTR(FcPatternGetString);
2378 #undef LOAD_FUNCPTR
2380 if(!pFcInit()) return;
2382 config = pFcConfigGetCurrent();
2383 pat = pFcPatternCreate();
2384 os = pFcObjectSetCreate();
2385 pFcObjectSetAdd(os, FC_FILE);
2386 pFcObjectSetAdd(os, FC_SCALABLE);
2387 fontset = pFcFontList(config, pat, os);
2388 if(!fontset) return;
2389 for(i = 0; i < fontset->nfont; i++) {
2390 FcBool scalable;
2392 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2393 continue;
2394 TRACE("fontconfig: %s\n", file);
2396 /* We're just interested in OT/TT fonts for now, so this hack just
2397 picks up the scalable fonts without extensions .pf[ab] to save time
2398 loading every other font */
2400 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2402 TRACE("not scalable\n");
2403 continue;
2406 len = strlen( file );
2407 if(len < 4) continue;
2408 ext = &file[ len - 3 ];
2409 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2410 AddFontToList(file, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2412 pFcFontSetDestroy(fontset);
2413 pFcObjectSetDestroy(os);
2414 pFcPatternDestroy(pat);
2415 sym_not_found:
2416 return;
2419 #elif defined(HAVE_CARBON_CARBON_H)
2421 static void load_mac_font_callback(const void *value, void *context)
2423 CFStringRef pathStr = value;
2424 CFIndex len;
2425 char* path;
2427 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2428 path = HeapAlloc(GetProcessHeap(), 0, len);
2429 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2431 TRACE("font file %s\n", path);
2432 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2434 HeapFree(GetProcessHeap(), 0, path);
2437 static void load_mac_fonts(void)
2439 CFStringRef removeDupesKey;
2440 CFBooleanRef removeDupesValue;
2441 CFDictionaryRef options;
2442 CTFontCollectionRef col;
2443 CFArrayRef descs;
2444 CFMutableSetRef paths;
2445 CFIndex i;
2447 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2448 removeDupesValue = kCFBooleanTrue;
2449 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2450 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2451 col = CTFontCollectionCreateFromAvailableFonts(options);
2452 if (options) CFRelease(options);
2453 if (!col)
2455 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2456 return;
2459 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2460 CFRelease(col);
2461 if (!descs)
2463 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2464 return;
2467 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2468 if (!paths)
2470 WARN("CFSetCreateMutable failed\n");
2471 CFRelease(descs);
2472 return;
2475 for (i = 0; i < CFArrayGetCount(descs); i++)
2477 CTFontDescriptorRef desc;
2478 CTFontRef font;
2479 ATSFontRef atsFont;
2480 OSStatus status;
2481 FSRef fsref;
2482 CFURLRef url;
2483 CFStringRef ext;
2484 CFStringRef path;
2486 desc = CFArrayGetValueAtIndex(descs, i);
2488 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2489 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2490 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2491 if (!font) continue;
2493 atsFont = CTFontGetPlatformFont(font, NULL);
2494 if (!atsFont)
2496 CFRelease(font);
2497 continue;
2500 status = ATSFontGetFileReference(atsFont, &fsref);
2501 CFRelease(font);
2502 if (status != noErr) continue;
2504 url = CFURLCreateFromFSRef(NULL, &fsref);
2505 if (!url) continue;
2507 ext = CFURLCopyPathExtension(url);
2508 if (ext)
2510 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2511 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2512 CFRelease(ext);
2513 if (skip)
2515 CFRelease(url);
2516 continue;
2520 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2521 CFRelease(url);
2522 if (!path) continue;
2524 CFSetAddValue(paths, path);
2525 CFRelease(path);
2528 CFRelease(descs);
2530 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2531 CFRelease(paths);
2534 #endif
2536 static BOOL load_font_from_data_dir(LPCWSTR file)
2538 BOOL ret = FALSE;
2539 const char *data_dir = wine_get_data_dir();
2541 if (!data_dir) data_dir = wine_get_build_dir();
2543 if (data_dir)
2545 INT len;
2546 char *unix_name;
2548 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2550 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2552 strcpy(unix_name, data_dir);
2553 strcat(unix_name, "/fonts/");
2555 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2557 EnterCriticalSection( &freetype_cs );
2558 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2559 LeaveCriticalSection( &freetype_cs );
2560 HeapFree(GetProcessHeap(), 0, unix_name);
2562 return ret;
2565 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2567 static const WCHAR slashW[] = {'\\','\0'};
2568 BOOL ret = FALSE;
2569 WCHAR windowsdir[MAX_PATH];
2570 char *unixname;
2572 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2573 strcatW(windowsdir, fontsW);
2574 strcatW(windowsdir, slashW);
2575 strcatW(windowsdir, file);
2576 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2577 EnterCriticalSection( &freetype_cs );
2578 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2579 LeaveCriticalSection( &freetype_cs );
2580 HeapFree(GetProcessHeap(), 0, unixname);
2582 return ret;
2585 static void load_system_fonts(void)
2587 HKEY hkey;
2588 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2589 const WCHAR * const *value;
2590 DWORD dlen, type;
2591 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2592 char *unixname;
2594 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2595 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2596 strcatW(windowsdir, fontsW);
2597 for(value = SystemFontValues; *value; value++) {
2598 dlen = sizeof(data);
2599 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2600 type == REG_SZ) {
2601 BOOL added = FALSE;
2603 sprintfW(pathW, fmtW, windowsdir, data);
2604 if((unixname = wine_get_unix_file_name(pathW))) {
2605 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2606 HeapFree(GetProcessHeap(), 0, unixname);
2608 if (!added)
2609 load_font_from_data_dir(data);
2612 RegCloseKey(hkey);
2616 /*************************************************************
2618 * This adds registry entries for any externally loaded fonts
2619 * (fonts from fontconfig or FontDirs). It also deletes entries
2620 * of no longer existing fonts.
2623 static void update_reg_entries(void)
2625 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2626 LPWSTR valueW;
2627 DWORD len, len_fam;
2628 Family *family;
2629 Face *face;
2630 struct list *family_elem_ptr, *face_elem_ptr;
2631 WCHAR *file;
2632 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2633 static const WCHAR spaceW[] = {' ', '\0'};
2634 char *path;
2636 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2637 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2638 ERR("Can't create Windows font reg key\n");
2639 goto end;
2642 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2643 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2644 ERR("Can't create Windows font reg key\n");
2645 goto end;
2648 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2649 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2650 ERR("Can't create external font reg key\n");
2651 goto end;
2654 /* enumerate the fonts and add external ones to the two keys */
2656 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2657 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2658 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2659 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2660 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2661 if(!face->external) continue;
2662 len = len_fam;
2663 if (!(face->ntmFlags & NTM_REGULAR))
2664 len = len_fam + strlenW(face->StyleName) + 1;
2665 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2666 strcpyW(valueW, family->FamilyName);
2667 if(len != len_fam) {
2668 strcatW(valueW, spaceW);
2669 strcatW(valueW, face->StyleName);
2671 strcatW(valueW, TrueType);
2673 file = wine_get_dos_file_name(face->file);
2674 if(file)
2675 len = strlenW(file) + 1;
2676 else
2678 if((path = strrchr(face->file, '/')) == NULL)
2679 path = face->file;
2680 else
2681 path++;
2682 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2684 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2685 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2687 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2688 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2689 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2691 HeapFree(GetProcessHeap(), 0, file);
2692 HeapFree(GetProcessHeap(), 0, valueW);
2695 end:
2696 if(external_key) RegCloseKey(external_key);
2697 if(win9x_key) RegCloseKey(win9x_key);
2698 if(winnt_key) RegCloseKey(winnt_key);
2699 return;
2702 static void delete_external_font_keys(void)
2704 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2705 DWORD dlen, vlen, datalen, valuelen, i, type;
2706 LPWSTR valueW;
2707 LPVOID data;
2709 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2710 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2711 ERR("Can't create Windows font reg key\n");
2712 goto end;
2715 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2716 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2717 ERR("Can't create Windows font reg key\n");
2718 goto end;
2721 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2722 ERR("Can't create external font reg key\n");
2723 goto end;
2726 /* Delete all external fonts added last time */
2728 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2729 &valuelen, &datalen, NULL, NULL);
2730 valuelen++; /* returned value doesn't include room for '\0' */
2731 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2732 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2734 dlen = datalen * sizeof(WCHAR);
2735 vlen = valuelen;
2736 i = 0;
2737 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2738 &dlen) == ERROR_SUCCESS) {
2740 RegDeleteValueW(winnt_key, valueW);
2741 RegDeleteValueW(win9x_key, valueW);
2742 /* reset dlen and vlen */
2743 dlen = datalen;
2744 vlen = valuelen;
2746 HeapFree(GetProcessHeap(), 0, data);
2747 HeapFree(GetProcessHeap(), 0, valueW);
2749 /* Delete the old external fonts key */
2750 RegCloseKey(external_key);
2751 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2753 end:
2754 if(win9x_key) RegCloseKey(win9x_key);
2755 if(winnt_key) RegCloseKey(winnt_key);
2758 /*************************************************************
2759 * WineEngAddFontResourceEx
2762 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2764 INT ret = 0;
2766 GDI_CheckNotLock();
2768 if (ft_handle) /* do it only if we have freetype up and running */
2770 char *unixname;
2772 if(flags)
2773 FIXME("Ignoring flags %x\n", flags);
2775 if((unixname = wine_get_unix_file_name(file)))
2777 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2779 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2780 EnterCriticalSection( &freetype_cs );
2781 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2782 LeaveCriticalSection( &freetype_cs );
2783 HeapFree(GetProcessHeap(), 0, unixname);
2785 if (!ret && !strchrW(file, '\\')) {
2786 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2787 ret = load_font_from_winfonts_dir(file);
2788 if (!ret) {
2789 /* Try in datadir/fonts (or builddir/fonts),
2790 * needed for Magic the Gathering Online
2792 ret = load_font_from_data_dir(file);
2796 return ret;
2799 /*************************************************************
2800 * WineEngAddFontMemResourceEx
2803 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2805 GDI_CheckNotLock();
2807 if (ft_handle) /* do it only if we have freetype up and running */
2809 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2811 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2812 memcpy(pFontCopy, pbFont, cbFont);
2814 EnterCriticalSection( &freetype_cs );
2815 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2816 LeaveCriticalSection( &freetype_cs );
2818 if (*pcFonts == 0)
2820 TRACE("AddFontToList failed\n");
2821 HeapFree(GetProcessHeap(), 0, pFontCopy);
2822 return 0;
2824 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2825 * For now return something unique but quite random
2827 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2828 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2831 *pcFonts = 0;
2832 return 0;
2835 /*************************************************************
2836 * WineEngRemoveFontResourceEx
2839 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2841 GDI_CheckNotLock();
2842 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2843 return TRUE;
2846 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
2848 WCHAR *fullname;
2849 char *unix_name;
2850 int file_len;
2852 if (!font_file) return NULL;
2854 file_len = strlenW( font_file );
2856 if (font_path && font_path[0])
2858 int path_len = strlenW( font_path );
2859 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
2860 if (!fullname) return NULL;
2861 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
2862 fullname[path_len] = '\\';
2863 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
2865 else
2867 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
2868 if (!len) return NULL;
2869 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2870 if (!fullname) return NULL;
2871 GetFullPathNameW( font_file, len, fullname, NULL );
2874 unix_name = wine_get_unix_file_name( fullname );
2875 HeapFree( GetProcessHeap(), 0, fullname );
2876 return unix_name;
2879 #include <pshpack1.h>
2880 struct fontdir
2882 WORD num_of_resources;
2883 WORD res_id;
2884 WORD dfVersion;
2885 DWORD dfSize;
2886 CHAR dfCopyright[60];
2887 WORD dfType;
2888 WORD dfPoints;
2889 WORD dfVertRes;
2890 WORD dfHorizRes;
2891 WORD dfAscent;
2892 WORD dfInternalLeading;
2893 WORD dfExternalLeading;
2894 BYTE dfItalic;
2895 BYTE dfUnderline;
2896 BYTE dfStrikeOut;
2897 WORD dfWeight;
2898 BYTE dfCharSet;
2899 WORD dfPixWidth;
2900 WORD dfPixHeight;
2901 BYTE dfPitchAndFamily;
2902 WORD dfAvgWidth;
2903 WORD dfMaxWidth;
2904 BYTE dfFirstChar;
2905 BYTE dfLastChar;
2906 BYTE dfDefaultChar;
2907 BYTE dfBreakChar;
2908 WORD dfWidthBytes;
2909 DWORD dfDevice;
2910 DWORD dfFace;
2911 DWORD dfReserved;
2912 CHAR szFaceName[LF_FACESIZE];
2915 #include <poppack.h>
2917 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2918 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
2920 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
2922 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
2923 Face *face;
2924 Family *family;
2925 WCHAR *name, *english_name;
2926 ENUMLOGFONTEXW elf;
2927 NEWTEXTMETRICEXW ntm;
2928 DWORD type;
2930 if (!ft_face) return FALSE;
2931 face = create_face( ft_face, 0, unix_name, NULL, 0, 0, FALSE );
2932 get_family_names( ft_face, &name, &english_name, FALSE );
2933 family = create_family( name, english_name );
2934 insert_face_in_family_list( face, family );
2935 pFT_Done_Face( ft_face );
2937 GetEnumStructs( face, &elf, &ntm, &type );
2938 free_family( family );
2940 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
2942 memset( fd, 0, sizeof(*fd) );
2944 fd->num_of_resources = 1;
2945 fd->res_id = 0;
2946 fd->dfVersion = 0x200;
2947 fd->dfSize = sizeof(*fd);
2948 strcpy( fd->dfCopyright, "Wine fontdir" );
2949 fd->dfType = 0x4003; /* 0x0080 set if private */
2950 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
2951 fd->dfVertRes = 72;
2952 fd->dfHorizRes = 72;
2953 fd->dfAscent = ntm.ntmTm.tmAscent;
2954 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
2955 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
2956 fd->dfItalic = ntm.ntmTm.tmItalic;
2957 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
2958 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
2959 fd->dfWeight = ntm.ntmTm.tmWeight;
2960 fd->dfCharSet = ntm.ntmTm.tmCharSet;
2961 fd->dfPixWidth = 0;
2962 fd->dfPixHeight = ntm.ntmTm.tmHeight;
2963 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
2964 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
2965 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
2966 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
2967 fd->dfLastChar = ntm.ntmTm.tmLastChar;
2968 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
2969 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
2970 fd->dfWidthBytes = 0;
2971 fd->dfDevice = 0;
2972 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
2973 fd->dfReserved = 0;
2974 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
2976 return TRUE;
2979 #define NE_FFLAGS_LIBMODULE 0x8000
2980 #define NE_OSFLAGS_WINDOWS 0x02
2982 static const char dos_string[0x40] = "This is a TrueType resource file";
2983 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
2985 #include <pshpack2.h>
2987 struct ne_typeinfo
2989 WORD type_id;
2990 WORD count;
2991 DWORD res;
2994 struct ne_nameinfo
2996 WORD off;
2997 WORD len;
2998 WORD flags;
2999 WORD id;
3000 DWORD res;
3003 struct rsrc_tab
3005 WORD align;
3006 struct ne_typeinfo fontdir_type;
3007 struct ne_nameinfo fontdir_name;
3008 struct ne_typeinfo scalable_type;
3009 struct ne_nameinfo scalable_name;
3010 WORD end_of_rsrc;
3011 BYTE fontdir_res_name[8];
3014 #include <poppack.h>
3016 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3018 BOOL ret = FALSE;
3019 HANDLE file;
3020 DWORD size, written;
3021 BYTE *ptr, *start;
3022 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3023 char *font_fileA, *last_part, *ext;
3024 IMAGE_DOS_HEADER dos;
3025 IMAGE_OS2_HEADER ne =
3027 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3028 0, 0, 0, 0, 0, 0,
3029 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3030 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3032 struct rsrc_tab rsrc_tab =
3035 { 0x8007, 1, 0 },
3036 { 0, 0, 0x0c50, 0x2c, 0 },
3037 { 0x80cc, 1, 0 },
3038 { 0, 0, 0x0c50, 0x8001, 0 },
3040 { 7,'F','O','N','T','D','I','R'}
3043 memset( &dos, 0, sizeof(dos) );
3044 dos.e_magic = IMAGE_DOS_SIGNATURE;
3045 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3047 /* import name is last part\0, resident name is last part without extension
3048 non-resident name is "FONTRES:" + lfFaceName */
3050 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3051 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3052 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3054 last_part = strrchr( font_fileA, '\\' );
3055 if (last_part) last_part++;
3056 else last_part = font_fileA;
3057 import_name_len = strlen( last_part ) + 1;
3059 ext = strchr( last_part, '.' );
3060 if (ext) res_name_len = ext - last_part;
3061 else res_name_len = import_name_len - 1;
3063 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3065 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3066 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3067 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3068 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3069 ne.ne_cbenttab = 2;
3070 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3072 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3073 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3074 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3075 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3077 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3078 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3080 if (!ptr)
3082 HeapFree( GetProcessHeap(), 0, font_fileA );
3083 return FALSE;
3086 memcpy( ptr, &dos, sizeof(dos) );
3087 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3088 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3090 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3091 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3093 ptr = start + dos.e_lfanew + ne.ne_restab;
3094 *ptr++ = res_name_len;
3095 memcpy( ptr, last_part, res_name_len );
3097 ptr = start + dos.e_lfanew + ne.ne_imptab;
3098 *ptr++ = import_name_len;
3099 memcpy( ptr, last_part, import_name_len );
3101 ptr = start + ne.ne_nrestab;
3102 *ptr++ = non_res_name_len;
3103 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3104 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3106 ptr = start + (rsrc_tab.scalable_name.off << 4);
3107 memcpy( ptr, font_fileA, font_file_len );
3109 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3110 memcpy( ptr, fontdir, fontdir->dfSize );
3112 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3113 if (file != INVALID_HANDLE_VALUE)
3115 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3116 ret = TRUE;
3117 CloseHandle( file );
3120 HeapFree( GetProcessHeap(), 0, start );
3121 HeapFree( GetProcessHeap(), 0, font_fileA );
3123 return ret;
3126 /*************************************************************
3127 * WineEngCreateScalableFontResource
3130 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3131 LPCWSTR font_file, LPCWSTR font_path )
3133 char *unix_name = get_ttf_file_name( font_file, font_path );
3134 struct fontdir fontdir;
3135 BOOL ret = FALSE;
3137 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3138 SetLastError( ERROR_INVALID_PARAMETER );
3139 else
3141 if (hidden) fontdir.dfType |= 0x80;
3142 ret = create_fot( resource, font_file, &fontdir );
3145 HeapFree( GetProcessHeap(), 0, unix_name );
3146 return ret;
3149 static const struct nls_update_font_list
3151 UINT ansi_cp, oem_cp;
3152 const char *oem, *fixed, *system;
3153 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3154 /* these are for font substitutes */
3155 const char *shelldlg, *tmsrmn;
3156 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3157 *helv_0, *tmsrmn_0;
3158 const struct subst
3160 const char *from, *to;
3161 } arial_0, courier_new_0, times_new_roman_0;
3162 } nls_update_font_list[] =
3164 /* Latin 1 (United States) */
3165 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3166 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3167 "Tahoma","Times New Roman",
3168 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3169 { 0 }, { 0 }, { 0 }
3171 /* Latin 1 (Multilingual) */
3172 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3173 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3174 "Tahoma","Times New Roman", /* FIXME unverified */
3175 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3176 { 0 }, { 0 }, { 0 }
3178 /* Eastern Europe */
3179 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3180 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3181 "Tahoma","Times New Roman", /* FIXME unverified */
3182 "Fixedsys,238", "System,238",
3183 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3184 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3185 { "Arial CE,0", "Arial,238" },
3186 { "Courier New CE,0", "Courier New,238" },
3187 { "Times New Roman CE,0", "Times New Roman,238" }
3189 /* Cyrillic */
3190 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3191 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3192 "Tahoma","Times New Roman", /* FIXME unverified */
3193 "Fixedsys,204", "System,204",
3194 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3195 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3196 { "Arial Cyr,0", "Arial,204" },
3197 { "Courier New Cyr,0", "Courier New,204" },
3198 { "Times New Roman Cyr,0", "Times New Roman,204" }
3200 /* Greek */
3201 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3202 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3203 "Tahoma","Times New Roman", /* FIXME unverified */
3204 "Fixedsys,161", "System,161",
3205 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3206 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3207 { "Arial Greek,0", "Arial,161" },
3208 { "Courier New Greek,0", "Courier New,161" },
3209 { "Times New Roman Greek,0", "Times New Roman,161" }
3211 /* Turkish */
3212 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3213 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3214 "Tahoma","Times New Roman", /* FIXME unverified */
3215 "Fixedsys,162", "System,162",
3216 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3217 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3218 { "Arial Tur,0", "Arial,162" },
3219 { "Courier New Tur,0", "Courier New,162" },
3220 { "Times New Roman Tur,0", "Times New Roman,162" }
3222 /* Hebrew */
3223 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3224 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3225 "Tahoma","Times New Roman", /* FIXME unverified */
3226 "Fixedsys,177", "System,177",
3227 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3228 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3229 { 0 }, { 0 }, { 0 }
3231 /* Arabic */
3232 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3233 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3234 "Tahoma","Times New Roman", /* FIXME unverified */
3235 "Fixedsys,178", "System,178",
3236 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3237 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3238 { 0 }, { 0 }, { 0 }
3240 /* Baltic */
3241 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3242 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3243 "Tahoma","Times New Roman", /* FIXME unverified */
3244 "Fixedsys,186", "System,186",
3245 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3246 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3247 { "Arial Baltic,0", "Arial,186" },
3248 { "Courier New Baltic,0", "Courier New,186" },
3249 { "Times New Roman Baltic,0", "Times New Roman,186" }
3251 /* Vietnamese */
3252 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3253 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3254 "Tahoma","Times New Roman", /* FIXME unverified */
3255 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3256 { 0 }, { 0 }, { 0 }
3258 /* Thai */
3259 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3260 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3261 "Tahoma","Times New Roman", /* FIXME unverified */
3262 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3263 { 0 }, { 0 }, { 0 }
3265 /* Japanese */
3266 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3267 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3268 "MS UI Gothic","MS Serif",
3269 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3270 { 0 }, { 0 }, { 0 }
3272 /* Chinese Simplified */
3273 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3274 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3275 "SimSun", "NSimSun",
3276 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3277 { 0 }, { 0 }, { 0 }
3279 /* Korean */
3280 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3281 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3282 "Gulim", "Batang",
3283 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3284 { 0 }, { 0 }, { 0 }
3286 /* Chinese Traditional */
3287 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3288 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3289 "PMingLiU", "MingLiU",
3290 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3291 { 0 }, { 0 }, { 0 }
3295 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3297 return ( ansi_cp == 932 /* CP932 for Japanese */
3298 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3299 || ansi_cp == 949 /* CP949 for Korean */
3300 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3303 static inline HKEY create_fonts_NT_registry_key(void)
3305 HKEY hkey = 0;
3307 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3308 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3309 return hkey;
3312 static inline HKEY create_fonts_9x_registry_key(void)
3314 HKEY hkey = 0;
3316 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3317 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3318 return hkey;
3321 static inline HKEY create_config_fonts_registry_key(void)
3323 HKEY hkey = 0;
3325 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3326 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3327 return hkey;
3330 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3332 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3334 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3335 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3336 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3337 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3340 static void set_value_key(HKEY hkey, const char *name, const char *value)
3342 if (value)
3343 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3344 else if (name)
3345 RegDeleteValueA(hkey, name);
3348 static void update_font_info(void)
3350 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3351 char buf[40], cpbuf[40];
3352 DWORD len, type;
3353 HKEY hkey = 0;
3354 UINT i, ansi_cp = 0, oem_cp = 0;
3355 DWORD screen_dpi = 96, font_dpi = 0;
3356 BOOL done = FALSE;
3358 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3359 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3360 &hkey) == ERROR_SUCCESS)
3362 reg_load_dword(hkey, logpixels, &screen_dpi);
3363 RegCloseKey(hkey);
3366 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3367 return;
3369 reg_load_dword(hkey, logpixels, &font_dpi);
3371 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3372 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3373 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3374 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3375 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3377 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3378 if (is_dbcs_ansi_cp(ansi_cp))
3379 use_default_fallback = TRUE;
3381 len = sizeof(buf);
3382 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3384 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3386 RegCloseKey(hkey);
3387 return;
3389 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3390 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3392 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3393 ansi_cp, oem_cp, screen_dpi);
3395 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3396 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3397 RegCloseKey(hkey);
3399 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3401 HKEY hkey;
3403 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3404 nls_update_font_list[i].oem_cp == oem_cp)
3406 hkey = create_config_fonts_registry_key();
3407 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3408 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3409 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3410 RegCloseKey(hkey);
3412 hkey = create_fonts_NT_registry_key();
3413 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3414 RegCloseKey(hkey);
3416 hkey = create_fonts_9x_registry_key();
3417 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3418 RegCloseKey(hkey);
3420 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3422 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3423 strlen(nls_update_font_list[i].shelldlg)+1);
3424 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3425 strlen(nls_update_font_list[i].tmsrmn)+1);
3427 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3428 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3429 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3430 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3431 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3432 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3433 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3434 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3436 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3437 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3438 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3440 RegCloseKey(hkey);
3442 done = TRUE;
3444 else
3446 /* Delete the FontSubstitutes from other locales */
3447 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3449 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3450 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3451 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3452 RegCloseKey(hkey);
3456 if (!done)
3457 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3460 static BOOL init_freetype(void)
3462 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3463 if(!ft_handle) {
3464 WINE_MESSAGE(
3465 "Wine cannot find the FreeType font library. To enable Wine to\n"
3466 "use TrueType fonts please install a version of FreeType greater than\n"
3467 "or equal to 2.0.5.\n"
3468 "http://www.freetype.org\n");
3469 return FALSE;
3472 #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;}
3474 LOAD_FUNCPTR(FT_Done_Face)
3475 LOAD_FUNCPTR(FT_Get_Char_Index)
3476 LOAD_FUNCPTR(FT_Get_First_Char)
3477 LOAD_FUNCPTR(FT_Get_Module)
3478 LOAD_FUNCPTR(FT_Get_Next_Char)
3479 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3480 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3481 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3482 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3483 LOAD_FUNCPTR(FT_Init_FreeType)
3484 LOAD_FUNCPTR(FT_Library_Version)
3485 LOAD_FUNCPTR(FT_Load_Glyph)
3486 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3487 LOAD_FUNCPTR(FT_Matrix_Multiply)
3488 #ifndef FT_MULFIX_INLINED
3489 LOAD_FUNCPTR(FT_MulFix)
3490 #endif
3491 LOAD_FUNCPTR(FT_New_Face)
3492 LOAD_FUNCPTR(FT_New_Memory_Face)
3493 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3494 LOAD_FUNCPTR(FT_Outline_Transform)
3495 LOAD_FUNCPTR(FT_Outline_Translate)
3496 LOAD_FUNCPTR(FT_Render_Glyph)
3497 LOAD_FUNCPTR(FT_Select_Charmap)
3498 LOAD_FUNCPTR(FT_Set_Charmap)
3499 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3500 LOAD_FUNCPTR(FT_Vector_Transform)
3501 LOAD_FUNCPTR(FT_Vector_Unit)
3502 #undef LOAD_FUNCPTR
3503 /* Don't warn if these ones are missing */
3504 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3505 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3506 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3507 #endif
3509 if(pFT_Init_FreeType(&library) != 0) {
3510 ERR("Can't init FreeType library\n");
3511 wine_dlclose(ft_handle, NULL, 0);
3512 ft_handle = NULL;
3513 return FALSE;
3515 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3517 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3518 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3519 ((FT_Version.minor << 8) & 0x00ff00) |
3520 ((FT_Version.patch ) & 0x0000ff);
3522 font_driver = &freetype_funcs;
3523 return TRUE;
3525 sym_not_found:
3526 WINE_MESSAGE(
3527 "Wine cannot find certain functions that it needs inside the FreeType\n"
3528 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3529 "FreeType to at least version 2.1.4.\n"
3530 "http://www.freetype.org\n");
3531 wine_dlclose(ft_handle, NULL, 0);
3532 ft_handle = NULL;
3533 return FALSE;
3536 static void init_font_list(void)
3538 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3539 static const WCHAR pathW[] = {'P','a','t','h',0};
3540 HKEY hkey;
3541 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3542 WCHAR windowsdir[MAX_PATH];
3543 char *unixname;
3544 const char *data_dir;
3546 delete_external_font_keys();
3548 /* load the system bitmap fonts */
3549 load_system_fonts();
3551 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3552 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3553 strcatW(windowsdir, fontsW);
3554 if((unixname = wine_get_unix_file_name(windowsdir)))
3556 ReadFontDir(unixname, FALSE);
3557 HeapFree(GetProcessHeap(), 0, unixname);
3560 /* load the system truetype fonts */
3561 data_dir = wine_get_data_dir();
3562 if (!data_dir) data_dir = wine_get_build_dir();
3563 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3565 strcpy(unixname, data_dir);
3566 strcat(unixname, "/fonts/");
3567 ReadFontDir(unixname, TRUE);
3568 HeapFree(GetProcessHeap(), 0, unixname);
3571 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3572 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3573 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3574 will skip these. */
3575 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3576 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3577 &hkey) == ERROR_SUCCESS)
3579 LPWSTR data, valueW;
3580 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3581 &valuelen, &datalen, NULL, NULL);
3583 valuelen++; /* returned value doesn't include room for '\0' */
3584 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3585 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3586 if (valueW && data)
3588 dlen = datalen * sizeof(WCHAR);
3589 vlen = valuelen;
3590 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3591 &dlen) == ERROR_SUCCESS)
3593 if(data[0] && (data[1] == ':'))
3595 if((unixname = wine_get_unix_file_name(data)))
3597 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3598 HeapFree(GetProcessHeap(), 0, unixname);
3601 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3603 WCHAR pathW[MAX_PATH];
3604 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3605 BOOL added = FALSE;
3607 sprintfW(pathW, fmtW, windowsdir, data);
3608 if((unixname = wine_get_unix_file_name(pathW)))
3610 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3611 HeapFree(GetProcessHeap(), 0, unixname);
3613 if (!added)
3614 load_font_from_data_dir(data);
3616 /* reset dlen and vlen */
3617 dlen = datalen;
3618 vlen = valuelen;
3621 HeapFree(GetProcessHeap(), 0, data);
3622 HeapFree(GetProcessHeap(), 0, valueW);
3623 RegCloseKey(hkey);
3626 #ifdef SONAME_LIBFONTCONFIG
3627 load_fontconfig_fonts();
3628 #elif defined(HAVE_CARBON_CARBON_H)
3629 load_mac_fonts();
3630 #endif
3632 /* then look in any directories that we've specified in the config file */
3633 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3634 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3636 DWORD len;
3637 LPWSTR valueW;
3638 LPSTR valueA, ptr;
3640 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3642 len += sizeof(WCHAR);
3643 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3644 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3646 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3647 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3648 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3649 TRACE( "got font path %s\n", debugstr_a(valueA) );
3650 ptr = valueA;
3651 while (ptr)
3653 const char* home;
3654 LPSTR next = strchr( ptr, ':' );
3655 if (next) *next++ = 0;
3656 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3657 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3659 strcpy( unixname, home );
3660 strcat( unixname, ptr + 1 );
3661 ReadFontDir( unixname, TRUE );
3662 HeapFree( GetProcessHeap(), 0, unixname );
3664 else
3665 ReadFontDir( ptr, TRUE );
3666 ptr = next;
3668 HeapFree( GetProcessHeap(), 0, valueA );
3670 HeapFree( GetProcessHeap(), 0, valueW );
3672 RegCloseKey(hkey);
3676 static BOOL move_to_front(const WCHAR *name)
3678 Family *family, *cursor2;
3679 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3681 if(!strcmpiW(family->FamilyName, name))
3683 list_remove(&family->entry);
3684 list_add_head(&font_list, &family->entry);
3685 return TRUE;
3688 return FALSE;
3691 static BOOL set_default(const WCHAR **name_list)
3693 while (*name_list)
3695 if (move_to_front(*name_list)) return TRUE;
3696 name_list++;
3699 return FALSE;
3702 static void reorder_font_list(void)
3704 set_default( default_serif_list );
3705 set_default( default_fixed_list );
3706 set_default( default_sans_list );
3709 /*************************************************************
3710 * WineEngInit
3712 * Initialize FreeType library and create a list of available faces
3714 BOOL WineEngInit(void)
3716 HKEY hkey_font_cache;
3717 DWORD disposition;
3718 HANDLE font_mutex;
3720 /* update locale dependent font info in registry */
3721 update_font_info();
3723 if(!init_freetype()) return FALSE;
3725 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3727 ERR("Failed to create font mutex\n");
3728 return FALSE;
3730 WaitForSingleObject(font_mutex, INFINITE);
3732 create_font_cache_key(&hkey_font_cache, &disposition);
3734 if(disposition == REG_CREATED_NEW_KEY)
3735 init_font_list();
3736 else
3737 load_font_list_from_cache(hkey_font_cache);
3739 RegCloseKey(hkey_font_cache);
3741 reorder_font_list();
3743 DumpFontList();
3744 LoadSubstList();
3745 DumpSubstList();
3746 LoadReplaceList();
3748 if(disposition == REG_CREATED_NEW_KEY)
3749 update_reg_entries();
3751 init_system_links();
3753 ReleaseMutex(font_mutex);
3754 return TRUE;
3758 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3760 TT_OS2 *pOS2;
3761 TT_HoriHeader *pHori;
3763 LONG ppem;
3765 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3766 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3768 if(height == 0) height = 16;
3770 /* Calc. height of EM square:
3772 * For +ve lfHeight we have
3773 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3774 * Re-arranging gives:
3775 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3777 * For -ve lfHeight we have
3778 * |lfHeight| = ppem
3779 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3780 * with il = winAscent + winDescent - units_per_em]
3784 if(height > 0) {
3785 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3786 ppem = MulDiv(ft_face->units_per_EM, height,
3787 pHori->Ascender - pHori->Descender);
3788 else
3789 ppem = MulDiv(ft_face->units_per_EM, height,
3790 pOS2->usWinAscent + pOS2->usWinDescent);
3792 else
3793 ppem = -height;
3795 return ppem;
3798 static struct font_mapping *map_font_file( const char *name )
3800 struct font_mapping *mapping;
3801 struct stat st;
3802 int fd;
3804 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3805 if (fstat( fd, &st ) == -1) goto error;
3807 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3809 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3811 mapping->refcount++;
3812 close( fd );
3813 return mapping;
3816 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3817 goto error;
3819 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3820 close( fd );
3822 if (mapping->data == MAP_FAILED)
3824 HeapFree( GetProcessHeap(), 0, mapping );
3825 return NULL;
3827 mapping->refcount = 1;
3828 mapping->dev = st.st_dev;
3829 mapping->ino = st.st_ino;
3830 mapping->size = st.st_size;
3831 list_add_tail( &mappings_list, &mapping->entry );
3832 return mapping;
3834 error:
3835 close( fd );
3836 return NULL;
3839 static void unmap_font_file( struct font_mapping *mapping )
3841 if (!--mapping->refcount)
3843 list_remove( &mapping->entry );
3844 munmap( mapping->data, mapping->size );
3845 HeapFree( GetProcessHeap(), 0, mapping );
3849 static LONG load_VDMX(GdiFont*, LONG);
3851 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3853 FT_Error err;
3854 FT_Face ft_face;
3855 void *data_ptr;
3856 DWORD data_size;
3858 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3860 if (face->file)
3862 if (!(font->mapping = map_font_file( face->file )))
3864 WARN("failed to map %s\n", debugstr_a(face->file));
3865 return 0;
3867 data_ptr = font->mapping->data;
3868 data_size = font->mapping->size;
3870 else
3872 data_ptr = face->font_data_ptr;
3873 data_size = face->font_data_size;
3876 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3877 if(err) {
3878 ERR("FT_New_Face rets %d\n", err);
3879 return 0;
3882 /* set it here, as load_VDMX needs it */
3883 font->ft_face = ft_face;
3885 if(FT_IS_SCALABLE(ft_face)) {
3886 /* load the VDMX table if we have one */
3887 font->ppem = load_VDMX(font, height);
3888 if(font->ppem == 0)
3889 font->ppem = calc_ppem_for_height(ft_face, height);
3890 TRACE("height %d => ppem %d\n", height, font->ppem);
3892 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3893 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3894 } else {
3895 font->ppem = height;
3896 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3897 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3899 return ft_face;
3903 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3905 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3906 a single face with the requested charset. The idea is to check if
3907 the selected font supports the current ANSI codepage, if it does
3908 return the corresponding charset, else return the first charset */
3910 CHARSETINFO csi;
3911 int acp = GetACP(), i;
3912 DWORD fs0;
3914 *cp = acp;
3915 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3917 const SYSTEM_LINKS *font_link;
3919 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
3920 return csi.ciCharset;
3922 font_link = find_font_link(family_name);
3923 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
3924 return csi.ciCharset;
3927 for(i = 0; i < 32; i++) {
3928 fs0 = 1L << i;
3929 if(face->fs.fsCsb[0] & fs0) {
3930 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3931 *cp = csi.ciACP;
3932 return csi.ciCharset;
3934 else
3935 FIXME("TCI failing on %x\n", fs0);
3939 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3940 face->fs.fsCsb[0], face->file);
3941 *cp = acp;
3942 return DEFAULT_CHARSET;
3945 static GdiFont *alloc_font(void)
3947 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3948 ret->gmsize = 1;
3949 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3950 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3951 ret->potm = NULL;
3952 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3953 ret->total_kern_pairs = (DWORD)-1;
3954 ret->kern_pairs = NULL;
3955 list_init(&ret->hfontlist);
3956 list_init(&ret->child_fonts);
3957 return ret;
3960 static void free_font(GdiFont *font)
3962 struct list *cursor, *cursor2;
3963 DWORD i;
3965 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3967 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3968 list_remove(cursor);
3969 if(child->font)
3970 free_font(child->font);
3971 HeapFree(GetProcessHeap(), 0, child);
3974 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3976 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3977 DeleteObject(hfontlist->hfont);
3978 list_remove(&hfontlist->entry);
3979 HeapFree(GetProcessHeap(), 0, hfontlist);
3982 if (font->ft_face) pFT_Done_Face(font->ft_face);
3983 if (font->mapping) unmap_font_file( font->mapping );
3984 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3985 HeapFree(GetProcessHeap(), 0, font->potm);
3986 HeapFree(GetProcessHeap(), 0, font->name);
3987 for (i = 0; i < font->gmsize; i++)
3988 HeapFree(GetProcessHeap(),0,font->gm[i]);
3989 HeapFree(GetProcessHeap(), 0, font->gm);
3990 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3991 HeapFree(GetProcessHeap(), 0, font);
3995 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3997 FT_Face ft_face = font->ft_face;
3998 FT_ULong len;
3999 FT_Error err;
4001 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4003 if(!buf)
4004 len = 0;
4005 else
4006 len = cbData;
4008 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4010 /* make sure value of len is the value freetype says it needs */
4011 if (buf && len)
4013 FT_ULong needed = 0;
4014 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4015 if( !err && needed < len) len = needed;
4017 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4018 if (err)
4020 TRACE("Can't find table %c%c%c%c\n",
4021 /* bytes were reversed */
4022 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4023 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4024 return GDI_ERROR;
4026 return len;
4029 /*************************************************************
4030 * load_VDMX
4032 * load the vdmx entry for the specified height
4035 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4036 ( ( (FT_ULong)_x4 << 24 ) | \
4037 ( (FT_ULong)_x3 << 16 ) | \
4038 ( (FT_ULong)_x2 << 8 ) | \
4039 (FT_ULong)_x1 )
4041 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4043 typedef struct {
4044 BYTE bCharSet;
4045 BYTE xRatio;
4046 BYTE yStartRatio;
4047 BYTE yEndRatio;
4048 } Ratios;
4050 typedef struct {
4051 WORD recs;
4052 BYTE startsz;
4053 BYTE endsz;
4054 } VDMX_group;
4056 static LONG load_VDMX(GdiFont *font, LONG height)
4058 WORD hdr[3], tmp;
4059 VDMX_group group;
4060 BYTE devXRatio, devYRatio;
4061 USHORT numRecs, numRatios;
4062 DWORD result, offset = -1;
4063 LONG ppem = 0;
4064 int i;
4066 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
4068 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4069 return ppem;
4071 /* FIXME: need the real device aspect ratio */
4072 devXRatio = 1;
4073 devYRatio = 1;
4075 numRecs = GET_BE_WORD(hdr[1]);
4076 numRatios = GET_BE_WORD(hdr[2]);
4078 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4079 for(i = 0; i < numRatios; i++) {
4080 Ratios ratio;
4082 offset = (3 * 2) + (i * sizeof(Ratios));
4083 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4084 offset = -1;
4086 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4088 if((ratio.xRatio == 0 &&
4089 ratio.yStartRatio == 0 &&
4090 ratio.yEndRatio == 0) ||
4091 (devXRatio == ratio.xRatio &&
4092 devYRatio >= ratio.yStartRatio &&
4093 devYRatio <= ratio.yEndRatio))
4095 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4096 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4097 offset = GET_BE_WORD(tmp);
4098 break;
4102 if(offset == -1) {
4103 FIXME("No suitable ratio found\n");
4104 return ppem;
4107 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4108 USHORT recs;
4109 BYTE startsz, endsz;
4110 WORD *vTable;
4112 recs = GET_BE_WORD(group.recs);
4113 startsz = group.startsz;
4114 endsz = group.endsz;
4116 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4118 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4119 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4120 if(result == GDI_ERROR) {
4121 FIXME("Failed to retrieve vTable\n");
4122 goto end;
4125 if(height > 0) {
4126 for(i = 0; i < recs; i++) {
4127 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4128 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4129 ppem = GET_BE_WORD(vTable[i * 3]);
4131 if(yMax + -yMin == height) {
4132 font->yMax = yMax;
4133 font->yMin = yMin;
4134 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4135 break;
4137 if(yMax + -yMin > height) {
4138 if(--i < 0) {
4139 ppem = 0;
4140 goto end; /* failed */
4142 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4143 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4144 ppem = GET_BE_WORD(vTable[i * 3]);
4145 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4146 break;
4149 if(!font->yMax) {
4150 ppem = 0;
4151 TRACE("ppem not found for height %d\n", height);
4154 end:
4155 HeapFree(GetProcessHeap(), 0, vTable);
4158 return ppem;
4161 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4163 if(font->font_desc.hash != fd->hash) return TRUE;
4164 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4165 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4166 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4167 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4170 static void calc_hash(FONT_DESC *pfd)
4172 DWORD hash = 0, *ptr, two_chars;
4173 WORD *pwc;
4174 unsigned int i;
4176 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4177 hash ^= *ptr;
4178 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4179 hash ^= *ptr;
4180 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4181 two_chars = *ptr;
4182 pwc = (WCHAR *)&two_chars;
4183 if(!*pwc) break;
4184 *pwc = toupperW(*pwc);
4185 pwc++;
4186 *pwc = toupperW(*pwc);
4187 hash ^= two_chars;
4188 if(!*pwc) break;
4190 hash ^= !pfd->can_use_bitmap;
4191 pfd->hash = hash;
4192 return;
4195 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4197 GdiFont *ret;
4198 FONT_DESC fd;
4199 HFONTLIST *hflist;
4200 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4202 fd.lf = *plf;
4203 fd.matrix = *pmat;
4204 fd.can_use_bitmap = can_use_bitmap;
4205 calc_hash(&fd);
4207 /* try the child list */
4208 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
4209 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4210 if(!fontcmp(ret, &fd)) {
4211 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4212 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4213 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4214 if(hflist->hfont == hfont)
4215 return ret;
4220 /* try the in-use list */
4221 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
4222 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4223 if(!fontcmp(ret, &fd)) {
4224 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4225 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4226 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4227 if(hflist->hfont == hfont)
4228 return ret;
4230 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4231 hflist->hfont = hfont;
4232 list_add_head(&ret->hfontlist, &hflist->entry);
4233 return ret;
4237 /* then the unused list */
4238 font_elem_ptr = list_head(&unused_gdi_font_list);
4239 while(font_elem_ptr) {
4240 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4241 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4242 if(!fontcmp(ret, &fd)) {
4243 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4244 assert(list_empty(&ret->hfontlist));
4245 TRACE("Found %p in unused list\n", ret);
4246 list_remove(&ret->entry);
4247 list_add_head(&gdi_font_list, &ret->entry);
4248 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4249 hflist->hfont = hfont;
4250 list_add_head(&ret->hfontlist, &hflist->entry);
4251 return ret;
4254 return NULL;
4257 static void add_to_cache(GdiFont *font)
4259 static DWORD cache_num = 1;
4261 font->cache_num = cache_num++;
4262 list_add_head(&gdi_font_list, &font->entry);
4265 /*************************************************************
4266 * create_child_font_list
4268 static BOOL create_child_font_list(GdiFont *font)
4270 BOOL ret = FALSE;
4271 SYSTEM_LINKS *font_link;
4272 CHILD_FONT *font_link_entry, *new_child;
4273 FontSubst *psub;
4274 WCHAR* font_name;
4276 psub = get_font_subst(&font_subst_list, font->name, -1);
4277 font_name = psub ? psub->to.name : font->name;
4278 font_link = find_font_link(font_name);
4279 if (font_link != NULL)
4281 TRACE("found entry in system list\n");
4282 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4284 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4285 new_child->face = font_link_entry->face;
4286 new_child->font = NULL;
4287 list_add_tail(&font->child_fonts, &new_child->entry);
4288 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
4290 ret = TRUE;
4293 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4294 * Sans Serif. This is how asian windows get default fallbacks for fonts
4296 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4297 font->charset != OEM_CHARSET &&
4298 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4300 font_link = find_font_link(szDefaultFallbackLink);
4301 if (font_link != NULL)
4303 TRACE("found entry in default fallback list\n");
4304 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4306 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4307 new_child->face = font_link_entry->face;
4308 new_child->font = NULL;
4309 list_add_tail(&font->child_fonts, &new_child->entry);
4310 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
4312 ret = TRUE;
4316 return ret;
4319 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4321 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4323 if (pFT_Set_Charmap)
4325 FT_Int i;
4326 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4328 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4330 for (i = 0; i < ft_face->num_charmaps; i++)
4332 if (ft_face->charmaps[i]->encoding == encoding)
4334 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4335 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4337 switch (ft_face->charmaps[i]->platform_id)
4339 default:
4340 cmap_def = ft_face->charmaps[i];
4341 break;
4342 case 0: /* Apple Unicode */
4343 cmap0 = ft_face->charmaps[i];
4344 break;
4345 case 1: /* Macintosh */
4346 cmap1 = ft_face->charmaps[i];
4347 break;
4348 case 2: /* ISO */
4349 cmap2 = ft_face->charmaps[i];
4350 break;
4351 case 3: /* Microsoft */
4352 cmap3 = ft_face->charmaps[i];
4353 break;
4357 if (cmap3) /* prefer Microsoft cmap table */
4358 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4359 else if (cmap1)
4360 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4361 else if (cmap2)
4362 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4363 else if (cmap0)
4364 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4365 else if (cmap_def)
4366 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4368 return ft_err == FT_Err_Ok;
4371 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4375 /*************************************************************
4376 * freetype_CreateDC
4378 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4379 LPCWSTR output, const DEVMODEW *devmode )
4381 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4383 if (!physdev) return FALSE;
4384 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4385 return TRUE;
4389 /*************************************************************
4390 * freetype_DeleteDC
4392 static BOOL freetype_DeleteDC( PHYSDEV dev )
4394 struct freetype_physdev *physdev = get_freetype_dev( dev );
4395 HeapFree( GetProcessHeap(), 0, physdev );
4396 return TRUE;
4400 /*************************************************************
4401 * freetype_SelectFont
4403 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
4405 struct freetype_physdev *physdev = get_freetype_dev( dev );
4406 GdiFont *ret;
4407 Face *face, *best, *best_bitmap;
4408 Family *family, *last_resort_family;
4409 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
4410 INT height, width = 0;
4411 unsigned int score = 0, new_score;
4412 signed int diff = 0, newdiff;
4413 BOOL bd, it, can_use_bitmap, want_vertical;
4414 LOGFONTW lf;
4415 CHARSETINFO csi;
4416 HFONTLIST *hflist;
4417 FMAT2 dcmat;
4418 FontSubst *psub = NULL;
4419 DC *dc = get_dc_ptr( dev->hdc );
4420 const SYSTEM_LINKS *font_link;
4422 if (!hfont) /* notification that the font has been changed by another driver */
4424 dc->gdiFont = NULL;
4425 physdev->font = NULL;
4426 release_dc_ptr( dc );
4427 return 0;
4430 GetObjectW( hfont, sizeof(lf), &lf );
4431 lf.lfWidth = abs(lf.lfWidth);
4433 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4435 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4436 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4437 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4438 lf.lfEscapement);
4440 if(dc->GraphicsMode == GM_ADVANCED)
4442 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4443 /* Try to avoid not necessary glyph transformations */
4444 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4446 lf.lfHeight *= fabs(dcmat.eM11);
4447 lf.lfWidth *= fabs(dcmat.eM11);
4448 dcmat.eM11 = dcmat.eM22 = 1.0;
4451 else
4453 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4454 font scaling abilities. */
4455 dcmat.eM11 = dcmat.eM22 = 1.0;
4456 dcmat.eM21 = dcmat.eM12 = 0;
4457 if (dc->vport2WorldValid)
4459 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4460 lf.lfOrientation = -lf.lfOrientation;
4461 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4462 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4466 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4467 dcmat.eM21, dcmat.eM22);
4469 GDI_CheckNotLock();
4470 EnterCriticalSection( &freetype_cs );
4472 /* check the cache first */
4473 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4474 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4475 goto done;
4478 if(list_empty(&font_list)) /* No fonts installed */
4480 TRACE("No fonts installed\n");
4481 goto done;
4484 TRACE("not in cache\n");
4485 ret = alloc_font();
4487 ret->font_desc.matrix = dcmat;
4488 ret->font_desc.lf = lf;
4489 ret->font_desc.can_use_bitmap = can_use_bitmap;
4490 calc_hash(&ret->font_desc);
4491 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4492 hflist->hfont = hfont;
4493 list_add_head(&ret->hfontlist, &hflist->entry);
4495 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4496 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4497 original value lfCharSet. Note this is a special case for
4498 Symbol and doesn't happen at least for "Wingdings*" */
4500 if(!strcmpiW(lf.lfFaceName, SymbolW))
4501 lf.lfCharSet = SYMBOL_CHARSET;
4503 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4504 switch(lf.lfCharSet) {
4505 case DEFAULT_CHARSET:
4506 csi.fs.fsCsb[0] = 0;
4507 break;
4508 default:
4509 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4510 csi.fs.fsCsb[0] = 0;
4511 break;
4515 family = NULL;
4516 if(lf.lfFaceName[0] != '\0') {
4517 CHILD_FONT *font_link_entry;
4518 LPWSTR FaceName = lf.lfFaceName;
4520 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4522 if(psub) {
4523 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4524 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4525 if (psub->to.charset != -1)
4526 lf.lfCharSet = psub->to.charset;
4529 /* We want a match on name and charset or just name if
4530 charset was DEFAULT_CHARSET. If the latter then
4531 we fixup the returned charset later in get_nearest_charset
4532 where we'll either use the charset of the current ansi codepage
4533 or if that's unavailable the first charset that the font supports.
4535 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4536 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4537 if (!strcmpiW(family->FamilyName, FaceName) ||
4538 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4540 font_link = find_font_link(family->FamilyName);
4541 face_list = get_face_list_from_family(family);
4542 LIST_FOR_EACH(face_elem_ptr, face_list) {
4543 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4544 if (!(face->scalable || can_use_bitmap))
4545 continue;
4546 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4547 goto found;
4548 if (font_link != NULL &&
4549 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4550 goto found;
4551 if (!csi.fs.fsCsb[0])
4552 goto found;
4557 /* Search by full face name. */
4558 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4559 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4560 face_list = get_face_list_from_family(family);
4561 LIST_FOR_EACH(face_elem_ptr, face_list) {
4562 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4563 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4564 (face->scalable || can_use_bitmap))
4566 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4567 goto found_face;
4568 font_link = find_font_link(family->FamilyName);
4569 if (font_link != NULL &&
4570 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4571 goto found_face;
4577 * Try check the SystemLink list first for a replacement font.
4578 * We may find good replacements there.
4580 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4582 if(!strcmpiW(font_link->font_name, FaceName) ||
4583 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4585 TRACE("found entry in system list\n");
4586 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4588 const SYSTEM_LINKS *links;
4590 face = font_link_entry->face;
4591 if (!(face->scalable || can_use_bitmap))
4592 continue;
4593 family = face->family;
4594 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4595 goto found;
4596 links = find_font_link(family->FamilyName);
4597 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4598 goto found;
4604 psub = NULL; /* substitution is no more relevant */
4606 /* If requested charset was DEFAULT_CHARSET then try using charset
4607 corresponding to the current ansi codepage */
4608 if (!csi.fs.fsCsb[0])
4610 INT acp = GetACP();
4611 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4612 FIXME("TCI failed on codepage %d\n", acp);
4613 csi.fs.fsCsb[0] = 0;
4614 } else
4615 lf.lfCharSet = csi.ciCharset;
4618 want_vertical = (lf.lfFaceName[0] == '@');
4620 /* Face families are in the top 4 bits of lfPitchAndFamily,
4621 so mask with 0xF0 before testing */
4623 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4624 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4625 strcpyW(lf.lfFaceName, defFixed);
4626 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4627 strcpyW(lf.lfFaceName, defSerif);
4628 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4629 strcpyW(lf.lfFaceName, defSans);
4630 else
4631 strcpyW(lf.lfFaceName, defSans);
4632 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4633 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4634 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4635 font_link = find_font_link(family->FamilyName);
4636 face_list = get_face_list_from_family(family);
4637 LIST_FOR_EACH(face_elem_ptr, face_list) {
4638 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4639 if (!(face->scalable || can_use_bitmap))
4640 continue;
4641 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4642 goto found;
4643 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4644 goto found;
4649 last_resort_family = NULL;
4650 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4651 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4652 font_link = find_font_link(family->FamilyName);
4653 face_list = get_face_list_from_family(family);
4654 LIST_FOR_EACH(face_elem_ptr, face_list) {
4655 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4656 if(face->vertical == want_vertical &&
4657 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4658 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4659 if(face->scalable)
4660 goto found;
4661 if(can_use_bitmap && !last_resort_family)
4662 last_resort_family = family;
4667 if(last_resort_family) {
4668 family = last_resort_family;
4669 csi.fs.fsCsb[0] = 0;
4670 goto found;
4673 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4674 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4675 face_list = get_face_list_from_family(family);
4676 LIST_FOR_EACH(face_elem_ptr, face_list) {
4677 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4678 if(face->scalable && face->vertical == want_vertical) {
4679 csi.fs.fsCsb[0] = 0;
4680 WARN("just using first face for now\n");
4681 goto found;
4683 if(can_use_bitmap && !last_resort_family)
4684 last_resort_family = family;
4687 if(!last_resort_family) {
4688 FIXME("can't find a single appropriate font - bailing\n");
4689 free_font(ret);
4690 ret = NULL;
4691 goto done;
4694 WARN("could only find a bitmap font - this will probably look awful!\n");
4695 family = last_resort_family;
4696 csi.fs.fsCsb[0] = 0;
4698 found:
4699 it = lf.lfItalic ? 1 : 0;
4700 bd = lf.lfWeight > 550 ? 1 : 0;
4702 height = lf.lfHeight;
4704 face = best = best_bitmap = NULL;
4705 font_link = find_font_link(family->FamilyName);
4706 face_list = get_face_list_from_family(family);
4707 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4709 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4710 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4711 !csi.fs.fsCsb[0])
4713 BOOL italic, bold;
4715 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4716 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4717 new_score = (italic ^ it) + (bold ^ bd);
4718 if(!best || new_score <= score)
4720 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4721 italic, bold, it, bd);
4722 score = new_score;
4723 best = face;
4724 if(best->scalable && score == 0) break;
4725 if(!best->scalable)
4727 if(height > 0)
4728 newdiff = height - (signed int)(best->size.height);
4729 else
4730 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4731 if(!best_bitmap || new_score < score ||
4732 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4734 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4735 diff = newdiff;
4736 best_bitmap = best;
4737 if(score == 0 && diff == 0) break;
4743 if(best)
4744 face = best->scalable ? best : best_bitmap;
4745 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4746 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4748 found_face:
4749 height = lf.lfHeight;
4751 ret->fs = face->fs;
4753 if(csi.fs.fsCsb[0]) {
4754 ret->charset = lf.lfCharSet;
4755 ret->codepage = csi.ciACP;
4757 else
4758 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4760 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4761 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4763 ret->aveWidth = height ? lf.lfWidth : 0;
4765 if(!face->scalable) {
4766 /* Windows uses integer scaling factors for bitmap fonts */
4767 INT scale, scaled_height;
4768 GdiFont *cachedfont;
4770 /* FIXME: rotation of bitmap fonts is ignored */
4771 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4772 if (ret->aveWidth)
4773 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4774 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4775 dcmat.eM11 = dcmat.eM22 = 1.0;
4776 /* As we changed the matrix, we need to search the cache for the font again,
4777 * otherwise we might explode the cache. */
4778 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4779 TRACE("Found cached font after non-scalable matrix rescale!\n");
4780 free_font( ret );
4781 ret = cachedfont;
4782 goto done;
4784 calc_hash(&ret->font_desc);
4786 if (height != 0) height = diff;
4787 height += face->size.height;
4789 scale = (height + face->size.height - 1) / face->size.height;
4790 scaled_height = scale * face->size.height;
4791 /* Only jump to the next height if the difference <= 25% original height */
4792 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4793 /* The jump between unscaled and doubled is delayed by 1 */
4794 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4795 ret->scale_y = scale;
4797 width = face->size.x_ppem >> 6;
4798 height = face->size.y_ppem >> 6;
4800 else
4801 ret->scale_y = 1.0;
4802 TRACE("font scale y: %f\n", ret->scale_y);
4804 ret->ft_face = OpenFontFace(ret, face, width, height);
4806 if (!ret->ft_face)
4808 free_font( ret );
4809 ret = NULL;
4810 goto done;
4813 ret->ntmFlags = face->ntmFlags;
4815 if (ret->charset == SYMBOL_CHARSET &&
4816 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4817 /* No ops */
4819 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4820 /* No ops */
4822 else {
4823 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4826 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4827 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4828 ret->underline = lf.lfUnderline ? 0xff : 0;
4829 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4830 create_child_font_list(ret);
4832 if (face->vertical) /* We need to try to load the GSUB table */
4834 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4835 if (length != GDI_ERROR)
4837 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4838 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4839 TRACE("Loaded GSUB table of %i bytes\n",length);
4843 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4845 add_to_cache(ret);
4846 done:
4847 if (ret)
4849 dc->gdiFont = ret;
4850 physdev->font = ret;
4852 LeaveCriticalSection( &freetype_cs );
4853 release_dc_ptr( dc );
4854 return ret ? hfont : 0;
4857 static void dump_gdi_font_list(void)
4859 GdiFont *gdiFont;
4860 struct list *elem_ptr;
4862 TRACE("---------- gdiFont Cache ----------\n");
4863 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4864 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4865 TRACE("gdiFont=%p %s %d\n",
4866 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4869 TRACE("---------- Unused gdiFont Cache ----------\n");
4870 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4871 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4872 TRACE("gdiFont=%p %s %d\n",
4873 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4876 TRACE("---------- Child gdiFont Cache ----------\n");
4877 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4878 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4879 TRACE("gdiFont=%p %s %d\n",
4880 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4884 /*************************************************************
4885 * WineEngDestroyFontInstance
4887 * free the gdiFont associated with this handle
4890 BOOL WineEngDestroyFontInstance(HFONT handle)
4892 GdiFont *gdiFont;
4893 HFONTLIST *hflist;
4894 BOOL ret = FALSE;
4895 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4896 int i = 0;
4898 GDI_CheckNotLock();
4899 EnterCriticalSection( &freetype_cs );
4901 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4903 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4904 while(hfontlist_elem_ptr) {
4905 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4906 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4907 if(hflist->hfont == handle) {
4908 TRACE("removing child font %p from child list\n", gdiFont);
4909 list_remove(&gdiFont->entry);
4910 LeaveCriticalSection( &freetype_cs );
4911 return TRUE;
4916 TRACE("destroying hfont=%p\n", handle);
4917 if(TRACE_ON(font))
4918 dump_gdi_font_list();
4920 font_elem_ptr = list_head(&gdi_font_list);
4921 while(font_elem_ptr) {
4922 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4923 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4925 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4926 while(hfontlist_elem_ptr) {
4927 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4928 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4929 if(hflist->hfont == handle) {
4930 list_remove(&hflist->entry);
4931 HeapFree(GetProcessHeap(), 0, hflist);
4932 ret = TRUE;
4935 if(list_empty(&gdiFont->hfontlist)) {
4936 TRACE("Moving to Unused list\n");
4937 list_remove(&gdiFont->entry);
4938 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4943 font_elem_ptr = list_head(&unused_gdi_font_list);
4944 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4945 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4946 while(font_elem_ptr) {
4947 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4948 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4949 TRACE("freeing %p\n", gdiFont);
4950 list_remove(&gdiFont->entry);
4951 free_font(gdiFont);
4953 LeaveCriticalSection( &freetype_cs );
4954 return ret;
4957 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4959 HRSRC rsrc;
4960 HGLOBAL hMem;
4961 WCHAR *p;
4962 int i;
4964 id += IDS_FIRST_SCRIPT;
4965 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4966 if (!rsrc) return 0;
4967 hMem = LoadResource( gdi32_module, rsrc );
4968 if (!hMem) return 0;
4970 p = LockResource( hMem );
4971 id &= 0x000f;
4972 while (id--) p += *p + 1;
4974 i = min(LF_FACESIZE - 1, *p);
4975 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4976 buffer[i] = 0;
4977 return i;
4981 /***************************************************
4982 * create_enum_charset_list
4984 * This function creates charset enumeration list because in DEFAULT_CHARSET
4985 * case, the ANSI codepage's charset takes precedence over other charsets.
4986 * This function works as a filter other than DEFAULT_CHARSET case.
4988 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4990 CHARSETINFO csi;
4991 DWORD n = 0;
4993 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4994 csi.fs.fsCsb[0] != 0) {
4995 list->element[n].mask = csi.fs.fsCsb[0];
4996 list->element[n].charset = csi.ciCharset;
4997 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4998 n++;
5000 else { /* charset is DEFAULT_CHARSET or invalid. */
5001 INT acp, i;
5003 /* Set the current codepage's charset as the first element. */
5004 acp = GetACP();
5005 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
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++;
5013 /* Fill out left elements. */
5014 for (i = 0; i < 32; i++) {
5015 FONTSIGNATURE fs;
5016 fs.fsCsb[0] = 1L << i;
5017 fs.fsCsb[1] = 0;
5018 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
5019 continue; /* skip, already added. */
5020 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5021 continue; /* skip, this is an invalid fsCsb bit. */
5023 list->element[n].mask = fs.fsCsb[0];
5024 list->element[n].charset = csi.ciCharset;
5025 load_script_name( i, list->element[n].name );
5026 n++;
5029 list->total = n;
5031 return n;
5034 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
5035 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5037 GdiFont *font;
5038 LONG width, height;
5040 if (face->cached_enum_data)
5042 TRACE("Cached\n");
5043 *pelf = face->cached_enum_data->elf;
5044 *pntm = face->cached_enum_data->ntm;
5045 *ptype = face->cached_enum_data->type;
5046 return;
5049 font = alloc_font();
5051 if(face->scalable) {
5052 height = 100;
5053 width = 0;
5054 } else {
5055 height = face->size.y_ppem >> 6;
5056 width = face->size.x_ppem >> 6;
5058 font->scale_y = 1.0;
5060 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5062 free_font(font);
5063 return;
5066 font->name = strdupW(face->family->FamilyName);
5067 font->ntmFlags = face->ntmFlags;
5069 if (get_outline_text_metrics(font))
5071 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5073 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5074 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5075 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5077 lstrcpynW(pelf->elfLogFont.lfFaceName,
5078 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5079 LF_FACESIZE);
5080 lstrcpynW(pelf->elfFullName,
5081 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
5082 LF_FULLFACESIZE);
5083 lstrcpynW(pelf->elfStyle,
5084 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5085 LF_FACESIZE);
5087 else
5089 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5091 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5092 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5093 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5095 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
5096 if (face->FullName)
5097 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5098 else
5099 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
5100 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5103 pntm->ntmTm.ntmFlags = face->ntmFlags;
5104 pntm->ntmFontSig = face->fs;
5106 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5108 pelf->elfLogFont.lfEscapement = 0;
5109 pelf->elfLogFont.lfOrientation = 0;
5110 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5111 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5112 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5113 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5114 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5115 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5116 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5117 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5118 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5119 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5120 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5122 *ptype = 0;
5123 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5124 *ptype |= TRUETYPE_FONTTYPE;
5125 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5126 *ptype |= DEVICE_FONTTYPE;
5127 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5128 *ptype |= RASTER_FONTTYPE;
5130 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5131 if (face->cached_enum_data)
5133 face->cached_enum_data->elf = *pelf;
5134 face->cached_enum_data->ntm = *pntm;
5135 face->cached_enum_data->type = *ptype;
5138 free_font(font);
5141 static void create_full_name(WCHAR *full_name, const WCHAR *family_name, const WCHAR *style_name)
5143 static const WCHAR spaceW[] = { ' ', 0 };
5145 strcpyW(full_name, family_name);
5146 strcatW(full_name, spaceW);
5147 strcatW(full_name, style_name);
5150 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5152 const struct list *face_list, *face_elem_ptr;
5154 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5156 face_list = get_face_list_from_family(family);
5157 LIST_FOR_EACH(face_elem_ptr, face_list)
5159 WCHAR full_family_name[LF_FULLFACESIZE];
5160 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
5162 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
5164 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
5165 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
5166 continue;
5169 create_full_name(full_family_name, family->FamilyName, face->StyleName);
5170 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
5173 return FALSE;
5176 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5178 WCHAR full_family_name[LF_FULLFACESIZE];
5180 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5182 if (strlenW(family_name) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
5184 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
5185 debugstr_w(family_name), debugstr_w(face->StyleName));
5186 return FALSE;
5189 create_full_name(full_family_name, family_name, face->StyleName);
5190 return !strcmpiW(lf->lfFaceName, full_family_name);
5193 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5194 FONTENUMPROCW proc, LPARAM lparam)
5196 ENUMLOGFONTEXW elf;
5197 NEWTEXTMETRICEXW ntm;
5198 DWORD type = 0;
5199 int i;
5201 GetEnumStructs(face, &elf, &ntm, &type);
5202 for(i = 0; i < list->total; i++) {
5203 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5204 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5205 load_script_name( IDS_OEM_DOS, elf.elfScript );
5206 i = list->total; /* break out of loop after enumeration */
5207 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
5208 continue;
5209 else {
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 create_full_name(elf.elfFullName, family->FamilyName, face->StyleName);
5221 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5222 debugstr_w(elf.elfLogFont.lfFaceName),
5223 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5224 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5225 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5226 ntm.ntmTm.ntmFlags);
5227 /* release section before callback (FIXME) */
5228 LeaveCriticalSection( &freetype_cs );
5229 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5230 EnterCriticalSection( &freetype_cs );
5232 return TRUE;
5235 /*************************************************************
5236 * freetype_EnumFonts
5238 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5240 Family *family;
5241 Face *face;
5242 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
5243 LOGFONTW lf;
5244 struct enum_charset_list enum_charsets;
5246 if (!plf)
5248 lf.lfCharSet = DEFAULT_CHARSET;
5249 lf.lfPitchAndFamily = 0;
5250 lf.lfFaceName[0] = 0;
5251 plf = &lf;
5254 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5256 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5258 GDI_CheckNotLock();
5259 EnterCriticalSection( &freetype_cs );
5260 if(plf->lfFaceName[0]) {
5261 FontSubst *psub;
5262 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5264 if(psub) {
5265 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5266 debugstr_w(psub->to.name));
5267 lf = *plf;
5268 strcpyW(lf.lfFaceName, psub->to.name);
5269 plf = &lf;
5272 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5273 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5274 if(family_matches(family, plf)) {
5275 face_list = get_face_list_from_family(family);
5276 LIST_FOR_EACH(face_elem_ptr, face_list) {
5277 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5278 if (!face_matches(family->FamilyName, face, plf)) continue;
5279 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5283 } else {
5284 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5285 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5286 face_list = get_face_list_from_family(family);
5287 face_elem_ptr = list_head(face_list);
5288 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5289 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5292 LeaveCriticalSection( &freetype_cs );
5293 return TRUE;
5296 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5298 pt->x.value = vec->x >> 6;
5299 pt->x.fract = (vec->x & 0x3f) << 10;
5300 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5301 pt->y.value = vec->y >> 6;
5302 pt->y.fract = (vec->y & 0x3f) << 10;
5303 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5304 return;
5307 /***************************************************
5308 * According to the MSDN documentation on WideCharToMultiByte,
5309 * certain codepages cannot set the default_used parameter.
5310 * This returns TRUE if the codepage can set that parameter, false else
5311 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5313 static BOOL codepage_sets_default_used(UINT codepage)
5315 switch (codepage)
5317 case CP_UTF7:
5318 case CP_UTF8:
5319 case CP_SYMBOL:
5320 return FALSE;
5321 default:
5322 return TRUE;
5327 * GSUB Table handling functions
5330 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5332 const GSUB_CoverageFormat1* cf1;
5334 cf1 = table;
5336 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5338 int count = GET_BE_WORD(cf1->GlyphCount);
5339 int i;
5340 TRACE("Coverage Format 1, %i glyphs\n",count);
5341 for (i = 0; i < count; i++)
5342 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5343 return i;
5344 return -1;
5346 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5348 const GSUB_CoverageFormat2* cf2;
5349 int i;
5350 int count;
5351 cf2 = (const GSUB_CoverageFormat2*)cf1;
5353 count = GET_BE_WORD(cf2->RangeCount);
5354 TRACE("Coverage Format 2, %i ranges\n",count);
5355 for (i = 0; i < count; i++)
5357 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5358 return -1;
5359 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5360 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5362 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5363 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5366 return -1;
5368 else
5369 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5371 return -1;
5374 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5376 const GSUB_ScriptList *script;
5377 const GSUB_Script *deflt = NULL;
5378 int i;
5379 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5381 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5382 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5384 const GSUB_Script *scr;
5385 int offset;
5387 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5388 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5390 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5391 return scr;
5392 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5393 deflt = scr;
5395 return deflt;
5398 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5400 int i;
5401 int offset;
5402 const GSUB_LangSys *Lang;
5404 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5406 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5408 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5409 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5411 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5412 return Lang;
5414 offset = GET_BE_WORD(script->DefaultLangSys);
5415 if (offset)
5417 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5418 return Lang;
5420 return NULL;
5423 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5425 int i;
5426 const GSUB_FeatureList *feature;
5427 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5429 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5430 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5432 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5433 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5435 const GSUB_Feature *feat;
5436 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5437 return feat;
5440 return NULL;
5443 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5445 int i;
5446 int offset;
5447 const GSUB_LookupList *lookup;
5448 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5450 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5451 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5453 const GSUB_LookupTable *look;
5454 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5455 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5456 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5457 if (GET_BE_WORD(look->LookupType) != 1)
5458 FIXME("We only handle SubType 1\n");
5459 else
5461 int j;
5463 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5465 const GSUB_SingleSubstFormat1 *ssf1;
5466 offset = GET_BE_WORD(look->SubTable[j]);
5467 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5468 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5470 int offset = GET_BE_WORD(ssf1->Coverage);
5471 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5472 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5474 TRACE(" Glyph 0x%x ->",glyph);
5475 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5476 TRACE(" 0x%x\n",glyph);
5479 else
5481 const GSUB_SingleSubstFormat2 *ssf2;
5482 INT index;
5483 INT offset;
5485 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5486 offset = GET_BE_WORD(ssf1->Coverage);
5487 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5488 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5489 TRACE(" Coverage index %i\n",index);
5490 if (index != -1)
5492 TRACE(" Glyph is 0x%x ->",glyph);
5493 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5494 TRACE("0x%x\n",glyph);
5500 return glyph;
5503 static const char* get_opentype_script(const GdiFont *font)
5506 * I am not sure if this is the correct way to generate our script tag
5509 switch (font->charset)
5511 case ANSI_CHARSET: return "latn";
5512 case BALTIC_CHARSET: return "latn"; /* ?? */
5513 case CHINESEBIG5_CHARSET: return "hani";
5514 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5515 case GB2312_CHARSET: return "hani";
5516 case GREEK_CHARSET: return "grek";
5517 case HANGUL_CHARSET: return "hang";
5518 case RUSSIAN_CHARSET: return "cyrl";
5519 case SHIFTJIS_CHARSET: return "kana";
5520 case TURKISH_CHARSET: return "latn"; /* ?? */
5521 case VIETNAMESE_CHARSET: return "latn";
5522 case JOHAB_CHARSET: return "latn"; /* ?? */
5523 case ARABIC_CHARSET: return "arab";
5524 case HEBREW_CHARSET: return "hebr";
5525 case THAI_CHARSET: return "thai";
5526 default: return "latn";
5530 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5532 const GSUB_Header *header;
5533 const GSUB_Script *script;
5534 const GSUB_LangSys *language;
5535 const GSUB_Feature *feature;
5537 if (!font->GSUB_Table)
5538 return glyph;
5540 header = font->GSUB_Table;
5542 script = GSUB_get_script_table(header, get_opentype_script(font));
5543 if (!script)
5545 TRACE("Script not found\n");
5546 return glyph;
5548 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5549 if (!language)
5551 TRACE("Language not found\n");
5552 return glyph;
5554 feature = GSUB_get_feature(header, language, "vrt2");
5555 if (!feature)
5556 feature = GSUB_get_feature(header, language, "vert");
5557 if (!feature)
5559 TRACE("vrt2/vert feature not found\n");
5560 return glyph;
5562 return GSUB_apply_feature(header, feature, glyph);
5565 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5567 FT_UInt glyphId;
5569 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5570 WCHAR wc = (WCHAR)glyph;
5571 BOOL default_used;
5572 BOOL *default_used_pointer;
5573 FT_UInt ret;
5574 char buf;
5575 default_used_pointer = NULL;
5576 default_used = FALSE;
5577 if (codepage_sets_default_used(font->codepage))
5578 default_used_pointer = &default_used;
5579 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5580 ret = 0;
5581 else
5582 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5583 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5584 return ret;
5587 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5589 if (glyph < 0x100) glyph += 0xf000;
5590 /* there is a number of old pre-Unicode "broken" TTFs, which
5591 do have symbols at U+00XX instead of U+f0XX */
5592 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5593 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5595 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5597 return glyphId;
5600 /*************************************************************
5601 * freetype_GetGlyphIndices
5603 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5605 struct freetype_physdev *physdev = get_freetype_dev( dev );
5606 int i;
5607 WORD default_char;
5608 BOOL got_default = FALSE;
5610 if (!physdev->font)
5612 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5613 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5616 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5618 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5619 got_default = TRUE;
5622 GDI_CheckNotLock();
5623 EnterCriticalSection( &freetype_cs );
5625 for(i = 0; i < count; i++)
5627 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5628 if (pgi[i] == 0)
5630 if (!got_default)
5632 if (FT_IS_SFNT(physdev->font->ft_face))
5634 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5635 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5637 else
5639 TEXTMETRICW textm;
5640 get_text_metrics(physdev->font, &textm);
5641 default_char = textm.tmDefaultChar;
5643 got_default = TRUE;
5645 pgi[i] = default_char;
5648 LeaveCriticalSection( &freetype_cs );
5649 return count;
5652 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5654 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5655 return !memcmp(matrix, &identity, sizeof(FMAT2));
5658 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5660 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5661 return !memcmp(matrix, &identity, sizeof(MAT2));
5664 static inline BYTE get_max_level( UINT format )
5666 switch( format )
5668 case GGO_GRAY2_BITMAP: return 4;
5669 case GGO_GRAY4_BITMAP: return 16;
5670 case GGO_GRAY8_BITMAP: return 64;
5672 return 255;
5675 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5677 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5678 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5679 const MAT2* lpmat)
5681 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5682 FT_Face ft_face = incoming_font->ft_face;
5683 GdiFont *font = incoming_font;
5684 FT_UInt glyph_index;
5685 DWORD width, height, pitch, needed = 0;
5686 FT_Bitmap ft_bitmap;
5687 FT_Error err;
5688 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5689 FT_Angle angle = 0;
5690 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5691 double widthRatio = 1.0;
5692 FT_Matrix transMat = identityMat;
5693 FT_Matrix transMatUnrotated;
5694 BOOL needsTransform = FALSE;
5695 BOOL tategaki = (font->GSUB_Table != NULL);
5696 UINT original_index;
5698 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5699 buflen, buf, lpmat);
5701 TRACE("font transform %f %f %f %f\n",
5702 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5703 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5705 if(format & GGO_GLYPH_INDEX) {
5706 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5707 original_index = glyph;
5708 format &= ~GGO_GLYPH_INDEX;
5709 } else {
5710 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5711 ft_face = font->ft_face;
5712 original_index = glyph_index;
5715 if(format & GGO_UNHINTED) {
5716 load_flags |= FT_LOAD_NO_HINTING;
5717 format &= ~GGO_UNHINTED;
5720 /* tategaki never appears to happen to lower glyph index */
5721 if (glyph_index < TATEGAKI_LOWER_BOUND )
5722 tategaki = FALSE;
5724 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5725 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5726 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5727 font->gmsize * sizeof(GM*));
5728 } else {
5729 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5730 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5732 *lpgm = FONT_GM(font,original_index)->gm;
5733 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5734 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5735 lpgm->gmCellIncX, lpgm->gmCellIncY);
5736 return 1; /* FIXME */
5740 if (!font->gm[original_index / GM_BLOCK_SIZE])
5741 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5743 /* Scaling factor */
5744 if (font->aveWidth)
5746 TEXTMETRICW tm;
5748 get_text_metrics(font, &tm);
5750 widthRatio = (double)font->aveWidth;
5751 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5753 else
5754 widthRatio = font->scale_y;
5756 /* Scaling transform */
5757 if (widthRatio != 1.0 || font->scale_y != 1.0)
5759 FT_Matrix scaleMat;
5760 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5761 scaleMat.xy = 0;
5762 scaleMat.yx = 0;
5763 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5765 pFT_Matrix_Multiply(&scaleMat, &transMat);
5766 needsTransform = TRUE;
5769 /* Slant transform */
5770 if (font->fake_italic) {
5771 FT_Matrix slantMat;
5773 slantMat.xx = (1 << 16);
5774 slantMat.xy = ((1 << 16) >> 2);
5775 slantMat.yx = 0;
5776 slantMat.yy = (1 << 16);
5777 pFT_Matrix_Multiply(&slantMat, &transMat);
5778 needsTransform = TRUE;
5781 /* Rotation transform */
5782 transMatUnrotated = transMat;
5783 if(font->orientation && !tategaki) {
5784 FT_Matrix rotationMat;
5785 FT_Vector vecAngle;
5786 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5787 pFT_Vector_Unit(&vecAngle, angle);
5788 rotationMat.xx = vecAngle.x;
5789 rotationMat.xy = -vecAngle.y;
5790 rotationMat.yx = -rotationMat.xy;
5791 rotationMat.yy = rotationMat.xx;
5793 pFT_Matrix_Multiply(&rotationMat, &transMat);
5794 needsTransform = TRUE;
5797 /* World transform */
5798 if (!is_identity_FMAT2(&font->font_desc.matrix))
5800 FT_Matrix worldMat;
5801 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5802 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5803 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5804 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5805 pFT_Matrix_Multiply(&worldMat, &transMat);
5806 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5807 needsTransform = TRUE;
5810 /* Extra transformation specified by caller */
5811 if (!is_identity_MAT2(lpmat))
5813 FT_Matrix extraMat;
5814 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5815 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5816 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5817 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5818 pFT_Matrix_Multiply(&extraMat, &transMat);
5819 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5820 needsTransform = TRUE;
5823 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5824 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5825 format == GGO_GRAY8_BITMAP))
5827 load_flags |= FT_LOAD_NO_BITMAP;
5830 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5832 if(err) {
5833 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5834 return GDI_ERROR;
5837 if(!needsTransform) {
5838 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5839 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5840 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5842 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5843 bottom = (ft_face->glyph->metrics.horiBearingY -
5844 ft_face->glyph->metrics.height) & -64;
5845 lpgm->gmCellIncX = adv;
5846 lpgm->gmCellIncY = 0;
5847 } else {
5848 INT xc, yc;
5849 FT_Vector vec;
5851 left = right = 0;
5853 for(xc = 0; xc < 2; xc++) {
5854 for(yc = 0; yc < 2; yc++) {
5855 vec.x = (ft_face->glyph->metrics.horiBearingX +
5856 xc * ft_face->glyph->metrics.width);
5857 vec.y = ft_face->glyph->metrics.horiBearingY -
5858 yc * ft_face->glyph->metrics.height;
5859 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5860 pFT_Vector_Transform(&vec, &transMat);
5861 if(xc == 0 && yc == 0) {
5862 left = right = vec.x;
5863 top = bottom = vec.y;
5864 } else {
5865 if(vec.x < left) left = vec.x;
5866 else if(vec.x > right) right = vec.x;
5867 if(vec.y < bottom) bottom = vec.y;
5868 else if(vec.y > top) top = vec.y;
5872 left = left & -64;
5873 right = (right + 63) & -64;
5874 bottom = bottom & -64;
5875 top = (top + 63) & -64;
5877 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5878 vec.x = ft_face->glyph->metrics.horiAdvance;
5879 vec.y = 0;
5880 pFT_Vector_Transform(&vec, &transMat);
5881 lpgm->gmCellIncX = (vec.x+63) >> 6;
5882 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5884 vec.x = ft_face->glyph->metrics.horiAdvance;
5885 vec.y = 0;
5886 pFT_Vector_Transform(&vec, &transMatUnrotated);
5887 adv = (vec.x+63) >> 6;
5890 lsb = left >> 6;
5891 bbx = (right - left) >> 6;
5892 lpgm->gmBlackBoxX = (right - left) >> 6;
5893 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5894 lpgm->gmptGlyphOrigin.x = left >> 6;
5895 lpgm->gmptGlyphOrigin.y = top >> 6;
5897 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5898 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5899 lpgm->gmCellIncX, lpgm->gmCellIncY);
5901 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5902 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5904 FONT_GM(font,original_index)->gm = *lpgm;
5905 FONT_GM(font,original_index)->adv = adv;
5906 FONT_GM(font,original_index)->lsb = lsb;
5907 FONT_GM(font,original_index)->bbx = bbx;
5908 FONT_GM(font,original_index)->init = TRUE;
5911 if(format == GGO_METRICS)
5913 return 1; /* FIXME */
5916 if(ft_face->glyph->format != ft_glyph_format_outline &&
5917 (format == GGO_NATIVE || format == GGO_BEZIER))
5919 TRACE("loaded a bitmap\n");
5920 return GDI_ERROR;
5923 switch(format) {
5924 case GGO_BITMAP:
5925 width = lpgm->gmBlackBoxX;
5926 height = lpgm->gmBlackBoxY;
5927 pitch = ((width + 31) >> 5) << 2;
5928 needed = pitch * height;
5930 if(!buf || !buflen) break;
5932 switch(ft_face->glyph->format) {
5933 case ft_glyph_format_bitmap:
5935 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5936 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5937 INT h = ft_face->glyph->bitmap.rows;
5938 while(h--) {
5939 memcpy(dst, src, w);
5940 src += ft_face->glyph->bitmap.pitch;
5941 dst += pitch;
5943 break;
5946 case ft_glyph_format_outline:
5947 ft_bitmap.width = width;
5948 ft_bitmap.rows = height;
5949 ft_bitmap.pitch = pitch;
5950 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5951 ft_bitmap.buffer = buf;
5953 if(needsTransform)
5954 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5956 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5958 /* Note: FreeType will only set 'black' bits for us. */
5959 memset(buf, 0, needed);
5960 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5961 break;
5963 default:
5964 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5965 return GDI_ERROR;
5967 break;
5969 case GGO_GRAY2_BITMAP:
5970 case GGO_GRAY4_BITMAP:
5971 case GGO_GRAY8_BITMAP:
5972 case WINE_GGO_GRAY16_BITMAP:
5974 unsigned int max_level, row, col;
5975 BYTE *start, *ptr;
5977 width = lpgm->gmBlackBoxX;
5978 height = lpgm->gmBlackBoxY;
5979 pitch = (width + 3) / 4 * 4;
5980 needed = pitch * height;
5982 if(!buf || !buflen) break;
5984 max_level = get_max_level( format );
5986 switch(ft_face->glyph->format) {
5987 case ft_glyph_format_bitmap:
5989 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5990 INT h = ft_face->glyph->bitmap.rows;
5991 INT x;
5992 memset( buf, 0, needed );
5993 while(h--) {
5994 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5995 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5996 src += ft_face->glyph->bitmap.pitch;
5997 dst += pitch;
5999 return needed;
6001 case ft_glyph_format_outline:
6003 ft_bitmap.width = width;
6004 ft_bitmap.rows = height;
6005 ft_bitmap.pitch = pitch;
6006 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6007 ft_bitmap.buffer = buf;
6009 if(needsTransform)
6010 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6012 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6014 memset(ft_bitmap.buffer, 0, buflen);
6016 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6018 if (max_level != 255)
6020 for (row = 0, start = buf; row < height; row++)
6022 for (col = 0, ptr = start; col < width; col++, ptr++)
6023 *ptr = (((int)*ptr) * max_level + 128) / 256;
6024 start += pitch;
6027 return needed;
6030 default:
6031 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6032 return GDI_ERROR;
6034 break;
6037 case WINE_GGO_HRGB_BITMAP:
6038 case WINE_GGO_HBGR_BITMAP:
6039 case WINE_GGO_VRGB_BITMAP:
6040 case WINE_GGO_VBGR_BITMAP:
6041 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6043 switch (ft_face->glyph->format)
6045 case FT_GLYPH_FORMAT_BITMAP:
6047 BYTE *src, *dst;
6048 INT src_pitch, x;
6050 width = lpgm->gmBlackBoxX;
6051 height = lpgm->gmBlackBoxY;
6052 pitch = width * 4;
6053 needed = pitch * height;
6055 if (!buf || !buflen) break;
6057 memset(buf, 0, buflen);
6058 dst = buf;
6059 src = ft_face->glyph->bitmap.buffer;
6060 src_pitch = ft_face->glyph->bitmap.pitch;
6062 height = min( height, ft_face->glyph->bitmap.rows );
6063 while ( height-- )
6065 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6067 if ( src[x / 8] & masks[x % 8] )
6068 ((unsigned int *)dst)[x] = ~0u;
6070 src += src_pitch;
6071 dst += pitch;
6074 break;
6077 case FT_GLYPH_FORMAT_OUTLINE:
6079 unsigned int *dst;
6080 BYTE *src;
6081 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6082 INT x_shift, y_shift;
6083 BOOL rgb;
6084 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6085 FT_Render_Mode render_mode =
6086 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6087 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6089 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6091 if ( render_mode == FT_RENDER_MODE_LCD)
6093 lpgm->gmBlackBoxX += 2;
6094 lpgm->gmptGlyphOrigin.x -= 1;
6096 else
6098 lpgm->gmBlackBoxY += 2;
6099 lpgm->gmptGlyphOrigin.y += 1;
6103 width = lpgm->gmBlackBoxX;
6104 height = lpgm->gmBlackBoxY;
6105 pitch = width * 4;
6106 needed = pitch * height;
6108 if (!buf || !buflen) break;
6110 memset(buf, 0, buflen);
6111 dst = buf;
6112 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6114 if ( needsTransform )
6115 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
6117 if ( pFT_Library_SetLcdFilter )
6118 pFT_Library_SetLcdFilter( library, lcdfilter );
6119 pFT_Render_Glyph (ft_face->glyph, render_mode);
6121 src = ft_face->glyph->bitmap.buffer;
6122 src_pitch = ft_face->glyph->bitmap.pitch;
6123 src_width = ft_face->glyph->bitmap.width;
6124 src_height = ft_face->glyph->bitmap.rows;
6126 if ( render_mode == FT_RENDER_MODE_LCD)
6128 rgb_interval = 1;
6129 hmul = 3;
6130 vmul = 1;
6132 else
6134 rgb_interval = src_pitch;
6135 hmul = 1;
6136 vmul = 3;
6139 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6140 if ( x_shift < 0 ) x_shift = 0;
6141 if ( x_shift + (src_width / hmul) > width )
6142 x_shift = width - (src_width / hmul);
6144 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6145 if ( y_shift < 0 ) y_shift = 0;
6146 if ( y_shift + (src_height / vmul) > height )
6147 y_shift = height - (src_height / vmul);
6149 dst += x_shift + y_shift * ( pitch / 4 );
6150 while ( src_height )
6152 for ( x = 0; x < src_width / hmul; x++ )
6154 if ( rgb )
6156 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6157 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6158 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6159 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6161 else
6163 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6164 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6165 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6166 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6169 src += src_pitch * vmul;
6170 dst += pitch / 4;
6171 src_height -= vmul;
6174 break;
6177 default:
6178 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6179 return GDI_ERROR;
6182 break;
6184 #else
6185 return GDI_ERROR;
6186 #endif
6188 case GGO_NATIVE:
6190 int contour, point = 0, first_pt;
6191 FT_Outline *outline = &ft_face->glyph->outline;
6192 TTPOLYGONHEADER *pph;
6193 TTPOLYCURVE *ppc;
6194 DWORD pph_start, cpfx, type;
6196 if(buflen == 0) buf = NULL;
6198 if (needsTransform && buf) {
6199 pFT_Outline_Transform(outline, &transMat);
6202 for(contour = 0; contour < outline->n_contours; contour++) {
6203 pph_start = needed;
6204 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6205 first_pt = point;
6206 if(buf) {
6207 pph->dwType = TT_POLYGON_TYPE;
6208 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6210 needed += sizeof(*pph);
6211 point++;
6212 while(point <= outline->contours[contour]) {
6213 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6214 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6215 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6216 cpfx = 0;
6217 do {
6218 if(buf)
6219 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6220 cpfx++;
6221 point++;
6222 } while(point <= outline->contours[contour] &&
6223 (outline->tags[point] & FT_Curve_Tag_On) ==
6224 (outline->tags[point-1] & FT_Curve_Tag_On));
6225 /* At the end of a contour Windows adds the start point, but
6226 only for Beziers */
6227 if(point > outline->contours[contour] &&
6228 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6229 if(buf)
6230 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6231 cpfx++;
6232 } else if(point <= outline->contours[contour] &&
6233 outline->tags[point] & FT_Curve_Tag_On) {
6234 /* add closing pt for bezier */
6235 if(buf)
6236 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6237 cpfx++;
6238 point++;
6240 if(buf) {
6241 ppc->wType = type;
6242 ppc->cpfx = cpfx;
6244 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6246 if(buf)
6247 pph->cb = needed - pph_start;
6249 break;
6251 case GGO_BEZIER:
6253 /* Convert the quadratic Beziers to cubic Beziers.
6254 The parametric eqn for a cubic Bezier is, from PLRM:
6255 r(t) = at^3 + bt^2 + ct + r0
6256 with the control points:
6257 r1 = r0 + c/3
6258 r2 = r1 + (c + b)/3
6259 r3 = r0 + c + b + a
6261 A quadratic Bezier has the form:
6262 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6264 So equating powers of t leads to:
6265 r1 = 2/3 p1 + 1/3 p0
6266 r2 = 2/3 p1 + 1/3 p2
6267 and of course r0 = p0, r3 = p2
6270 int contour, point = 0, first_pt;
6271 FT_Outline *outline = &ft_face->glyph->outline;
6272 TTPOLYGONHEADER *pph;
6273 TTPOLYCURVE *ppc;
6274 DWORD pph_start, cpfx, type;
6275 FT_Vector cubic_control[4];
6276 if(buflen == 0) buf = NULL;
6278 if (needsTransform && buf) {
6279 pFT_Outline_Transform(outline, &transMat);
6282 for(contour = 0; contour < outline->n_contours; contour++) {
6283 pph_start = needed;
6284 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6285 first_pt = point;
6286 if(buf) {
6287 pph->dwType = TT_POLYGON_TYPE;
6288 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6290 needed += sizeof(*pph);
6291 point++;
6292 while(point <= outline->contours[contour]) {
6293 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6294 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6295 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6296 cpfx = 0;
6297 do {
6298 if(type == TT_PRIM_LINE) {
6299 if(buf)
6300 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6301 cpfx++;
6302 point++;
6303 } else {
6304 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6305 so cpfx = 3n */
6307 /* FIXME: Possible optimization in endpoint calculation
6308 if there are two consecutive curves */
6309 cubic_control[0] = outline->points[point-1];
6310 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6311 cubic_control[0].x += outline->points[point].x + 1;
6312 cubic_control[0].y += outline->points[point].y + 1;
6313 cubic_control[0].x >>= 1;
6314 cubic_control[0].y >>= 1;
6316 if(point+1 > outline->contours[contour])
6317 cubic_control[3] = outline->points[first_pt];
6318 else {
6319 cubic_control[3] = outline->points[point+1];
6320 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6321 cubic_control[3].x += outline->points[point].x + 1;
6322 cubic_control[3].y += outline->points[point].y + 1;
6323 cubic_control[3].x >>= 1;
6324 cubic_control[3].y >>= 1;
6327 /* r1 = 1/3 p0 + 2/3 p1
6328 r2 = 1/3 p2 + 2/3 p1 */
6329 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6330 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6331 cubic_control[2] = cubic_control[1];
6332 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6333 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6334 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6335 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6336 if(buf) {
6337 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6338 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6339 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6341 cpfx += 3;
6342 point++;
6344 } while(point <= outline->contours[contour] &&
6345 (outline->tags[point] & FT_Curve_Tag_On) ==
6346 (outline->tags[point-1] & FT_Curve_Tag_On));
6347 /* At the end of a contour Windows adds the start point,
6348 but only for Beziers and we've already done that.
6350 if(point <= outline->contours[contour] &&
6351 outline->tags[point] & FT_Curve_Tag_On) {
6352 /* This is the closing pt of a bezier, but we've already
6353 added it, so just inc point and carry on */
6354 point++;
6356 if(buf) {
6357 ppc->wType = type;
6358 ppc->cpfx = cpfx;
6360 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6362 if(buf)
6363 pph->cb = needed - pph_start;
6365 break;
6368 default:
6369 FIXME("Unsupported format %d\n", format);
6370 return GDI_ERROR;
6372 return needed;
6375 static BOOL get_bitmap_text_metrics(GdiFont *font)
6377 FT_Face ft_face = font->ft_face;
6378 FT_WinFNT_HeaderRec winfnt_header;
6379 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6380 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6381 font->potm->otmSize = size;
6383 #define TM font->potm->otmTextMetrics
6384 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6386 TM.tmHeight = winfnt_header.pixel_height;
6387 TM.tmAscent = winfnt_header.ascent;
6388 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6389 TM.tmInternalLeading = winfnt_header.internal_leading;
6390 TM.tmExternalLeading = winfnt_header.external_leading;
6391 TM.tmAveCharWidth = winfnt_header.avg_width;
6392 TM.tmMaxCharWidth = winfnt_header.max_width;
6393 TM.tmWeight = winfnt_header.weight;
6394 TM.tmOverhang = 0;
6395 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6396 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6397 TM.tmFirstChar = winfnt_header.first_char;
6398 TM.tmLastChar = winfnt_header.last_char;
6399 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6400 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6401 TM.tmItalic = winfnt_header.italic;
6402 TM.tmUnderlined = font->underline;
6403 TM.tmStruckOut = font->strikeout;
6404 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6405 TM.tmCharSet = winfnt_header.charset;
6407 else
6409 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6410 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6411 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6412 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6413 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6414 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6415 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6416 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6417 TM.tmOverhang = 0;
6418 TM.tmDigitizedAspectX = 96; /* FIXME */
6419 TM.tmDigitizedAspectY = 96; /* FIXME */
6420 TM.tmFirstChar = 1;
6421 TM.tmLastChar = 255;
6422 TM.tmDefaultChar = 32;
6423 TM.tmBreakChar = 32;
6424 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6425 TM.tmUnderlined = font->underline;
6426 TM.tmStruckOut = font->strikeout;
6427 /* NB inverted meaning of TMPF_FIXED_PITCH */
6428 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6429 TM.tmCharSet = font->charset;
6431 #undef TM
6433 return TRUE;
6437 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6439 double scale_x, scale_y;
6441 if (font->aveWidth)
6443 scale_x = (double)font->aveWidth;
6444 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6446 else
6447 scale_x = font->scale_y;
6449 scale_x *= fabs(font->font_desc.matrix.eM11);
6450 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6452 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6453 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6455 SCALE_Y(ptm->tmHeight);
6456 SCALE_Y(ptm->tmAscent);
6457 SCALE_Y(ptm->tmDescent);
6458 SCALE_Y(ptm->tmInternalLeading);
6459 SCALE_Y(ptm->tmExternalLeading);
6460 SCALE_Y(ptm->tmOverhang);
6462 SCALE_X(ptm->tmAveCharWidth);
6463 SCALE_X(ptm->tmMaxCharWidth);
6465 #undef SCALE_X
6466 #undef SCALE_Y
6469 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6471 double scale_x, scale_y;
6473 if (font->aveWidth)
6475 scale_x = (double)font->aveWidth;
6476 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6478 else
6479 scale_x = font->scale_y;
6481 scale_x *= fabs(font->font_desc.matrix.eM11);
6482 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6484 scale_font_metrics(font, &potm->otmTextMetrics);
6486 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6487 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6489 SCALE_Y(potm->otmAscent);
6490 SCALE_Y(potm->otmDescent);
6491 SCALE_Y(potm->otmLineGap);
6492 SCALE_Y(potm->otmsCapEmHeight);
6493 SCALE_Y(potm->otmsXHeight);
6494 SCALE_Y(potm->otmrcFontBox.top);
6495 SCALE_Y(potm->otmrcFontBox.bottom);
6496 SCALE_X(potm->otmrcFontBox.left);
6497 SCALE_X(potm->otmrcFontBox.right);
6498 SCALE_Y(potm->otmMacAscent);
6499 SCALE_Y(potm->otmMacDescent);
6500 SCALE_Y(potm->otmMacLineGap);
6501 SCALE_X(potm->otmptSubscriptSize.x);
6502 SCALE_Y(potm->otmptSubscriptSize.y);
6503 SCALE_X(potm->otmptSubscriptOffset.x);
6504 SCALE_Y(potm->otmptSubscriptOffset.y);
6505 SCALE_X(potm->otmptSuperscriptSize.x);
6506 SCALE_Y(potm->otmptSuperscriptSize.y);
6507 SCALE_X(potm->otmptSuperscriptOffset.x);
6508 SCALE_Y(potm->otmptSuperscriptOffset.y);
6509 SCALE_Y(potm->otmsStrikeoutSize);
6510 SCALE_Y(potm->otmsStrikeoutPosition);
6511 SCALE_Y(potm->otmsUnderscoreSize);
6512 SCALE_Y(potm->otmsUnderscorePosition);
6514 #undef SCALE_X
6515 #undef SCALE_Y
6518 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6520 if(!font->potm)
6522 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6524 /* Make sure that the font has sane width/height ratio */
6525 if (font->aveWidth)
6527 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6529 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6530 font->aveWidth = 0;
6534 *ptm = font->potm->otmTextMetrics;
6535 scale_font_metrics(font, ptm);
6536 return TRUE;
6539 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6541 int i;
6543 for(i = 0; i < ft_face->num_charmaps; i++)
6545 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6546 return TRUE;
6548 return FALSE;
6551 static BOOL get_outline_text_metrics(GdiFont *font)
6553 BOOL ret = FALSE;
6554 FT_Face ft_face = font->ft_face;
6555 UINT needed, lenfam, lensty;
6556 TT_OS2 *pOS2;
6557 TT_HoriHeader *pHori;
6558 TT_Postscript *pPost;
6559 FT_Fixed x_scale, y_scale;
6560 WCHAR *family_nameW, *style_nameW;
6561 static const WCHAR spaceW[] = {' ', '\0'};
6562 char *cp;
6563 INT ascent, descent;
6565 TRACE("font=%p\n", font);
6567 if(!FT_IS_SCALABLE(ft_face))
6568 return FALSE;
6570 needed = sizeof(*font->potm);
6572 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6573 family_nameW = strdupW(font->name);
6575 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6576 * sizeof(WCHAR);
6577 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6578 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6579 style_nameW, lensty/sizeof(WCHAR));
6581 /* These names should be read from the TT name table */
6583 /* length of otmpFamilyName */
6584 needed += lenfam;
6586 /* length of otmpFaceName */
6587 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
6588 needed += lenfam; /* just the family name */
6589 } else {
6590 needed += lenfam + lensty; /* family + " " + style */
6593 /* length of otmpStyleName */
6594 needed += lensty;
6596 /* length of otmpFullName */
6597 needed += lenfam + lensty;
6600 x_scale = ft_face->size->metrics.x_scale;
6601 y_scale = ft_face->size->metrics.y_scale;
6603 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6604 if(!pOS2) {
6605 FIXME("Can't find OS/2 table - not TT font?\n");
6606 goto end;
6609 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6610 if(!pHori) {
6611 FIXME("Can't find HHEA table - not TT font?\n");
6612 goto end;
6615 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6617 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",
6618 pOS2->usWinAscent, pOS2->usWinDescent,
6619 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6620 pOS2->xAvgCharWidth,
6621 ft_face->ascender, ft_face->descender, ft_face->height,
6622 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6623 ft_face->bbox.yMax, ft_face->bbox.yMin);
6625 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6626 font->potm->otmSize = needed;
6628 #define TM font->potm->otmTextMetrics
6630 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6631 ascent = pHori->Ascender;
6632 descent = -pHori->Descender;
6633 } else {
6634 ascent = pOS2->usWinAscent;
6635 descent = pOS2->usWinDescent;
6638 font->ntmCellHeight = ascent + descent;
6639 font->ntmAvgWidth = pOS2->xAvgCharWidth;
6641 if(font->yMax) {
6642 TM.tmAscent = font->yMax;
6643 TM.tmDescent = -font->yMin;
6644 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6645 } else {
6646 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6647 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6648 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6649 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6652 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6654 /* MSDN says:
6655 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6657 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6658 ((ascent + descent) -
6659 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6661 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6662 if (TM.tmAveCharWidth == 0) {
6663 TM.tmAveCharWidth = 1;
6665 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6666 TM.tmWeight = FW_REGULAR;
6667 if (font->fake_bold)
6668 TM.tmWeight = FW_BOLD;
6669 else
6671 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6673 if (pOS2->usWeightClass > FW_MEDIUM)
6674 TM.tmWeight = pOS2->usWeightClass;
6676 else if (pOS2->usWeightClass <= FW_MEDIUM)
6677 TM.tmWeight = pOS2->usWeightClass;
6679 TM.tmOverhang = 0;
6680 TM.tmDigitizedAspectX = 96; /* FIXME */
6681 TM.tmDigitizedAspectY = 96; /* FIXME */
6682 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6683 * symbol range to 0 - f0ff
6686 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6688 TM.tmFirstChar = 0;
6689 switch(GetACP())
6691 case 1257: /* Baltic */
6692 TM.tmLastChar = 0xf8fd;
6693 break;
6694 default:
6695 TM.tmLastChar = 0xf0ff;
6697 TM.tmBreakChar = 0x20;
6698 TM.tmDefaultChar = 0x1f;
6700 else
6702 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6703 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6705 if(pOS2->usFirstCharIndex <= 1)
6706 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6707 else if (pOS2->usFirstCharIndex > 0xff)
6708 TM.tmBreakChar = 0x20;
6709 else
6710 TM.tmBreakChar = pOS2->usFirstCharIndex;
6711 TM.tmDefaultChar = TM.tmBreakChar - 1;
6713 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6714 TM.tmUnderlined = font->underline;
6715 TM.tmStruckOut = font->strikeout;
6717 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6718 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6719 (pOS2->version == 0xFFFFU ||
6720 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6721 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6722 else
6723 TM.tmPitchAndFamily = 0;
6725 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6727 case PAN_FAMILY_SCRIPT:
6728 TM.tmPitchAndFamily |= FF_SCRIPT;
6729 break;
6731 case PAN_FAMILY_DECORATIVE:
6732 TM.tmPitchAndFamily |= FF_DECORATIVE;
6733 break;
6735 case PAN_ANY:
6736 case PAN_NO_FIT:
6737 case PAN_FAMILY_TEXT_DISPLAY:
6738 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6739 /* which is clearly not what the panose spec says. */
6740 default:
6741 if(TM.tmPitchAndFamily == 0 || /* fixed */
6742 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6743 TM.tmPitchAndFamily = FF_MODERN;
6744 else
6746 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6748 case PAN_ANY:
6749 case PAN_NO_FIT:
6750 default:
6751 TM.tmPitchAndFamily |= FF_DONTCARE;
6752 break;
6754 case PAN_SERIF_COVE:
6755 case PAN_SERIF_OBTUSE_COVE:
6756 case PAN_SERIF_SQUARE_COVE:
6757 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6758 case PAN_SERIF_SQUARE:
6759 case PAN_SERIF_THIN:
6760 case PAN_SERIF_BONE:
6761 case PAN_SERIF_EXAGGERATED:
6762 case PAN_SERIF_TRIANGLE:
6763 TM.tmPitchAndFamily |= FF_ROMAN;
6764 break;
6766 case PAN_SERIF_NORMAL_SANS:
6767 case PAN_SERIF_OBTUSE_SANS:
6768 case PAN_SERIF_PERP_SANS:
6769 case PAN_SERIF_FLARED:
6770 case PAN_SERIF_ROUNDED:
6771 TM.tmPitchAndFamily |= FF_SWISS;
6772 break;
6775 break;
6778 if(FT_IS_SCALABLE(ft_face))
6779 TM.tmPitchAndFamily |= TMPF_VECTOR;
6781 if(FT_IS_SFNT(ft_face))
6783 if (font->ntmFlags & NTM_PS_OPENTYPE)
6784 TM.tmPitchAndFamily |= TMPF_DEVICE;
6785 else
6786 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6789 TM.tmCharSet = font->charset;
6791 font->potm->otmFiller = 0;
6792 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6793 font->potm->otmfsSelection = pOS2->fsSelection;
6794 font->potm->otmfsType = pOS2->fsType;
6795 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6796 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6797 font->potm->otmItalicAngle = 0; /* POST table */
6798 font->potm->otmEMSquare = ft_face->units_per_EM;
6799 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6800 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6801 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6802 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6803 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6804 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6805 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6806 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6807 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6808 font->potm->otmMacAscent = TM.tmAscent;
6809 font->potm->otmMacDescent = -TM.tmDescent;
6810 font->potm->otmMacLineGap = font->potm->otmLineGap;
6811 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6812 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6813 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6814 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6815 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6816 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6817 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6818 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6819 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6820 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6821 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6822 if(!pPost) {
6823 font->potm->otmsUnderscoreSize = 0;
6824 font->potm->otmsUnderscorePosition = 0;
6825 } else {
6826 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6827 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6829 #undef TM
6831 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6832 cp = (char*)font->potm + sizeof(*font->potm);
6833 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6834 strcpyW((WCHAR*)cp, family_nameW);
6835 cp += lenfam;
6836 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6837 strcpyW((WCHAR*)cp, style_nameW);
6838 cp += lensty;
6839 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6840 strcpyW((WCHAR*)cp, family_nameW);
6841 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6842 strcatW((WCHAR*)cp, spaceW);
6843 strcatW((WCHAR*)cp, style_nameW);
6844 cp += lenfam + lensty;
6845 } else
6846 cp += lenfam;
6847 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6848 strcpyW((WCHAR*)cp, family_nameW);
6849 strcatW((WCHAR*)cp, spaceW);
6850 strcatW((WCHAR*)cp, style_nameW);
6851 ret = TRUE;
6853 end:
6854 HeapFree(GetProcessHeap(), 0, style_nameW);
6855 HeapFree(GetProcessHeap(), 0, family_nameW);
6856 return ret;
6859 /*************************************************************
6860 * freetype_GetGlyphOutline
6862 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6863 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6865 struct freetype_physdev *physdev = get_freetype_dev( dev );
6866 DWORD ret;
6868 if (!physdev->font)
6870 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6871 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6874 GDI_CheckNotLock();
6875 EnterCriticalSection( &freetype_cs );
6876 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6877 LeaveCriticalSection( &freetype_cs );
6878 return ret;
6881 /*************************************************************
6882 * freetype_GetTextMetrics
6884 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6886 struct freetype_physdev *physdev = get_freetype_dev( dev );
6887 BOOL ret;
6889 if (!physdev->font)
6891 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6892 return dev->funcs->pGetTextMetrics( dev, metrics );
6895 GDI_CheckNotLock();
6896 EnterCriticalSection( &freetype_cs );
6897 ret = get_text_metrics( physdev->font, metrics );
6898 LeaveCriticalSection( &freetype_cs );
6899 return ret;
6902 /*************************************************************
6903 * freetype_GetOutlineTextMetrics
6905 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6907 struct freetype_physdev *physdev = get_freetype_dev( dev );
6908 UINT ret = 0;
6910 if (!physdev->font)
6912 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6913 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6916 TRACE("font=%p\n", physdev->font);
6918 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6920 GDI_CheckNotLock();
6921 EnterCriticalSection( &freetype_cs );
6923 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6925 if(cbSize >= physdev->font->potm->otmSize)
6927 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6928 scale_outline_font_metrics(physdev->font, potm);
6930 ret = physdev->font->potm->otmSize;
6932 LeaveCriticalSection( &freetype_cs );
6933 return ret;
6936 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6938 HFONTLIST *hfontlist;
6939 child->font = alloc_font();
6940 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6941 if(!child->font->ft_face)
6943 free_font(child->font);
6944 child->font = NULL;
6945 return FALSE;
6948 child->font->font_desc = font->font_desc;
6949 child->font->ntmFlags = child->face->ntmFlags;
6950 child->font->orientation = font->orientation;
6951 child->font->scale_y = font->scale_y;
6952 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6953 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6954 child->font->name = strdupW(child->face->family->FamilyName);
6955 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6956 child->font->base_font = font;
6957 list_add_head(&child_font_list, &child->font->entry);
6958 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6959 return TRUE;
6962 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6964 FT_UInt g;
6965 CHILD_FONT *child_font;
6967 if(font->base_font)
6968 font = font->base_font;
6970 *linked_font = font;
6972 if((*glyph = get_glyph_index(font, c)))
6974 *glyph = get_GSUB_vert_glyph(font, *glyph);
6975 return TRUE;
6978 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6980 if(!child_font->font)
6981 if(!load_child_font(font, child_font))
6982 continue;
6984 if(!child_font->font->ft_face)
6985 continue;
6986 g = get_glyph_index(child_font->font, c);
6987 g = get_GSUB_vert_glyph(child_font->font, g);
6988 if(g)
6990 *glyph = g;
6991 *linked_font = child_font->font;
6992 return TRUE;
6995 return FALSE;
6998 /*************************************************************
6999 * freetype_GetCharWidth
7001 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7003 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7004 UINT c;
7005 GLYPHMETRICS gm;
7006 FT_UInt glyph_index;
7007 GdiFont *linked_font;
7008 struct freetype_physdev *physdev = get_freetype_dev( dev );
7010 if (!physdev->font)
7012 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7013 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7016 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7018 GDI_CheckNotLock();
7019 EnterCriticalSection( &freetype_cs );
7020 for(c = firstChar; c <= lastChar; c++) {
7021 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
7022 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7023 &gm, 0, NULL, &identity);
7024 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
7026 LeaveCriticalSection( &freetype_cs );
7027 return TRUE;
7030 /*************************************************************
7031 * freetype_GetCharABCWidths
7033 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7035 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7036 UINT c;
7037 GLYPHMETRICS gm;
7038 FT_UInt glyph_index;
7039 GdiFont *linked_font;
7040 struct freetype_physdev *physdev = get_freetype_dev( dev );
7042 if (!physdev->font)
7044 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7045 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7048 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7050 GDI_CheckNotLock();
7051 EnterCriticalSection( &freetype_cs );
7053 for(c = firstChar; c <= lastChar; c++) {
7054 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
7055 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7056 &gm, 0, NULL, &identity);
7057 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
7058 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
7059 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
7060 FONT_GM(linked_font,glyph_index)->bbx;
7062 LeaveCriticalSection( &freetype_cs );
7063 return TRUE;
7066 /*************************************************************
7067 * freetype_GetCharABCWidthsI
7069 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7071 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7072 UINT c;
7073 GLYPHMETRICS gm;
7074 FT_UInt glyph_index;
7075 GdiFont *linked_font;
7076 struct freetype_physdev *physdev = get_freetype_dev( dev );
7078 if (!physdev->font)
7080 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7081 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7084 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7085 return FALSE;
7087 GDI_CheckNotLock();
7088 EnterCriticalSection( &freetype_cs );
7090 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
7091 if (!pgi)
7092 for(c = firstChar; c < firstChar+count; c++) {
7093 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
7094 &gm, 0, NULL, &identity);
7095 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
7096 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
7097 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
7098 - FONT_GM(linked_font,c)->bbx;
7100 else
7101 for(c = 0; c < count; c++) {
7102 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
7103 &gm, 0, NULL, &identity);
7104 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
7105 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
7106 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
7107 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
7110 LeaveCriticalSection( &freetype_cs );
7111 return TRUE;
7114 /*************************************************************
7115 * freetype_GetTextExtentExPoint
7117 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
7118 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
7120 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7121 INT idx;
7122 INT nfit = 0, ext;
7123 GLYPHMETRICS gm;
7124 TEXTMETRICW tm;
7125 FT_UInt glyph_index;
7126 GdiFont *linked_font;
7127 struct freetype_physdev *physdev = get_freetype_dev( dev );
7129 if (!physdev->font)
7131 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7132 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
7135 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
7137 GDI_CheckNotLock();
7138 EnterCriticalSection( &freetype_cs );
7140 size->cx = 0;
7141 get_text_metrics( physdev->font, &tm );
7142 size->cy = tm.tmHeight;
7144 for(idx = 0; idx < count; idx++) {
7145 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
7146 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7147 &gm, 0, NULL, &identity);
7148 size->cx += FONT_GM(linked_font,glyph_index)->adv;
7149 ext = size->cx;
7150 if (! pnfit || ext <= max_ext) {
7151 ++nfit;
7152 if (dxs)
7153 dxs[idx] = ext;
7157 if (pnfit)
7158 *pnfit = nfit;
7160 LeaveCriticalSection( &freetype_cs );
7161 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7162 return TRUE;
7165 /*************************************************************
7166 * freetype_GetTextExtentExPointI
7168 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
7169 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
7171 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7172 INT idx;
7173 INT nfit = 0, ext;
7174 GLYPHMETRICS gm;
7175 TEXTMETRICW tm;
7176 struct freetype_physdev *physdev = get_freetype_dev( dev );
7178 if (!physdev->font)
7180 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7181 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
7184 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
7186 GDI_CheckNotLock();
7187 EnterCriticalSection( &freetype_cs );
7189 size->cx = 0;
7190 get_text_metrics(physdev->font, &tm);
7191 size->cy = tm.tmHeight;
7193 for(idx = 0; idx < count; idx++) {
7194 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
7195 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
7196 ext = size->cx;
7197 if (! pnfit || ext <= max_ext) {
7198 ++nfit;
7199 if (dxs)
7200 dxs[idx] = ext;
7204 if (pnfit)
7205 *pnfit = nfit;
7207 LeaveCriticalSection( &freetype_cs );
7208 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7209 return TRUE;
7212 /*************************************************************
7213 * freetype_GetFontData
7215 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7217 struct freetype_physdev *physdev = get_freetype_dev( dev );
7219 if (!physdev->font)
7221 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7222 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7225 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7226 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7227 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7229 return get_font_data( physdev->font, table, offset, buf, cbData );
7232 /*************************************************************
7233 * freetype_GetTextFace
7235 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7237 INT n;
7238 struct freetype_physdev *physdev = get_freetype_dev( dev );
7240 if (!physdev->font)
7242 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7243 return dev->funcs->pGetTextFace( dev, count, str );
7246 n = strlenW(physdev->font->name) + 1;
7247 if (str)
7249 lstrcpynW(str, physdev->font->name, count);
7250 n = min(count, n);
7252 return n;
7255 /*************************************************************
7256 * freetype_GetTextCharsetInfo
7258 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7260 struct freetype_physdev *physdev = get_freetype_dev( dev );
7262 if (!physdev->font)
7264 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7265 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7267 if (fs) *fs = physdev->font->fs;
7268 return physdev->font->charset;
7271 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7273 GdiFont *font = dc->gdiFont, *linked_font;
7274 struct list *first_hfont;
7275 BOOL ret;
7277 GDI_CheckNotLock();
7278 EnterCriticalSection( &freetype_cs );
7279 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
7280 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
7281 if(font == linked_font)
7282 *new_hfont = dc->hFont;
7283 else
7285 first_hfont = list_head(&linked_font->hfontlist);
7286 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
7288 LeaveCriticalSection( &freetype_cs );
7289 return ret;
7292 /* Retrieve a list of supported Unicode ranges for a given font.
7293 * Can be called with NULL gs to calculate the buffer size. Returns
7294 * the number of ranges found.
7296 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7298 DWORD num_ranges = 0;
7300 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7302 FT_UInt glyph_code;
7303 FT_ULong char_code, char_code_prev;
7305 glyph_code = 0;
7306 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7308 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7309 face->num_glyphs, glyph_code, char_code);
7311 if (!glyph_code) return 0;
7313 if (gs)
7315 gs->ranges[0].wcLow = (USHORT)char_code;
7316 gs->ranges[0].cGlyphs = 0;
7317 gs->cGlyphsSupported = 0;
7320 num_ranges = 1;
7321 while (glyph_code)
7323 if (char_code < char_code_prev)
7325 ERR("expected increasing char code from FT_Get_Next_Char\n");
7326 return 0;
7328 if (char_code - char_code_prev > 1)
7330 num_ranges++;
7331 if (gs)
7333 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7334 gs->ranges[num_ranges - 1].cGlyphs = 1;
7335 gs->cGlyphsSupported++;
7338 else if (gs)
7340 gs->ranges[num_ranges - 1].cGlyphs++;
7341 gs->cGlyphsSupported++;
7343 char_code_prev = char_code;
7344 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7347 else
7348 FIXME("encoding %u not supported\n", face->charmap->encoding);
7350 return num_ranges;
7353 /*************************************************************
7354 * freetype_GetFontUnicodeRanges
7356 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7358 struct freetype_physdev *physdev = get_freetype_dev( dev );
7359 DWORD size, num_ranges;
7361 if (!physdev->font)
7363 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7364 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7367 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7368 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7369 if (glyphset)
7371 glyphset->cbThis = size;
7372 glyphset->cRanges = num_ranges;
7373 glyphset->flAccel = 0;
7375 return size;
7378 /*************************************************************
7379 * freetype_FontIsLinked
7381 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7383 struct freetype_physdev *physdev = get_freetype_dev( dev );
7384 BOOL ret;
7386 if (!physdev->font)
7388 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7389 return dev->funcs->pFontIsLinked( dev );
7392 GDI_CheckNotLock();
7393 EnterCriticalSection( &freetype_cs );
7394 ret = !list_empty(&physdev->font->child_fonts);
7395 LeaveCriticalSection( &freetype_cs );
7396 return ret;
7399 static BOOL is_hinting_enabled(void)
7401 /* Use the >= 2.2.0 function if available */
7402 if(pFT_Get_TrueType_Engine_Type)
7404 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
7405 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
7407 #ifdef FT_DRIVER_HAS_HINTER
7408 else
7410 FT_Module mod;
7412 /* otherwise if we've been compiled with < 2.2.0 headers
7413 use the internal macro */
7414 mod = pFT_Get_Module(library, "truetype");
7415 if(mod && FT_DRIVER_HAS_HINTER(mod))
7416 return TRUE;
7418 #endif
7420 return FALSE;
7423 static BOOL is_subpixel_rendering_enabled( void )
7425 #ifdef HAVE_FREETYPE_FTLCDFIL_H
7426 return pFT_Library_SetLcdFilter &&
7427 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
7428 #else
7429 return FALSE;
7430 #endif
7433 /*************************************************************************
7434 * GetRasterizerCaps (GDI32.@)
7436 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7438 static int hinting = -1;
7439 static int subpixel = -1;
7441 if(hinting == -1)
7443 hinting = is_hinting_enabled();
7444 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
7447 if ( subpixel == -1 )
7449 subpixel = is_subpixel_rendering_enabled();
7450 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
7453 lprs->nSize = sizeof(RASTERIZER_STATUS);
7454 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
7455 if ( subpixel )
7456 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
7457 lprs->nLanguageID = 0;
7458 return TRUE;
7461 /*************************************************************
7462 * freetype_GdiRealizationInfo
7464 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7466 struct freetype_physdev *physdev = get_freetype_dev( dev );
7467 realization_info_t *info = ptr;
7469 if (!physdev->font)
7471 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7472 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7475 FIXME("(%p, %p): stub!\n", physdev->font, info);
7477 info->flags = 1;
7478 if(FT_IS_SCALABLE(physdev->font->ft_face))
7479 info->flags |= 2;
7481 info->cache_num = physdev->font->cache_num;
7482 info->unknown2 = -1;
7483 return TRUE;
7486 /*************************************************************************
7487 * Kerning support for TrueType fonts
7489 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7491 struct TT_kern_table
7493 USHORT version;
7494 USHORT nTables;
7497 struct TT_kern_subtable
7499 USHORT version;
7500 USHORT length;
7501 union
7503 USHORT word;
7504 struct
7506 USHORT horizontal : 1;
7507 USHORT minimum : 1;
7508 USHORT cross_stream: 1;
7509 USHORT override : 1;
7510 USHORT reserved1 : 4;
7511 USHORT format : 8;
7512 } bits;
7513 } coverage;
7516 struct TT_format0_kern_subtable
7518 USHORT nPairs;
7519 USHORT searchRange;
7520 USHORT entrySelector;
7521 USHORT rangeShift;
7524 struct TT_kern_pair
7526 USHORT left;
7527 USHORT right;
7528 short value;
7531 static DWORD parse_format0_kern_subtable(GdiFont *font,
7532 const struct TT_format0_kern_subtable *tt_f0_ks,
7533 const USHORT *glyph_to_char,
7534 KERNINGPAIR *kern_pair, DWORD cPairs)
7536 USHORT i, nPairs;
7537 const struct TT_kern_pair *tt_kern_pair;
7539 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7541 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7543 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7544 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7545 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7547 if (!kern_pair || !cPairs)
7548 return nPairs;
7550 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7552 nPairs = min(nPairs, cPairs);
7554 for (i = 0; i < nPairs; i++)
7556 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7557 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7558 /* this algorithm appears to better match what Windows does */
7559 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7560 if (kern_pair->iKernAmount < 0)
7562 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7563 kern_pair->iKernAmount -= font->ppem;
7565 else if (kern_pair->iKernAmount > 0)
7567 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7568 kern_pair->iKernAmount += font->ppem;
7570 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7572 TRACE("left %u right %u value %d\n",
7573 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7575 kern_pair++;
7577 TRACE("copied %u entries\n", nPairs);
7578 return nPairs;
7581 /*************************************************************
7582 * freetype_GetKerningPairs
7584 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7586 DWORD length;
7587 void *buf;
7588 const struct TT_kern_table *tt_kern_table;
7589 const struct TT_kern_subtable *tt_kern_subtable;
7590 USHORT i, nTables;
7591 USHORT *glyph_to_char;
7592 GdiFont *font;
7593 struct freetype_physdev *physdev = get_freetype_dev( dev );
7595 if (!(font = physdev->font))
7597 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7598 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7601 GDI_CheckNotLock();
7602 EnterCriticalSection( &freetype_cs );
7603 if (font->total_kern_pairs != (DWORD)-1)
7605 if (cPairs && kern_pair)
7607 cPairs = min(cPairs, font->total_kern_pairs);
7608 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7610 else cPairs = font->total_kern_pairs;
7612 LeaveCriticalSection( &freetype_cs );
7613 return cPairs;
7616 font->total_kern_pairs = 0;
7618 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7620 if (length == GDI_ERROR)
7622 TRACE("no kerning data in the font\n");
7623 LeaveCriticalSection( &freetype_cs );
7624 return 0;
7627 buf = HeapAlloc(GetProcessHeap(), 0, length);
7628 if (!buf)
7630 WARN("Out of memory\n");
7631 LeaveCriticalSection( &freetype_cs );
7632 return 0;
7635 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7637 /* build a glyph index to char code map */
7638 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7639 if (!glyph_to_char)
7641 WARN("Out of memory allocating a glyph index to char code map\n");
7642 HeapFree(GetProcessHeap(), 0, buf);
7643 LeaveCriticalSection( &freetype_cs );
7644 return 0;
7647 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7649 FT_UInt glyph_code;
7650 FT_ULong char_code;
7652 glyph_code = 0;
7653 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7655 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7656 font->ft_face->num_glyphs, glyph_code, char_code);
7658 while (glyph_code)
7660 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7662 /* FIXME: This doesn't match what Windows does: it does some fancy
7663 * things with duplicate glyph index to char code mappings, while
7664 * we just avoid overriding existing entries.
7666 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7667 glyph_to_char[glyph_code] = (USHORT)char_code;
7669 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7672 else
7674 ULONG n;
7676 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7677 for (n = 0; n <= 65535; n++)
7678 glyph_to_char[n] = (USHORT)n;
7681 tt_kern_table = buf;
7682 nTables = GET_BE_WORD(tt_kern_table->nTables);
7683 TRACE("version %u, nTables %u\n",
7684 GET_BE_WORD(tt_kern_table->version), nTables);
7686 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7688 for (i = 0; i < nTables; i++)
7690 struct TT_kern_subtable tt_kern_subtable_copy;
7692 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7693 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7694 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7696 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7697 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7698 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7700 /* According to the TrueType specification this is the only format
7701 * that will be properly interpreted by Windows and OS/2
7703 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7705 DWORD new_chunk, old_total = font->total_kern_pairs;
7707 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7708 glyph_to_char, NULL, 0);
7709 font->total_kern_pairs += new_chunk;
7711 if (!font->kern_pairs)
7712 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7713 font->total_kern_pairs * sizeof(*font->kern_pairs));
7714 else
7715 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7716 font->total_kern_pairs * sizeof(*font->kern_pairs));
7718 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7719 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7721 else
7722 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7724 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7727 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7728 HeapFree(GetProcessHeap(), 0, buf);
7730 if (cPairs && kern_pair)
7732 cPairs = min(cPairs, font->total_kern_pairs);
7733 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7735 else cPairs = font->total_kern_pairs;
7737 LeaveCriticalSection( &freetype_cs );
7738 return cPairs;
7741 static const struct gdi_dc_funcs freetype_funcs =
7743 NULL, /* pAbortDoc */
7744 NULL, /* pAbortPath */
7745 NULL, /* pAlphaBlend */
7746 NULL, /* pAngleArc */
7747 NULL, /* pArc */
7748 NULL, /* pArcTo */
7749 NULL, /* pBeginPath */
7750 NULL, /* pBlendImage */
7751 NULL, /* pChord */
7752 NULL, /* pCloseFigure */
7753 NULL, /* pCreateCompatibleDC */
7754 freetype_CreateDC, /* pCreateDC */
7755 freetype_DeleteDC, /* pDeleteDC */
7756 NULL, /* pDeleteObject */
7757 NULL, /* pDeviceCapabilities */
7758 NULL, /* pEllipse */
7759 NULL, /* pEndDoc */
7760 NULL, /* pEndPage */
7761 NULL, /* pEndPath */
7762 freetype_EnumFonts, /* pEnumFonts */
7763 NULL, /* pEnumICMProfiles */
7764 NULL, /* pExcludeClipRect */
7765 NULL, /* pExtDeviceMode */
7766 NULL, /* pExtEscape */
7767 NULL, /* pExtFloodFill */
7768 NULL, /* pExtSelectClipRgn */
7769 NULL, /* pExtTextOut */
7770 NULL, /* pFillPath */
7771 NULL, /* pFillRgn */
7772 NULL, /* pFlattenPath */
7773 freetype_FontIsLinked, /* pFontIsLinked */
7774 NULL, /* pFrameRgn */
7775 NULL, /* pGdiComment */
7776 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7777 NULL, /* pGetBoundsRect */
7778 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7779 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7780 freetype_GetCharWidth, /* pGetCharWidth */
7781 NULL, /* pGetDeviceCaps */
7782 NULL, /* pGetDeviceGammaRamp */
7783 freetype_GetFontData, /* pGetFontData */
7784 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7785 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7786 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7787 NULL, /* pGetICMProfile */
7788 NULL, /* pGetImage */
7789 freetype_GetKerningPairs, /* pGetKerningPairs */
7790 NULL, /* pGetNearestColor */
7791 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7792 NULL, /* pGetPixel */
7793 NULL, /* pGetSystemPaletteEntries */
7794 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7795 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7796 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7797 freetype_GetTextFace, /* pGetTextFace */
7798 freetype_GetTextMetrics, /* pGetTextMetrics */
7799 NULL, /* pGradientFill */
7800 NULL, /* pIntersectClipRect */
7801 NULL, /* pInvertRgn */
7802 NULL, /* pLineTo */
7803 NULL, /* pModifyWorldTransform */
7804 NULL, /* pMoveTo */
7805 NULL, /* pOffsetClipRgn */
7806 NULL, /* pOffsetViewportOrg */
7807 NULL, /* pOffsetWindowOrg */
7808 NULL, /* pPaintRgn */
7809 NULL, /* pPatBlt */
7810 NULL, /* pPie */
7811 NULL, /* pPolyBezier */
7812 NULL, /* pPolyBezierTo */
7813 NULL, /* pPolyDraw */
7814 NULL, /* pPolyPolygon */
7815 NULL, /* pPolyPolyline */
7816 NULL, /* pPolygon */
7817 NULL, /* pPolyline */
7818 NULL, /* pPolylineTo */
7819 NULL, /* pPutImage */
7820 NULL, /* pRealizeDefaultPalette */
7821 NULL, /* pRealizePalette */
7822 NULL, /* pRectangle */
7823 NULL, /* pResetDC */
7824 NULL, /* pRestoreDC */
7825 NULL, /* pRoundRect */
7826 NULL, /* pSaveDC */
7827 NULL, /* pScaleViewportExt */
7828 NULL, /* pScaleWindowExt */
7829 NULL, /* pSelectBitmap */
7830 NULL, /* pSelectBrush */
7831 NULL, /* pSelectClipPath */
7832 freetype_SelectFont, /* pSelectFont */
7833 NULL, /* pSelectPalette */
7834 NULL, /* pSelectPen */
7835 NULL, /* pSetArcDirection */
7836 NULL, /* pSetBkColor */
7837 NULL, /* pSetBkMode */
7838 NULL, /* pSetDCBrushColor */
7839 NULL, /* pSetDCPenColor */
7840 NULL, /* pSetDIBColorTable */
7841 NULL, /* pSetDIBitsToDevice */
7842 NULL, /* pSetDeviceClipping */
7843 NULL, /* pSetDeviceGammaRamp */
7844 NULL, /* pSetLayout */
7845 NULL, /* pSetMapMode */
7846 NULL, /* pSetMapperFlags */
7847 NULL, /* pSetPixel */
7848 NULL, /* pSetPolyFillMode */
7849 NULL, /* pSetROP2 */
7850 NULL, /* pSetRelAbs */
7851 NULL, /* pSetStretchBltMode */
7852 NULL, /* pSetTextAlign */
7853 NULL, /* pSetTextCharacterExtra */
7854 NULL, /* pSetTextColor */
7855 NULL, /* pSetTextJustification */
7856 NULL, /* pSetViewportExt */
7857 NULL, /* pSetViewportOrg */
7858 NULL, /* pSetWindowExt */
7859 NULL, /* pSetWindowOrg */
7860 NULL, /* pSetWorldTransform */
7861 NULL, /* pStartDoc */
7862 NULL, /* pStartPage */
7863 NULL, /* pStretchBlt */
7864 NULL, /* pStretchDIBits */
7865 NULL, /* pStrokeAndFillPath */
7866 NULL, /* pStrokePath */
7867 NULL, /* pSwapBuffers */
7868 NULL, /* pUnrealizePalette */
7869 NULL, /* pWidenPath */
7870 NULL, /* wine_get_wgl_driver */
7871 GDI_PRIORITY_FONT_DRV /* priority */
7874 #else /* HAVE_FREETYPE */
7876 /*************************************************************************/
7878 BOOL WineEngInit(void)
7880 return FALSE;
7882 BOOL WineEngDestroyFontInstance(HFONT hfont)
7884 return FALSE;
7887 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7889 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7890 return 1;
7893 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7895 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7896 return TRUE;
7899 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7901 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7902 return NULL;
7905 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
7906 LPCWSTR font_file, LPCWSTR font_path )
7908 FIXME("stub\n");
7909 return FALSE;
7912 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7914 return FALSE;
7917 /*************************************************************************
7918 * GetRasterizerCaps (GDI32.@)
7920 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7922 lprs->nSize = sizeof(RASTERIZER_STATUS);
7923 lprs->wFlags = 0;
7924 lprs->nLanguageID = 0;
7925 return TRUE;
7928 #endif /* HAVE_FREETYPE */