gdi32: Avoid redundant computation of the gradient bounding rectangle.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blob58a081a439e4583b4230e5937035774924a78ba1
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 FONTSIGNATURE fs;
346 GdiFont *base_font;
347 VOID *GSUB_Table;
348 DWORD cache_num;
351 typedef struct {
352 struct list entry;
353 const WCHAR *font_name;
354 FONTSIGNATURE fs;
355 struct list links;
356 } SYSTEM_LINKS;
358 struct enum_charset_element {
359 DWORD mask;
360 DWORD charset;
361 WCHAR name[LF_FACESIZE];
364 struct enum_charset_list {
365 DWORD total;
366 struct enum_charset_element element[32];
369 #define GM_BLOCK_SIZE 128
370 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
372 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
373 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
374 #define UNUSED_CACHE_SIZE 10
375 static struct list child_font_list = LIST_INIT(child_font_list);
376 static struct list system_links = LIST_INIT(system_links);
378 static struct list font_subst_list = LIST_INIT(font_subst_list);
380 static struct list font_list = LIST_INIT(font_list);
382 struct freetype_physdev
384 struct gdi_physdev dev;
385 GdiFont *font;
388 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
390 return (struct freetype_physdev *)dev;
393 static const struct gdi_dc_funcs freetype_funcs;
395 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
396 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
397 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
399 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
400 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
401 'W','i','n','d','o','w','s','\\',
402 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
403 'F','o','n','t','s','\0'};
405 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
406 'W','i','n','d','o','w','s',' ','N','T','\\',
407 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
408 'F','o','n','t','s','\0'};
410 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
411 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
412 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
413 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
415 static const WCHAR * const SystemFontValues[] = {
416 System_Value,
417 OEMFont_Value,
418 FixedSys_Value,
419 NULL
422 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
423 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
425 /* Interesting and well-known (frequently-assumed!) font names */
426 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
427 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 };
428 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
429 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
430 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
431 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
432 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
433 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
435 static const WCHAR arial[] = {'A','r','i','a','l',0};
436 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
437 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};
438 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};
439 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
440 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
441 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
442 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
443 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
444 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
446 static const WCHAR *default_serif_list[] =
448 times_new_roman,
449 liberation_serif,
450 bitstream_vera_serif,
451 NULL
454 static const WCHAR *default_fixed_list[] =
456 courier_new,
457 liberation_mono,
458 bitstream_vera_sans_mono,
459 NULL
462 static const WCHAR *default_sans_list[] =
464 arial,
465 liberation_sans,
466 bitstream_vera_sans,
467 NULL
470 typedef struct {
471 WCHAR *name;
472 INT charset;
473 } NameCs;
475 typedef struct tagFontSubst {
476 struct list entry;
477 NameCs from;
478 NameCs to;
479 } FontSubst;
481 /* Registry font cache key and value names */
482 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
483 'F','o','n','t','s',0};
484 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
485 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
486 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
487 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
488 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
489 static const WCHAR face_vertical_value[] = {'V','e','r','t','i','c','a','l',0};
490 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
491 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
492 static const WCHAR face_size_value[] = {'S','i','z','e',0};
493 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
494 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
495 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
496 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
497 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
500 struct font_mapping
502 struct list entry;
503 int refcount;
504 dev_t dev;
505 ino_t ino;
506 void *data;
507 size_t size;
510 static struct list mappings_list = LIST_INIT( mappings_list );
512 static CRITICAL_SECTION freetype_cs;
513 static CRITICAL_SECTION_DEBUG critsect_debug =
515 0, 0, &freetype_cs,
516 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
517 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
519 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
521 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
523 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
524 static BOOL use_default_fallback = FALSE;
526 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
527 static BOOL get_outline_text_metrics(GdiFont *font);
528 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
530 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
531 'W','i','n','d','o','w','s',' ','N','T','\\',
532 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
533 'S','y','s','t','e','m','L','i','n','k',0};
535 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
536 'F','o','n','t','L','i','n','k','\\',
537 'S','y','s','t','e','m','L','i','n','k',0};
539 /****************************************
540 * Notes on .fon files
542 * The fonts System, FixedSys and Terminal are special. There are typically multiple
543 * versions installed for different resolutions and codepages. Windows stores which one to use
544 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
545 * Key Meaning
546 * FIXEDFON.FON FixedSys
547 * FONTS.FON System
548 * OEMFONT.FON Terminal
549 * LogPixels Current dpi set by the display control panel applet
550 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
551 * also has a LogPixels value that appears to mirror this)
553 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
554 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
555 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
556 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
557 * so that makes sense.
559 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
560 * to be mapped into the registry on Windows 2000 at least).
561 * I have
562 * woafont=app850.fon
563 * ega80woa.fon=ega80850.fon
564 * ega40woa.fon=ega40850.fon
565 * cga80woa.fon=cga80850.fon
566 * cga40woa.fon=cga40850.fon
569 /* These are all structures needed for the GSUB table */
571 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
572 #define TATEGAKI_LOWER_BOUND 0x02F1
574 typedef struct {
575 DWORD version;
576 WORD ScriptList;
577 WORD FeatureList;
578 WORD LookupList;
579 } GSUB_Header;
581 typedef struct {
582 CHAR ScriptTag[4];
583 WORD Script;
584 } GSUB_ScriptRecord;
586 typedef struct {
587 WORD ScriptCount;
588 GSUB_ScriptRecord ScriptRecord[1];
589 } GSUB_ScriptList;
591 typedef struct {
592 CHAR LangSysTag[4];
593 WORD LangSys;
594 } GSUB_LangSysRecord;
596 typedef struct {
597 WORD DefaultLangSys;
598 WORD LangSysCount;
599 GSUB_LangSysRecord LangSysRecord[1];
600 } GSUB_Script;
602 typedef struct {
603 WORD LookupOrder; /* Reserved */
604 WORD ReqFeatureIndex;
605 WORD FeatureCount;
606 WORD FeatureIndex[1];
607 } GSUB_LangSys;
609 typedef struct {
610 CHAR FeatureTag[4];
611 WORD Feature;
612 } GSUB_FeatureRecord;
614 typedef struct {
615 WORD FeatureCount;
616 GSUB_FeatureRecord FeatureRecord[1];
617 } GSUB_FeatureList;
619 typedef struct {
620 WORD FeatureParams; /* Reserved */
621 WORD LookupCount;
622 WORD LookupListIndex[1];
623 } GSUB_Feature;
625 typedef struct {
626 WORD LookupCount;
627 WORD Lookup[1];
628 } GSUB_LookupList;
630 typedef struct {
631 WORD LookupType;
632 WORD LookupFlag;
633 WORD SubTableCount;
634 WORD SubTable[1];
635 } GSUB_LookupTable;
637 typedef struct {
638 WORD CoverageFormat;
639 WORD GlyphCount;
640 WORD GlyphArray[1];
641 } GSUB_CoverageFormat1;
643 typedef struct {
644 WORD Start;
645 WORD End;
646 WORD StartCoverageIndex;
647 } GSUB_RangeRecord;
649 typedef struct {
650 WORD CoverageFormat;
651 WORD RangeCount;
652 GSUB_RangeRecord RangeRecord[1];
653 } GSUB_CoverageFormat2;
655 typedef struct {
656 WORD SubstFormat; /* = 1 */
657 WORD Coverage;
658 WORD DeltaGlyphID;
659 } GSUB_SingleSubstFormat1;
661 typedef struct {
662 WORD SubstFormat; /* = 2 */
663 WORD Coverage;
664 WORD GlyphCount;
665 WORD Substitute[1];
666 }GSUB_SingleSubstFormat2;
668 #ifdef HAVE_CARBON_CARBON_H
669 static char *find_cache_dir(void)
671 FSRef ref;
672 OSErr err;
673 static char cached_path[MAX_PATH];
674 static const char *wine = "/Wine", *fonts = "/Fonts";
676 if(*cached_path) return cached_path;
678 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
679 if(err != noErr)
681 WARN("can't create cached data folder\n");
682 return NULL;
684 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
685 if(err != noErr)
687 WARN("can't create cached data path\n");
688 *cached_path = '\0';
689 return NULL;
691 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
693 ERR("Could not create full path\n");
694 *cached_path = '\0';
695 return NULL;
697 strcat(cached_path, wine);
699 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
701 WARN("Couldn't mkdir %s\n", cached_path);
702 *cached_path = '\0';
703 return NULL;
705 strcat(cached_path, fonts);
706 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
708 WARN("Couldn't mkdir %s\n", cached_path);
709 *cached_path = '\0';
710 return NULL;
712 return cached_path;
715 /******************************************************************
716 * expand_mac_font
718 * Extracts individual TrueType font files from a Mac suitcase font
719 * and saves them into the user's caches directory (see
720 * find_cache_dir()).
721 * Returns a NULL terminated array of filenames.
723 * We do this because they are apps that try to read ttf files
724 * themselves and they don't like Mac suitcase files.
726 static char **expand_mac_font(const char *path)
728 FSRef ref;
729 SInt16 res_ref;
730 OSStatus s;
731 unsigned int idx;
732 const char *out_dir;
733 const char *filename;
734 int output_len;
735 struct {
736 char **array;
737 unsigned int size, max_size;
738 } ret;
740 TRACE("path %s\n", path);
742 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
743 if(s != noErr)
745 WARN("failed to get ref\n");
746 return NULL;
749 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
750 if(s != noErr)
752 TRACE("no data fork, so trying resource fork\n");
753 res_ref = FSOpenResFile(&ref, fsRdPerm);
754 if(res_ref == -1)
756 TRACE("unable to open resource fork\n");
757 return NULL;
761 ret.size = 0;
762 ret.max_size = 10;
763 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
764 if(!ret.array)
766 CloseResFile(res_ref);
767 return NULL;
770 out_dir = find_cache_dir();
772 filename = strrchr(path, '/');
773 if(!filename) filename = path;
774 else filename++;
776 /* output filename has the form out_dir/filename_%04x.ttf */
777 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
779 UseResFile(res_ref);
780 idx = 1;
781 while(1)
783 FamRec *fam_rec;
784 unsigned short *num_faces_ptr, num_faces, face;
785 AsscEntry *assoc;
786 Handle fond;
787 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
789 fond = Get1IndResource(fond_res, idx);
790 if(!fond) break;
791 TRACE("got fond resource %d\n", idx);
792 HLock(fond);
794 fam_rec = *(FamRec**)fond;
795 num_faces_ptr = (unsigned short *)(fam_rec + 1);
796 num_faces = GET_BE_WORD(*num_faces_ptr);
797 num_faces++;
798 assoc = (AsscEntry*)(num_faces_ptr + 1);
799 TRACE("num faces %04x\n", num_faces);
800 for(face = 0; face < num_faces; face++, assoc++)
802 Handle sfnt;
803 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
804 unsigned short size, font_id;
805 char *output;
807 size = GET_BE_WORD(assoc->fontSize);
808 font_id = GET_BE_WORD(assoc->fontID);
809 if(size != 0)
811 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
812 continue;
815 TRACE("trying to load sfnt id %04x\n", font_id);
816 sfnt = GetResource(sfnt_res, font_id);
817 if(!sfnt)
819 TRACE("can't get sfnt resource %04x\n", font_id);
820 continue;
823 output = HeapAlloc(GetProcessHeap(), 0, output_len);
824 if(output)
826 int fd;
828 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
830 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
831 if(fd != -1 || errno == EEXIST)
833 if(fd != -1)
835 unsigned char *sfnt_data;
837 HLock(sfnt);
838 sfnt_data = *(unsigned char**)sfnt;
839 write(fd, sfnt_data, GetHandleSize(sfnt));
840 HUnlock(sfnt);
841 close(fd);
843 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
845 ret.max_size *= 2;
846 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
848 ret.array[ret.size++] = output;
850 else
852 WARN("unable to create %s\n", output);
853 HeapFree(GetProcessHeap(), 0, output);
856 ReleaseResource(sfnt);
858 HUnlock(fond);
859 ReleaseResource(fond);
860 idx++;
862 CloseResFile(res_ref);
864 return ret.array;
867 #endif /* HAVE_CARBON_CARBON_H */
869 static inline BOOL is_win9x(void)
871 return GetVersion() & 0x80000000;
874 This function builds an FT_Fixed from a double. It fails if the absolute
875 value of the float number is greater than 32768.
877 static inline FT_Fixed FT_FixedFromFloat(double f)
879 return f * 0x10000;
883 This function builds an FT_Fixed from a FIXED. It simply put f.value
884 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
886 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
888 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
892 static const struct list *get_face_list_from_family(const Family *family)
894 if (!list_empty(&family->faces))
895 return &family->faces;
896 else
897 return family->replacement;
900 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
902 Family *family;
903 Face *face;
904 const char *file;
905 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
906 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
908 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
909 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
911 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
913 const struct list *face_list;
914 if(face_name && strcmpiW(face_name, family->FamilyName))
915 continue;
916 face_list = get_face_list_from_family(family);
917 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
919 if (!face->file)
920 continue;
921 file = strrchr(face->file, '/');
922 if(!file)
923 file = face->file;
924 else
925 file++;
926 if(!strcasecmp(file, file_nameA))
928 HeapFree(GetProcessHeap(), 0, file_nameA);
929 return face;
933 HeapFree(GetProcessHeap(), 0, file_nameA);
934 return NULL;
937 static Family *find_family_from_name(const WCHAR *name)
939 Family *family;
941 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
943 if(!strcmpiW(family->FamilyName, name))
944 return family;
947 return NULL;
950 static Family *find_family_from_any_name(const WCHAR *name)
952 Family *family;
954 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
956 if(!strcmpiW(family->FamilyName, name))
957 return family;
958 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
959 return family;
962 return NULL;
965 static void DumpSubstList(void)
967 FontSubst *psub;
969 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
971 if(psub->from.charset != -1 || psub->to.charset != -1)
972 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
973 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
974 else
975 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
976 debugstr_w(psub->to.name));
978 return;
981 static LPWSTR strdupW(LPCWSTR p)
983 LPWSTR ret;
984 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
985 ret = HeapAlloc(GetProcessHeap(), 0, len);
986 memcpy(ret, p, len);
987 return ret;
990 static LPSTR strdupA(LPCSTR p)
992 LPSTR ret;
993 DWORD len = (strlen(p) + 1);
994 ret = HeapAlloc(GetProcessHeap(), 0, len);
995 memcpy(ret, p, len);
996 return ret;
999 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1000 INT from_charset)
1002 FontSubst *element;
1004 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1006 if(!strcmpiW(element->from.name, from_name) &&
1007 (element->from.charset == from_charset ||
1008 element->from.charset == -1))
1009 return element;
1012 return NULL;
1015 #define ADD_FONT_SUBST_FORCE 1
1017 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1019 FontSubst *from_exist, *to_exist;
1021 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1023 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1025 list_remove(&from_exist->entry);
1026 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
1027 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
1028 HeapFree(GetProcessHeap(), 0, from_exist);
1029 from_exist = NULL;
1032 if(!from_exist)
1034 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1036 if(to_exist)
1038 HeapFree(GetProcessHeap(), 0, subst->to.name);
1039 subst->to.name = strdupW(to_exist->to.name);
1042 list_add_tail(subst_list, &subst->entry);
1044 return TRUE;
1047 HeapFree(GetProcessHeap(), 0, subst->from.name);
1048 HeapFree(GetProcessHeap(), 0, subst->to.name);
1049 HeapFree(GetProcessHeap(), 0, subst);
1050 return FALSE;
1053 static WCHAR *towstr(UINT cp, const char *str)
1055 int len;
1056 WCHAR *wstr;
1058 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1059 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1060 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1061 return wstr;
1064 static void split_subst_info(NameCs *nc, LPSTR str)
1066 CHAR *p = strrchr(str, ',');
1068 nc->charset = -1;
1069 if(p && *(p+1)) {
1070 nc->charset = strtol(p+1, NULL, 10);
1071 *p = '\0';
1073 nc->name = towstr(CP_ACP, str);
1076 static void LoadSubstList(void)
1078 FontSubst *psub;
1079 HKEY hkey;
1080 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1081 LPSTR value;
1082 LPVOID data;
1084 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1085 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1086 &hkey) == ERROR_SUCCESS) {
1088 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1089 &valuelen, &datalen, NULL, NULL);
1091 valuelen++; /* returned value doesn't include room for '\0' */
1092 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1093 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1095 dlen = datalen;
1096 vlen = valuelen;
1097 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1098 &dlen) == ERROR_SUCCESS) {
1099 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1101 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1102 split_subst_info(&psub->from, value);
1103 split_subst_info(&psub->to, data);
1105 /* Win 2000 doesn't allow mapping between different charsets
1106 or mapping of DEFAULT_CHARSET */
1107 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1108 psub->to.charset == DEFAULT_CHARSET) {
1109 HeapFree(GetProcessHeap(), 0, psub->to.name);
1110 HeapFree(GetProcessHeap(), 0, psub->from.name);
1111 HeapFree(GetProcessHeap(), 0, psub);
1112 } else {
1113 add_font_subst(&font_subst_list, psub, 0);
1115 /* reset dlen and vlen */
1116 dlen = datalen;
1117 vlen = valuelen;
1119 HeapFree(GetProcessHeap(), 0, data);
1120 HeapFree(GetProcessHeap(), 0, value);
1121 RegCloseKey(hkey);
1126 /*****************************************************************
1127 * get_name_table_entry
1129 * Supply the platform, encoding, language and name ids in req
1130 * and if the name exists the function will fill in the string
1131 * and string_len members. The string is owned by FreeType so
1132 * don't free it. Returns TRUE if the name is found else FALSE.
1134 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1136 FT_SfntName name;
1137 FT_UInt num_names, name_index;
1139 if(FT_IS_SFNT(ft_face))
1141 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1143 for(name_index = 0; name_index < num_names; name_index++)
1145 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1147 if((name.platform_id == req->platform_id) &&
1148 (name.encoding_id == req->encoding_id) &&
1149 (name.language_id == req->language_id) &&
1150 (name.name_id == req->name_id))
1152 req->string = name.string;
1153 req->string_len = name.string_len;
1154 return TRUE;
1159 req->string = NULL;
1160 req->string_len = 0;
1161 return FALSE;
1164 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1166 WCHAR *ret = NULL;
1167 FT_SfntName name;
1169 name.platform_id = TT_PLATFORM_MICROSOFT;
1170 name.encoding_id = TT_MS_ID_UNICODE_CS;
1171 name.language_id = language_id;
1172 name.name_id = name_id;
1174 if(get_name_table_entry(ft_face, &name))
1176 FT_UInt i;
1178 /* String is not nul terminated and string_len is a byte length. */
1179 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1180 for(i = 0; i < name.string_len / 2; i++)
1182 WORD *tmp = (WORD *)&name.string[i * 2];
1183 ret[i] = GET_BE_WORD(*tmp);
1185 ret[i] = 0;
1186 TRACE("Got localised name %s\n", debugstr_w(ret));
1189 return ret;
1192 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1194 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1195 if (f1->scalable) return TRUE;
1196 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1197 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1200 static inline void free_face( Face *face )
1202 HeapFree( GetProcessHeap(), 0, face->file );
1203 HeapFree( GetProcessHeap(), 0, face->StyleName );
1204 HeapFree( GetProcessHeap(), 0, face->FullName );
1205 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1206 HeapFree( GetProcessHeap(), 0, face );
1209 static inline void free_family( Family *family )
1211 Face *face, *cursor2;
1213 LIST_FOR_EACH_ENTRY_SAFE( face, cursor2, &family->faces, Face, entry )
1215 list_remove( &face->entry );
1216 free_face( face );
1218 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1219 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1220 HeapFree( GetProcessHeap(), 0, family );
1223 static inline int style_order(const Face *face)
1225 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1227 case NTM_REGULAR:
1228 return 0;
1229 case NTM_BOLD:
1230 return 1;
1231 case NTM_ITALIC:
1232 return 2;
1233 case NTM_BOLD | NTM_ITALIC:
1234 return 3;
1235 default:
1236 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1237 debugstr_w(face->family->FamilyName),
1238 debugstr_w(face->StyleName),
1239 face->ntmFlags);
1240 return 9999;
1244 static BOOL insert_face_in_family_list( Face *face, Family *family )
1246 Face *cursor;
1248 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1250 if (faces_equal( face, cursor ))
1252 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1253 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1254 cursor->font_version, face->font_version);
1256 if (face->font_version <= cursor->font_version)
1258 TRACE("Original font %s is newer so skipping %s\n",
1259 debugstr_a(cursor->file), debugstr_a(face->file));
1260 return FALSE;
1262 else
1264 TRACE("Replacing original %s with %s\n",
1265 debugstr_a(cursor->file), debugstr_a(face->file));
1266 list_add_before( &cursor->entry, &face->entry );
1267 face->family = family;
1268 list_remove( &cursor->entry);
1269 free_face( cursor );
1270 return TRUE;
1273 else
1274 TRACE("Adding new %s\n", debugstr_a(face->file));
1276 if (style_order( face ) < style_order( cursor )) break;
1279 list_add_before( &cursor->entry, &face->entry );
1280 face->family = family;
1281 return TRUE;
1284 /****************************************************************
1285 * NB This function stores the ptrs to the strings to save copying.
1286 * Don't free them after calling.
1288 static Family *create_family( WCHAR *name, WCHAR *english_name )
1290 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1291 family->FamilyName = name;
1292 family->EnglishName = english_name;
1293 list_init( &family->faces );
1294 family->replacement = &family->faces;
1296 return family;
1299 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1301 DWORD type, needed;
1302 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1303 if(r != ERROR_SUCCESS) return r;
1304 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1305 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1308 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1310 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1313 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1315 DWORD needed;
1316 DWORD num_strikes, max_strike_key_len;
1318 /* If we have a File Name key then this is a real font, not just the parent
1319 key of a bunch of non-scalable strikes */
1320 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1322 Face *face;
1323 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1324 face->cached_enum_data = NULL;
1326 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1327 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1329 face->StyleName = strdupW(face_name);
1331 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1333 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1334 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1335 face->FullName = fullName;
1337 else
1338 face->FullName = NULL;
1340 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1341 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1342 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1343 reg_load_dword(hkey_face, face_vertical_value, (DWORD*)&face->vertical);
1345 needed = sizeof(face->fs);
1346 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1348 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1350 face->scalable = TRUE;
1351 memset(&face->size, 0, sizeof(face->size));
1353 else
1355 face->scalable = FALSE;
1356 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1357 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1358 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1359 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1360 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1362 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1363 face->size.height, face->size.width, face->size.size >> 6,
1364 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1367 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1368 face->fs.fsCsb[0], face->fs.fsCsb[1],
1369 face->fs.fsUsb[0], face->fs.fsUsb[1],
1370 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1372 insert_face_in_family_list(face, family);
1374 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1377 /* do we have any bitmap strikes? */
1378 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1379 NULL, NULL, NULL, NULL);
1380 if(num_strikes != 0)
1382 WCHAR strike_name[10];
1383 DWORD strike_index = 0;
1385 needed = sizeof(strike_name) / sizeof(WCHAR);
1386 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1387 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1389 HKEY hkey_strike;
1390 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1391 load_face(hkey_strike, face_name, family);
1392 RegCloseKey(hkey_strike);
1393 needed = sizeof(strike_name) / sizeof(WCHAR);
1398 static void load_font_list_from_cache(HKEY hkey_font_cache)
1400 DWORD max_family_key_len, size;
1401 WCHAR *family_name;
1402 DWORD family_index = 0;
1403 Family *family;
1404 HKEY hkey_family;
1406 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1407 NULL, NULL, NULL, NULL);
1408 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1410 size = max_family_key_len + 1;
1411 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1412 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1414 WCHAR *english_family = NULL;
1415 DWORD face_index = 0;
1416 WCHAR *face_name;
1417 DWORD max_face_key_len;
1419 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1420 TRACE("opened family key %s\n", debugstr_w(family_name));
1421 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1423 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1424 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1427 family = create_family(strdupW(family_name), english_family);
1428 list_add_tail(&font_list, &family->entry);
1430 if(english_family)
1432 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1433 subst->from.name = strdupW(english_family);
1434 subst->from.charset = -1;
1435 subst->to.name = strdupW(family_name);
1436 subst->to.charset = -1;
1437 add_font_subst(&font_subst_list, subst, 0);
1440 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1441 NULL, NULL, NULL, NULL);
1443 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1444 size = max_face_key_len + 1;
1445 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1446 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1448 HKEY hkey_face;
1450 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1451 load_face(hkey_face, face_name, family);
1452 RegCloseKey(hkey_face);
1453 size = max_face_key_len + 1;
1455 HeapFree(GetProcessHeap(), 0, face_name);
1456 RegCloseKey(hkey_family);
1457 size = max_family_key_len + 1;
1460 HeapFree(GetProcessHeap(), 0, family_name);
1463 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1465 LONG ret;
1466 HKEY hkey_wine_fonts;
1468 /* We don't want to create the fonts key as volatile, so open this first */
1469 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1470 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1471 if(ret != ERROR_SUCCESS)
1473 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1474 return ret;
1477 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1478 KEY_ALL_ACCESS, NULL, hkey, disposition);
1479 RegCloseKey(hkey_wine_fonts);
1480 return ret;
1483 static void add_face_to_cache(Face *face)
1485 HKEY hkey_font_cache, hkey_family, hkey_face;
1486 WCHAR *face_key_name;
1488 create_font_cache_key(&hkey_font_cache, NULL);
1490 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1491 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1492 if(face->family->EnglishName)
1493 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1494 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1496 if(face->scalable)
1497 face_key_name = face->StyleName;
1498 else
1500 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1501 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1502 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1504 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1505 &hkey_face, NULL);
1506 if(!face->scalable)
1507 HeapFree(GetProcessHeap(), 0, face_key_name);
1509 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1510 if (face->FullName)
1511 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1512 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1514 reg_save_dword(hkey_face, face_index_value, face->face_index);
1515 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1516 reg_save_dword(hkey_face, face_version_value, face->font_version);
1517 reg_save_dword(hkey_face, face_vertical_value, face->vertical);
1519 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1521 if(!face->scalable)
1523 reg_save_dword(hkey_face, face_height_value, face->size.height);
1524 reg_save_dword(hkey_face, face_width_value, face->size.width);
1525 reg_save_dword(hkey_face, face_size_value, face->size.size);
1526 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1527 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1528 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1530 RegCloseKey(hkey_face);
1531 RegCloseKey(hkey_family);
1532 RegCloseKey(hkey_font_cache);
1535 static WCHAR *prepend_at(WCHAR *family)
1537 WCHAR *str;
1539 if (!family)
1540 return NULL;
1542 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1543 str[0] = '@';
1544 strcpyW(str + 1, family);
1545 HeapFree(GetProcessHeap(), 0, family);
1546 return str;
1549 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1551 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1552 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1554 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID() );
1555 if (!*name)
1557 *name = *english;
1558 *english = NULL;
1560 else if (!strcmpiW( *name, *english ))
1562 HeapFree( GetProcessHeap(), 0, *english );
1563 *english = NULL;
1566 if (vertical)
1568 *name = prepend_at( *name );
1569 *english = prepend_at( *english );
1573 static Family *get_family( FT_Face ft_face, BOOL vertical )
1575 Family *family;
1576 WCHAR *name, *english_name;
1578 get_family_names( ft_face, &name, &english_name, vertical );
1580 family = find_family_from_name( name );
1582 if (!family)
1584 family = create_family( name, english_name );
1585 list_add_tail( &font_list, &family->entry );
1587 if (english_name)
1589 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1590 subst->from.name = strdupW( english_name );
1591 subst->from.charset = -1;
1592 subst->to.name = strdupW( name );
1593 subst->to.charset = -1;
1594 add_font_subst( &font_subst_list, subst, 0 );
1597 else
1599 HeapFree( GetProcessHeap(), 0, name );
1600 HeapFree( GetProcessHeap(), 0, english_name );
1603 return family;
1606 static inline FT_Fixed get_font_version( FT_Face ft_face )
1608 FT_Fixed version = 0;
1609 TT_Header *header;
1611 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1612 if (header) version = header->Font_Revision;
1614 return version;
1617 static inline DWORD get_ntm_flags( FT_Face ft_face )
1619 DWORD flags = 0;
1620 FT_ULong table_size = 0;
1622 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1623 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1624 if (flags == 0) flags = NTM_REGULAR;
1626 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1627 flags |= NTM_PS_OPENTYPE;
1629 return flags;
1632 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1634 int internal_leading = 0;
1635 FT_WinFNT_HeaderRec winfnt_header;
1637 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1638 internal_leading = winfnt_header.internal_leading;
1640 return internal_leading;
1643 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1645 TT_OS2 *os2;
1646 FT_UInt dummy;
1647 CHARSETINFO csi;
1648 FT_WinFNT_HeaderRec winfnt_header;
1649 int i;
1651 memset( fs, 0, sizeof(*fs) );
1653 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1654 if (os2)
1656 fs->fsUsb[0] = os2->ulUnicodeRange1;
1657 fs->fsUsb[1] = os2->ulUnicodeRange2;
1658 fs->fsUsb[2] = os2->ulUnicodeRange3;
1659 fs->fsUsb[3] = os2->ulUnicodeRange4;
1661 if (os2->version == 0)
1663 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1664 fs->fsCsb[0] = FS_LATIN1;
1665 else
1666 fs->fsCsb[0] = FS_SYMBOL;
1668 else
1670 fs->fsCsb[0] = os2->ulCodePageRange1;
1671 fs->fsCsb[1] = os2->ulCodePageRange2;
1674 else
1676 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1678 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1679 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1680 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1681 *fs = csi.fs;
1685 if (fs->fsCsb[0] == 0)
1687 /* let's see if we can find any interesting cmaps */
1688 for (i = 0; i < ft_face->num_charmaps; i++)
1690 switch (ft_face->charmaps[i]->encoding)
1692 case FT_ENCODING_UNICODE:
1693 case FT_ENCODING_APPLE_ROMAN:
1694 fs->fsCsb[0] |= FS_LATIN1;
1695 break;
1696 case FT_ENCODING_MS_SYMBOL:
1697 fs->fsCsb[0] |= FS_SYMBOL;
1698 break;
1699 default:
1700 break;
1706 #define ADDFONT_EXTERNAL_FONT 0x01
1707 #define ADDFONT_FORCE_BITMAP 0x02
1708 #define ADDFONT_ADD_TO_CACHE 0x04
1710 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1711 DWORD flags, BOOL vertical )
1713 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1714 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1716 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1717 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1718 if (file)
1720 face->file = strdupA( file );
1721 face->font_data_ptr = NULL;
1722 face->font_data_size = 0;
1724 else
1726 face->file = NULL;
1727 face->font_data_ptr = font_data_ptr;
1728 face->font_data_size = font_data_size;
1731 face->face_index = face_index;
1732 get_fontsig( ft_face, &face->fs );
1733 face->ntmFlags = get_ntm_flags( ft_face );
1734 face->font_version = get_font_version( ft_face );
1736 if (FT_IS_SCALABLE( ft_face ))
1738 memset( &face->size, 0, sizeof(face->size) );
1739 face->scalable = TRUE;
1741 else
1743 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1744 size->height, size->width, size->size >> 6,
1745 size->x_ppem >> 6, size->y_ppem >> 6);
1746 face->size.height = size->height;
1747 face->size.width = size->width;
1748 face->size.size = size->size;
1749 face->size.x_ppem = size->x_ppem;
1750 face->size.y_ppem = size->y_ppem;
1751 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1752 face->scalable = FALSE;
1755 face->vertical = vertical;
1756 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1757 face->family = NULL;
1758 face->cached_enum_data = NULL;
1760 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1761 face->fs.fsCsb[0], face->fs.fsCsb[1],
1762 face->fs.fsUsb[0], face->fs.fsUsb[1],
1763 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1765 return face;
1768 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1769 FT_Long face_index, DWORD flags, BOOL vertical)
1771 Face *face;
1772 Family *family;
1774 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags, vertical );
1775 family = get_family( ft_face, vertical );
1776 if (!insert_face_in_family_list( face, family ))
1778 free_face( face );
1779 return;
1782 if (flags & ADDFONT_ADD_TO_CACHE)
1783 add_face_to_cache( face );
1785 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1786 debugstr_w(face->StyleName));
1789 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1790 FT_Long face_index, BOOL allow_bitmap )
1792 FT_Error err;
1793 TT_OS2 *pOS2;
1794 FT_Face ft_face;
1796 if (file)
1798 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1799 err = pFT_New_Face(library, file, face_index, &ft_face);
1801 else
1803 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1804 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1807 if (err != 0)
1809 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1810 return NULL;
1813 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1814 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1816 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1817 goto fail;
1820 if (!FT_IS_SFNT( ft_face ))
1822 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1824 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1825 goto fail;
1828 else
1830 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1831 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1832 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1834 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1835 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1836 goto fail;
1839 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1840 we don't want to load these. */
1841 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1843 FT_ULong len = 0;
1845 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1847 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1848 goto fail;
1853 if (!ft_face->family_name || !ft_face->style_name)
1855 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1856 goto fail;
1859 return ft_face;
1860 fail:
1861 pFT_Done_Face( ft_face );
1862 return NULL;
1865 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1867 FT_Face ft_face;
1868 FT_Long face_index = 0, num_faces;
1869 INT ret = 0;
1871 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1872 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1874 #ifdef HAVE_CARBON_CARBON_H
1875 if(file)
1877 char **mac_list = expand_mac_font(file);
1878 if(mac_list)
1880 BOOL had_one = FALSE;
1881 char **cursor;
1882 for(cursor = mac_list; *cursor; cursor++)
1884 had_one = TRUE;
1885 AddFontToList(*cursor, NULL, 0, flags);
1886 HeapFree(GetProcessHeap(), 0, *cursor);
1888 HeapFree(GetProcessHeap(), 0, mac_list);
1889 if(had_one)
1890 return 1;
1893 #endif /* HAVE_CARBON_CARBON_H */
1895 do {
1896 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_FORCE_BITMAP );
1897 if (!ft_face) return 0;
1899 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1901 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1902 pFT_Done_Face(ft_face);
1903 return 0;
1906 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1907 ++ret;
1909 if (FT_HAS_VERTICAL(ft_face))
1911 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1912 ++ret;
1915 num_faces = ft_face->num_faces;
1916 pFT_Done_Face(ft_face);
1917 } while(num_faces > ++face_index);
1918 return ret;
1921 static void DumpFontList(void)
1923 Family *family;
1924 Face *face;
1925 struct list *family_elem_ptr, *face_elem_ptr;
1927 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1928 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1929 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1930 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1931 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1932 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1933 if(!face->scalable)
1934 TRACE(" %d", face->size.height);
1935 TRACE("\n");
1938 return;
1941 /***********************************************************
1942 * The replacement list is a way to map an entire font
1943 * family onto another family. For example adding
1945 * [HKCU\Software\Wine\Fonts\Replacements]
1946 * "Wingdings"="Winedings"
1948 * would enumerate the Winedings font both as Winedings and
1949 * Wingdings. However if a real Wingdings font is present the
1950 * replacement does not take place.
1953 static void LoadReplaceList(void)
1955 HKEY hkey;
1956 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1957 LPWSTR value;
1958 LPVOID data;
1959 CHAR familyA[400];
1961 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1962 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1964 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1965 &valuelen, &datalen, NULL, NULL);
1967 valuelen++; /* returned value doesn't include room for '\0' */
1968 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1969 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1971 dlen = datalen;
1972 vlen = valuelen;
1973 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1974 &dlen) == ERROR_SUCCESS) {
1975 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1976 /* "NewName"="Oldname" */
1977 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1979 if(!find_family_from_any_name(value))
1981 Family * const family = find_family_from_any_name(data);
1982 if (family != NULL)
1984 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
1985 if (new_family != NULL)
1987 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
1988 new_family->FamilyName = strdupW(value);
1989 new_family->EnglishName = NULL;
1990 list_init(&new_family->faces);
1991 new_family->replacement = &family->faces;
1992 list_add_tail(&font_list, &new_family->entry);
1995 else
1997 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2000 else
2002 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2004 /* reset dlen and vlen */
2005 dlen = datalen;
2006 vlen = valuelen;
2008 HeapFree(GetProcessHeap(), 0, data);
2009 HeapFree(GetProcessHeap(), 0, value);
2010 RegCloseKey(hkey);
2014 static const WCHAR *font_links_list[] =
2016 Lucida_Sans_Unicode,
2017 Microsoft_Sans_Serif,
2018 Tahoma
2021 static const struct font_links_defaults_list
2023 /* Keyed off substitution for "MS Shell Dlg" */
2024 const WCHAR *shelldlg;
2025 /* Maximum of four substitutes, plus terminating NULL pointer */
2026 const WCHAR *substitutes[5];
2027 } font_links_defaults_list[] =
2029 /* Non East-Asian */
2030 { Tahoma, /* FIXME unverified ordering */
2031 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2033 /* Below lists are courtesy of
2034 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2036 /* Japanese */
2037 { MS_UI_Gothic,
2038 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2040 /* Chinese Simplified */
2041 { SimSun,
2042 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2044 /* Korean */
2045 { Gulim,
2046 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2048 /* Chinese Traditional */
2049 { PMingLiU,
2050 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2055 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2057 SYSTEM_LINKS *font_link;
2059 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2061 if(!strcmpiW(font_link->font_name, name))
2062 return font_link;
2065 return NULL;
2068 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2070 const WCHAR *value;
2071 int i;
2072 FontSubst *psub;
2073 Family *family;
2074 Face *face;
2075 const char *file;
2076 WCHAR *fileW;
2078 if (values)
2080 SYSTEM_LINKS *font_link;
2082 psub = get_font_subst(&font_subst_list, name, -1);
2083 /* Don't store fonts that are only substitutes for other fonts */
2084 if(psub)
2086 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2087 return;
2090 font_link = find_font_link(name);
2091 if (font_link == NULL)
2093 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2094 font_link->font_name = strdupW(name);
2095 list_init(&font_link->links);
2096 list_add_tail(&system_links, &font_link->entry);
2099 memset(&font_link->fs, 0, sizeof font_link->fs);
2100 for (i = 0; values[i] != NULL; i++)
2102 const struct list *face_list;
2103 CHILD_FONT *child_font;
2105 value = values[i];
2106 if (!strcmpiW(name,value))
2107 continue;
2108 psub = get_font_subst(&font_subst_list, value, -1);
2109 if(psub)
2110 value = psub->to.name;
2111 family = find_family_from_name(value);
2112 if (!family)
2113 continue;
2114 file = NULL;
2115 /* Use first extant filename for this Family */
2116 face_list = get_face_list_from_family(family);
2117 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2119 if (!face->file)
2120 continue;
2121 file = strrchr(face->file, '/');
2122 if (!file)
2123 file = face->file;
2124 else
2125 file++;
2126 break;
2128 if (!file)
2129 continue;
2130 fileW = towstr(CP_UNIXCP, file);
2132 face = find_face_from_filename(fileW, value);
2133 if(!face)
2135 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2136 continue;
2139 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2140 child_font->face = face;
2141 child_font->font = NULL;
2142 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2143 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2144 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2145 list_add_tail(&font_link->links, &child_font->entry);
2147 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2148 HeapFree(GetProcessHeap(), 0, fileW);
2154 /*************************************************************
2155 * init_system_links
2157 static BOOL init_system_links(void)
2159 HKEY hkey;
2160 BOOL ret = FALSE;
2161 DWORD type, max_val, max_data, val_len, data_len, index;
2162 WCHAR *value, *data;
2163 WCHAR *entry, *next;
2164 SYSTEM_LINKS *font_link, *system_font_link;
2165 CHILD_FONT *child_font;
2166 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2167 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2168 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2169 Face *face;
2170 FontSubst *psub;
2171 UINT i, j;
2173 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2175 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2176 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2177 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2178 val_len = max_val + 1;
2179 data_len = max_data;
2180 index = 0;
2181 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2183 psub = get_font_subst(&font_subst_list, value, -1);
2184 /* Don't store fonts that are only substitutes for other fonts */
2185 if(psub)
2187 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2188 goto next;
2190 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2191 font_link->font_name = strdupW(value);
2192 memset(&font_link->fs, 0, sizeof font_link->fs);
2193 list_init(&font_link->links);
2194 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2196 WCHAR *face_name;
2197 CHILD_FONT *child_font;
2199 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2201 next = entry + strlenW(entry) + 1;
2203 face_name = strchrW(entry, ',');
2204 if(face_name)
2206 *face_name++ = 0;
2207 while(isspaceW(*face_name))
2208 face_name++;
2210 psub = get_font_subst(&font_subst_list, face_name, -1);
2211 if(psub)
2212 face_name = psub->to.name;
2214 face = find_face_from_filename(entry, face_name);
2215 if(!face)
2217 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2218 continue;
2221 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2222 child_font->face = face;
2223 child_font->font = NULL;
2224 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2225 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2226 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2227 list_add_tail(&font_link->links, &child_font->entry);
2229 list_add_tail(&system_links, &font_link->entry);
2230 next:
2231 val_len = max_val + 1;
2232 data_len = max_data;
2235 HeapFree(GetProcessHeap(), 0, value);
2236 HeapFree(GetProcessHeap(), 0, data);
2237 RegCloseKey(hkey);
2241 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2242 if (!psub) {
2243 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2244 goto skip_internal;
2247 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2249 const FontSubst *psub2;
2250 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2252 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2254 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2255 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2257 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2258 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2260 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2262 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2266 skip_internal:
2268 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2269 that Tahoma has */
2271 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2272 system_font_link->font_name = strdupW(System);
2273 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2274 list_init(&system_font_link->links);
2276 face = find_face_from_filename(tahoma_ttf, Tahoma);
2277 if(face)
2279 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2280 child_font->face = face;
2281 child_font->font = NULL;
2282 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2283 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2284 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2285 list_add_tail(&system_font_link->links, &child_font->entry);
2287 font_link = find_font_link(Tahoma);
2288 if (font_link != NULL)
2290 CHILD_FONT *font_link_entry;
2291 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2293 CHILD_FONT *new_child;
2294 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2295 new_child->face = font_link_entry->face;
2296 new_child->font = NULL;
2297 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2298 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2299 list_add_tail(&system_font_link->links, &new_child->entry);
2302 list_add_tail(&system_links, &system_font_link->entry);
2303 return ret;
2306 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2308 DIR *dir;
2309 struct dirent *dent;
2310 char path[MAX_PATH];
2312 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2314 dir = opendir(dirname);
2315 if(!dir) {
2316 WARN("Can't open directory %s\n", debugstr_a(dirname));
2317 return FALSE;
2319 while((dent = readdir(dir)) != NULL) {
2320 struct stat statbuf;
2322 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2323 continue;
2325 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2327 sprintf(path, "%s/%s", dirname, dent->d_name);
2329 if(stat(path, &statbuf) == -1)
2331 WARN("Can't stat %s\n", debugstr_a(path));
2332 continue;
2334 if(S_ISDIR(statbuf.st_mode))
2335 ReadFontDir(path, external_fonts);
2336 else
2338 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2339 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2340 AddFontToList(path, NULL, 0, addfont_flags);
2343 closedir(dir);
2344 return TRUE;
2347 #ifdef SONAME_LIBFONTCONFIG
2348 static void load_fontconfig_fonts(void)
2350 void *fc_handle = NULL;
2351 FcConfig *config;
2352 FcPattern *pat;
2353 FcObjectSet *os;
2354 FcFontSet *fontset;
2355 int i, len;
2356 char *file;
2357 const char *ext;
2359 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2360 if(!fc_handle) {
2361 TRACE("Wine cannot find the fontconfig library (%s).\n",
2362 SONAME_LIBFONTCONFIG);
2363 return;
2365 #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;}
2366 LOAD_FUNCPTR(FcConfigGetCurrent);
2367 LOAD_FUNCPTR(FcFontList);
2368 LOAD_FUNCPTR(FcFontSetDestroy);
2369 LOAD_FUNCPTR(FcInit);
2370 LOAD_FUNCPTR(FcObjectSetAdd);
2371 LOAD_FUNCPTR(FcObjectSetCreate);
2372 LOAD_FUNCPTR(FcObjectSetDestroy);
2373 LOAD_FUNCPTR(FcPatternCreate);
2374 LOAD_FUNCPTR(FcPatternDestroy);
2375 LOAD_FUNCPTR(FcPatternGetBool);
2376 LOAD_FUNCPTR(FcPatternGetString);
2377 #undef LOAD_FUNCPTR
2379 if(!pFcInit()) return;
2381 config = pFcConfigGetCurrent();
2382 pat = pFcPatternCreate();
2383 os = pFcObjectSetCreate();
2384 pFcObjectSetAdd(os, FC_FILE);
2385 pFcObjectSetAdd(os, FC_SCALABLE);
2386 fontset = pFcFontList(config, pat, os);
2387 if(!fontset) return;
2388 for(i = 0; i < fontset->nfont; i++) {
2389 FcBool scalable;
2391 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2392 continue;
2393 TRACE("fontconfig: %s\n", file);
2395 /* We're just interested in OT/TT fonts for now, so this hack just
2396 picks up the scalable fonts without extensions .pf[ab] to save time
2397 loading every other font */
2399 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2401 TRACE("not scalable\n");
2402 continue;
2405 len = strlen( file );
2406 if(len < 4) continue;
2407 ext = &file[ len - 3 ];
2408 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2409 AddFontToList(file, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2411 pFcFontSetDestroy(fontset);
2412 pFcObjectSetDestroy(os);
2413 pFcPatternDestroy(pat);
2414 sym_not_found:
2415 return;
2418 #elif defined(HAVE_CARBON_CARBON_H)
2420 static void load_mac_font_callback(const void *value, void *context)
2422 CFStringRef pathStr = value;
2423 CFIndex len;
2424 char* path;
2426 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2427 path = HeapAlloc(GetProcessHeap(), 0, len);
2428 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2430 TRACE("font file %s\n", path);
2431 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2433 HeapFree(GetProcessHeap(), 0, path);
2436 static void load_mac_fonts(void)
2438 CFStringRef removeDupesKey;
2439 CFBooleanRef removeDupesValue;
2440 CFDictionaryRef options;
2441 CTFontCollectionRef col;
2442 CFArrayRef descs;
2443 CFMutableSetRef paths;
2444 CFIndex i;
2446 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2447 removeDupesValue = kCFBooleanTrue;
2448 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2449 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2450 col = CTFontCollectionCreateFromAvailableFonts(options);
2451 if (options) CFRelease(options);
2452 if (!col)
2454 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2455 return;
2458 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2459 CFRelease(col);
2460 if (!descs)
2462 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2463 return;
2466 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2467 if (!paths)
2469 WARN("CFSetCreateMutable failed\n");
2470 CFRelease(descs);
2471 return;
2474 for (i = 0; i < CFArrayGetCount(descs); i++)
2476 CTFontDescriptorRef desc;
2477 CTFontRef font;
2478 ATSFontRef atsFont;
2479 OSStatus status;
2480 FSRef fsref;
2481 CFURLRef url;
2482 CFStringRef ext;
2483 CFStringRef path;
2485 desc = CFArrayGetValueAtIndex(descs, i);
2487 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2488 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2489 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2490 if (!font) continue;
2492 atsFont = CTFontGetPlatformFont(font, NULL);
2493 if (!atsFont)
2495 CFRelease(font);
2496 continue;
2499 status = ATSFontGetFileReference(atsFont, &fsref);
2500 CFRelease(font);
2501 if (status != noErr) continue;
2503 url = CFURLCreateFromFSRef(NULL, &fsref);
2504 if (!url) continue;
2506 ext = CFURLCopyPathExtension(url);
2507 if (ext)
2509 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2510 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2511 CFRelease(ext);
2512 if (skip)
2514 CFRelease(url);
2515 continue;
2519 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2520 CFRelease(url);
2521 if (!path) continue;
2523 CFSetAddValue(paths, path);
2524 CFRelease(path);
2527 CFRelease(descs);
2529 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2530 CFRelease(paths);
2533 #endif
2535 static BOOL load_font_from_data_dir(LPCWSTR file)
2537 BOOL ret = FALSE;
2538 const char *data_dir = wine_get_data_dir();
2540 if (!data_dir) data_dir = wine_get_build_dir();
2542 if (data_dir)
2544 INT len;
2545 char *unix_name;
2547 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2549 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2551 strcpy(unix_name, data_dir);
2552 strcat(unix_name, "/fonts/");
2554 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2556 EnterCriticalSection( &freetype_cs );
2557 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2558 LeaveCriticalSection( &freetype_cs );
2559 HeapFree(GetProcessHeap(), 0, unix_name);
2561 return ret;
2564 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2566 static const WCHAR slashW[] = {'\\','\0'};
2567 BOOL ret = FALSE;
2568 WCHAR windowsdir[MAX_PATH];
2569 char *unixname;
2571 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2572 strcatW(windowsdir, fontsW);
2573 strcatW(windowsdir, slashW);
2574 strcatW(windowsdir, file);
2575 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2576 EnterCriticalSection( &freetype_cs );
2577 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2578 LeaveCriticalSection( &freetype_cs );
2579 HeapFree(GetProcessHeap(), 0, unixname);
2581 return ret;
2584 static void load_system_fonts(void)
2586 HKEY hkey;
2587 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2588 const WCHAR * const *value;
2589 DWORD dlen, type;
2590 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2591 char *unixname;
2593 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2594 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2595 strcatW(windowsdir, fontsW);
2596 for(value = SystemFontValues; *value; value++) {
2597 dlen = sizeof(data);
2598 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2599 type == REG_SZ) {
2600 BOOL added = FALSE;
2602 sprintfW(pathW, fmtW, windowsdir, data);
2603 if((unixname = wine_get_unix_file_name(pathW))) {
2604 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2605 HeapFree(GetProcessHeap(), 0, unixname);
2607 if (!added)
2608 load_font_from_data_dir(data);
2611 RegCloseKey(hkey);
2615 /*************************************************************
2617 * This adds registry entries for any externally loaded fonts
2618 * (fonts from fontconfig or FontDirs). It also deletes entries
2619 * of no longer existing fonts.
2622 static void update_reg_entries(void)
2624 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2625 LPWSTR valueW;
2626 DWORD len, len_fam;
2627 Family *family;
2628 Face *face;
2629 struct list *family_elem_ptr, *face_elem_ptr;
2630 WCHAR *file;
2631 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2632 static const WCHAR spaceW[] = {' ', '\0'};
2633 char *path;
2635 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2636 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2637 ERR("Can't create Windows font reg key\n");
2638 goto end;
2641 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2642 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2643 ERR("Can't create Windows font reg key\n");
2644 goto end;
2647 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2648 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2649 ERR("Can't create external font reg key\n");
2650 goto end;
2653 /* enumerate the fonts and add external ones to the two keys */
2655 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2656 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2657 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2658 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2659 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2660 if(!face->external) continue;
2661 len = len_fam;
2662 if (!(face->ntmFlags & NTM_REGULAR))
2663 len = len_fam + strlenW(face->StyleName) + 1;
2664 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2665 strcpyW(valueW, family->FamilyName);
2666 if(len != len_fam) {
2667 strcatW(valueW, spaceW);
2668 strcatW(valueW, face->StyleName);
2670 strcatW(valueW, TrueType);
2672 file = wine_get_dos_file_name(face->file);
2673 if(file)
2674 len = strlenW(file) + 1;
2675 else
2677 if((path = strrchr(face->file, '/')) == NULL)
2678 path = face->file;
2679 else
2680 path++;
2681 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2683 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2684 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2686 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2687 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2688 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2690 HeapFree(GetProcessHeap(), 0, file);
2691 HeapFree(GetProcessHeap(), 0, valueW);
2694 end:
2695 if(external_key) RegCloseKey(external_key);
2696 if(win9x_key) RegCloseKey(win9x_key);
2697 if(winnt_key) RegCloseKey(winnt_key);
2698 return;
2701 static void delete_external_font_keys(void)
2703 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2704 DWORD dlen, vlen, datalen, valuelen, i, type;
2705 LPWSTR valueW;
2706 LPVOID data;
2708 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2709 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2710 ERR("Can't create Windows font reg key\n");
2711 goto end;
2714 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2715 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2716 ERR("Can't create Windows font reg key\n");
2717 goto end;
2720 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2721 ERR("Can't create external font reg key\n");
2722 goto end;
2725 /* Delete all external fonts added last time */
2727 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2728 &valuelen, &datalen, NULL, NULL);
2729 valuelen++; /* returned value doesn't include room for '\0' */
2730 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2731 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2733 dlen = datalen * sizeof(WCHAR);
2734 vlen = valuelen;
2735 i = 0;
2736 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2737 &dlen) == ERROR_SUCCESS) {
2739 RegDeleteValueW(winnt_key, valueW);
2740 RegDeleteValueW(win9x_key, valueW);
2741 /* reset dlen and vlen */
2742 dlen = datalen;
2743 vlen = valuelen;
2745 HeapFree(GetProcessHeap(), 0, data);
2746 HeapFree(GetProcessHeap(), 0, valueW);
2748 /* Delete the old external fonts key */
2749 RegCloseKey(external_key);
2750 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2752 end:
2753 if(win9x_key) RegCloseKey(win9x_key);
2754 if(winnt_key) RegCloseKey(winnt_key);
2757 /*************************************************************
2758 * WineEngAddFontResourceEx
2761 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2763 INT ret = 0;
2765 GDI_CheckNotLock();
2767 if (ft_handle) /* do it only if we have freetype up and running */
2769 char *unixname;
2771 if(flags)
2772 FIXME("Ignoring flags %x\n", flags);
2774 if((unixname = wine_get_unix_file_name(file)))
2776 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2778 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2779 EnterCriticalSection( &freetype_cs );
2780 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2781 LeaveCriticalSection( &freetype_cs );
2782 HeapFree(GetProcessHeap(), 0, unixname);
2784 if (!ret && !strchrW(file, '\\')) {
2785 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2786 ret = load_font_from_winfonts_dir(file);
2787 if (!ret) {
2788 /* Try in datadir/fonts (or builddir/fonts),
2789 * needed for Magic the Gathering Online
2791 ret = load_font_from_data_dir(file);
2795 return ret;
2798 /*************************************************************
2799 * WineEngAddFontMemResourceEx
2802 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2804 GDI_CheckNotLock();
2806 if (ft_handle) /* do it only if we have freetype up and running */
2808 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2810 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2811 memcpy(pFontCopy, pbFont, cbFont);
2813 EnterCriticalSection( &freetype_cs );
2814 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2815 LeaveCriticalSection( &freetype_cs );
2817 if (*pcFonts == 0)
2819 TRACE("AddFontToList failed\n");
2820 HeapFree(GetProcessHeap(), 0, pFontCopy);
2821 return 0;
2823 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2824 * For now return something unique but quite random
2826 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2827 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2830 *pcFonts = 0;
2831 return 0;
2834 /*************************************************************
2835 * WineEngRemoveFontResourceEx
2838 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2840 GDI_CheckNotLock();
2841 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2842 return TRUE;
2845 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
2847 WCHAR *fullname;
2848 char *unix_name;
2849 int file_len;
2851 if (!font_file) return NULL;
2853 file_len = strlenW( font_file );
2855 if (font_path && font_path[0])
2857 int path_len = strlenW( font_path );
2858 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
2859 if (!fullname) return NULL;
2860 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
2861 fullname[path_len] = '\\';
2862 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
2864 else
2866 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
2867 if (!len) return NULL;
2868 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2869 if (!fullname) return NULL;
2870 GetFullPathNameW( font_file, len, fullname, NULL );
2873 unix_name = wine_get_unix_file_name( fullname );
2874 HeapFree( GetProcessHeap(), 0, fullname );
2875 return unix_name;
2878 #include <pshpack1.h>
2879 struct fontdir
2881 WORD num_of_resources;
2882 WORD res_id;
2883 WORD dfVersion;
2884 DWORD dfSize;
2885 CHAR dfCopyright[60];
2886 WORD dfType;
2887 WORD dfPoints;
2888 WORD dfVertRes;
2889 WORD dfHorizRes;
2890 WORD dfAscent;
2891 WORD dfInternalLeading;
2892 WORD dfExternalLeading;
2893 BYTE dfItalic;
2894 BYTE dfUnderline;
2895 BYTE dfStrikeOut;
2896 WORD dfWeight;
2897 BYTE dfCharSet;
2898 WORD dfPixWidth;
2899 WORD dfPixHeight;
2900 BYTE dfPitchAndFamily;
2901 WORD dfAvgWidth;
2902 WORD dfMaxWidth;
2903 BYTE dfFirstChar;
2904 BYTE dfLastChar;
2905 BYTE dfDefaultChar;
2906 BYTE dfBreakChar;
2907 WORD dfWidthBytes;
2908 DWORD dfDevice;
2909 DWORD dfFace;
2910 DWORD dfReserved;
2911 CHAR szFaceName[LF_FACESIZE];
2914 #include <poppack.h>
2916 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2917 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
2919 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
2921 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
2922 Face *face;
2923 Family *family;
2924 WCHAR *name, *english_name;
2925 ENUMLOGFONTEXW elf;
2926 NEWTEXTMETRICEXW ntm;
2927 DWORD type;
2929 if (!ft_face) return FALSE;
2930 face = create_face( ft_face, 0, unix_name, NULL, 0, 0, FALSE );
2931 get_family_names( ft_face, &name, &english_name, FALSE );
2932 family = create_family( name, english_name );
2933 insert_face_in_family_list( face, family );
2934 pFT_Done_Face( ft_face );
2936 GetEnumStructs( face, &elf, &ntm, &type );
2937 free_family( family );
2939 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
2941 memset( fd, 0, sizeof(*fd) );
2943 fd->num_of_resources = 1;
2944 fd->res_id = 0;
2945 fd->dfVersion = 0x200;
2946 fd->dfSize = sizeof(*fd);
2947 strcpy( fd->dfCopyright, "Wine fontdir" );
2948 fd->dfType = 0x4003; /* 0x0080 set if private */
2949 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
2950 fd->dfVertRes = 72;
2951 fd->dfHorizRes = 72;
2952 fd->dfAscent = ntm.ntmTm.tmAscent;
2953 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
2954 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
2955 fd->dfItalic = ntm.ntmTm.tmItalic;
2956 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
2957 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
2958 fd->dfWeight = ntm.ntmTm.tmWeight;
2959 fd->dfCharSet = ntm.ntmTm.tmCharSet;
2960 fd->dfPixWidth = 0;
2961 fd->dfPixHeight = ntm.ntmTm.tmHeight;
2962 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
2963 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
2964 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
2965 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
2966 fd->dfLastChar = ntm.ntmTm.tmLastChar;
2967 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
2968 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
2969 fd->dfWidthBytes = 0;
2970 fd->dfDevice = 0;
2971 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
2972 fd->dfReserved = 0;
2973 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
2975 return TRUE;
2978 #define NE_FFLAGS_LIBMODULE 0x8000
2979 #define NE_OSFLAGS_WINDOWS 0x02
2981 static const char dos_string[0x40] = "This is a TrueType resource file";
2982 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
2984 #include <pshpack2.h>
2986 struct ne_typeinfo
2988 WORD type_id;
2989 WORD count;
2990 DWORD res;
2993 struct ne_nameinfo
2995 WORD off;
2996 WORD len;
2997 WORD flags;
2998 WORD id;
2999 DWORD res;
3002 struct rsrc_tab
3004 WORD align;
3005 struct ne_typeinfo fontdir_type;
3006 struct ne_nameinfo fontdir_name;
3007 struct ne_typeinfo scalable_type;
3008 struct ne_nameinfo scalable_name;
3009 WORD end_of_rsrc;
3010 BYTE fontdir_res_name[8];
3013 #include <poppack.h>
3015 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3017 BOOL ret = FALSE;
3018 HANDLE file;
3019 DWORD size, written;
3020 BYTE *ptr, *start;
3021 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3022 char *font_fileA, *last_part, *ext;
3023 IMAGE_DOS_HEADER dos;
3024 IMAGE_OS2_HEADER ne =
3026 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3027 0, 0, 0, 0, 0, 0,
3028 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3029 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3031 struct rsrc_tab rsrc_tab =
3034 { 0x8007, 1, 0 },
3035 { 0, 0, 0x0c50, 0x2c, 0 },
3036 { 0x80cc, 1, 0 },
3037 { 0, 0, 0x0c50, 0x8001, 0 },
3039 { 7,'F','O','N','T','D','I','R'}
3042 memset( &dos, 0, sizeof(dos) );
3043 dos.e_magic = IMAGE_DOS_SIGNATURE;
3044 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3046 /* import name is last part\0, resident name is last part without extension
3047 non-resident name is "FONTRES:" + lfFaceName */
3049 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3050 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3051 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3053 last_part = strrchr( font_fileA, '\\' );
3054 if (last_part) last_part++;
3055 else last_part = font_fileA;
3056 import_name_len = strlen( last_part ) + 1;
3058 ext = strchr( last_part, '.' );
3059 if (ext) res_name_len = ext - last_part;
3060 else res_name_len = import_name_len - 1;
3062 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3064 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3065 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3066 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3067 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3068 ne.ne_cbenttab = 2;
3069 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3071 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3072 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3073 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3074 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3076 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3077 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3079 if (!ptr)
3081 HeapFree( GetProcessHeap(), 0, font_fileA );
3082 return FALSE;
3085 memcpy( ptr, &dos, sizeof(dos) );
3086 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3087 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3089 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3090 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3092 ptr = start + dos.e_lfanew + ne.ne_restab;
3093 *ptr++ = res_name_len;
3094 memcpy( ptr, last_part, res_name_len );
3096 ptr = start + dos.e_lfanew + ne.ne_imptab;
3097 *ptr++ = import_name_len;
3098 memcpy( ptr, last_part, import_name_len );
3100 ptr = start + ne.ne_nrestab;
3101 *ptr++ = non_res_name_len;
3102 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3103 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3105 ptr = start + (rsrc_tab.scalable_name.off << 4);
3106 memcpy( ptr, font_fileA, font_file_len );
3108 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3109 memcpy( ptr, fontdir, fontdir->dfSize );
3111 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3112 if (file != INVALID_HANDLE_VALUE)
3114 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3115 ret = TRUE;
3116 CloseHandle( file );
3119 HeapFree( GetProcessHeap(), 0, start );
3120 HeapFree( GetProcessHeap(), 0, font_fileA );
3122 return ret;
3125 /*************************************************************
3126 * WineEngCreateScalableFontResource
3129 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3130 LPCWSTR font_file, LPCWSTR font_path )
3132 char *unix_name = get_ttf_file_name( font_file, font_path );
3133 struct fontdir fontdir;
3134 BOOL ret = FALSE;
3136 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3137 SetLastError( ERROR_INVALID_PARAMETER );
3138 else
3140 if (hidden) fontdir.dfType |= 0x80;
3141 ret = create_fot( resource, font_file, &fontdir );
3144 HeapFree( GetProcessHeap(), 0, unix_name );
3145 return ret;
3148 static const struct nls_update_font_list
3150 UINT ansi_cp, oem_cp;
3151 const char *oem, *fixed, *system;
3152 const char *courier, *serif, *small, *sserif;
3153 /* these are for font substitutes */
3154 const char *shelldlg, *tmsrmn;
3155 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3156 *helv_0, *tmsrmn_0;
3157 const struct subst
3159 const char *from, *to;
3160 } arial_0, courier_new_0, times_new_roman_0;
3161 } nls_update_font_list[] =
3163 /* Latin 1 (United States) */
3164 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3165 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3166 "Tahoma","Times New Roman",
3167 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3168 { 0 }, { 0 }, { 0 }
3170 /* Latin 1 (Multilingual) */
3171 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3172 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3173 "Tahoma","Times New Roman", /* FIXME unverified */
3174 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3175 { 0 }, { 0 }, { 0 }
3177 /* Eastern Europe */
3178 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3179 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
3180 "Tahoma","Times New Roman", /* FIXME unverified */
3181 "Fixedsys,238", "System,238",
3182 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3183 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3184 { "Arial CE,0", "Arial,238" },
3185 { "Courier New CE,0", "Courier New,238" },
3186 { "Times New Roman CE,0", "Times New Roman,238" }
3188 /* Cyrillic */
3189 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3190 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
3191 "Tahoma","Times New Roman", /* FIXME unverified */
3192 "Fixedsys,204", "System,204",
3193 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3194 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3195 { "Arial Cyr,0", "Arial,204" },
3196 { "Courier New Cyr,0", "Courier New,204" },
3197 { "Times New Roman Cyr,0", "Times New Roman,204" }
3199 /* Greek */
3200 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3201 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
3202 "Tahoma","Times New Roman", /* FIXME unverified */
3203 "Fixedsys,161", "System,161",
3204 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3205 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3206 { "Arial Greek,0", "Arial,161" },
3207 { "Courier New Greek,0", "Courier New,161" },
3208 { "Times New Roman Greek,0", "Times New Roman,161" }
3210 /* Turkish */
3211 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3212 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
3213 "Tahoma","Times New Roman", /* FIXME unverified */
3214 "Fixedsys,162", "System,162",
3215 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3216 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3217 { "Arial Tur,0", "Arial,162" },
3218 { "Courier New Tur,0", "Courier New,162" },
3219 { "Times New Roman Tur,0", "Times New Roman,162" }
3221 /* Hebrew */
3222 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3223 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
3224 "Tahoma","Times New Roman", /* FIXME unverified */
3225 "Fixedsys,177", "System,177",
3226 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3227 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3228 { 0 }, { 0 }, { 0 }
3230 /* Arabic */
3231 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3232 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
3233 "Tahoma","Times New Roman", /* FIXME unverified */
3234 "Fixedsys,178", "System,178",
3235 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3236 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3237 { 0 }, { 0 }, { 0 }
3239 /* Baltic */
3240 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3241 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
3242 "Tahoma","Times New Roman", /* FIXME unverified */
3243 "Fixedsys,186", "System,186",
3244 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3245 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3246 { "Arial Baltic,0", "Arial,186" },
3247 { "Courier New Baltic,0", "Courier New,186" },
3248 { "Times New Roman Baltic,0", "Times New Roman,186" }
3250 /* Vietnamese */
3251 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3252 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3253 "Tahoma","Times New Roman", /* FIXME unverified */
3254 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3255 { 0 }, { 0 }, { 0 }
3257 /* Thai */
3258 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3259 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
3260 "Tahoma","Times New Roman", /* FIXME unverified */
3261 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3262 { 0 }, { 0 }, { 0 }
3264 /* Japanese */
3265 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3266 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
3267 "MS UI Gothic","MS Serif",
3268 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3269 { 0 }, { 0 }, { 0 }
3271 /* Chinese Simplified */
3272 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3273 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3274 "SimSun", "NSimSun",
3275 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3276 { 0 }, { 0 }, { 0 }
3278 /* Korean */
3279 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3280 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3281 "Gulim", "Batang",
3282 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3283 { 0 }, { 0 }, { 0 }
3285 /* Chinese Traditional */
3286 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3287 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3288 "PMingLiU", "MingLiU",
3289 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3290 { 0 }, { 0 }, { 0 }
3294 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3296 return ( ansi_cp == 932 /* CP932 for Japanese */
3297 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3298 || ansi_cp == 949 /* CP949 for Korean */
3299 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3302 static inline HKEY create_fonts_NT_registry_key(void)
3304 HKEY hkey = 0;
3306 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3307 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3308 return hkey;
3311 static inline HKEY create_fonts_9x_registry_key(void)
3313 HKEY hkey = 0;
3315 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3316 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3317 return hkey;
3320 static inline HKEY create_config_fonts_registry_key(void)
3322 HKEY hkey = 0;
3324 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3325 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3326 return hkey;
3329 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
3331 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3332 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3333 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
3334 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3337 static void set_value_key(HKEY hkey, const char *name, const char *value)
3339 if (value)
3340 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3341 else if (name)
3342 RegDeleteValueA(hkey, name);
3345 static void update_font_info(void)
3347 char buf[40], cpbuf[40];
3348 DWORD len, type;
3349 HKEY hkey = 0;
3350 UINT i, ansi_cp = 0, oem_cp = 0;
3351 BOOL done = FALSE;
3353 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3354 return;
3356 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3357 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3358 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3359 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3360 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3362 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3363 if (is_dbcs_ansi_cp(ansi_cp))
3364 use_default_fallback = TRUE;
3366 len = sizeof(buf);
3367 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3369 if (!strcmp( buf, cpbuf )) /* already set correctly */
3371 RegCloseKey(hkey);
3372 return;
3374 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
3376 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
3378 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3379 RegCloseKey(hkey);
3381 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3383 HKEY hkey;
3385 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3386 nls_update_font_list[i].oem_cp == oem_cp)
3388 hkey = create_config_fonts_registry_key();
3389 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3390 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3391 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3392 RegCloseKey(hkey);
3394 hkey = create_fonts_NT_registry_key();
3395 add_font_list(hkey, &nls_update_font_list[i]);
3396 RegCloseKey(hkey);
3398 hkey = create_fonts_9x_registry_key();
3399 add_font_list(hkey, &nls_update_font_list[i]);
3400 RegCloseKey(hkey);
3402 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3404 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3405 strlen(nls_update_font_list[i].shelldlg)+1);
3406 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3407 strlen(nls_update_font_list[i].tmsrmn)+1);
3409 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3410 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3411 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3412 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3413 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3414 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3415 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3416 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3418 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3419 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3420 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3422 RegCloseKey(hkey);
3424 done = TRUE;
3426 else
3428 /* Delete the FontSubstitutes from other locales */
3429 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3431 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3432 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3433 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3434 RegCloseKey(hkey);
3438 if (!done)
3439 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3442 static BOOL init_freetype(void)
3444 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3445 if(!ft_handle) {
3446 WINE_MESSAGE(
3447 "Wine cannot find the FreeType font library. To enable Wine to\n"
3448 "use TrueType fonts please install a version of FreeType greater than\n"
3449 "or equal to 2.0.5.\n"
3450 "http://www.freetype.org\n");
3451 return FALSE;
3454 #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;}
3456 LOAD_FUNCPTR(FT_Done_Face)
3457 LOAD_FUNCPTR(FT_Get_Char_Index)
3458 LOAD_FUNCPTR(FT_Get_First_Char)
3459 LOAD_FUNCPTR(FT_Get_Module)
3460 LOAD_FUNCPTR(FT_Get_Next_Char)
3461 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3462 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3463 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3464 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3465 LOAD_FUNCPTR(FT_Init_FreeType)
3466 LOAD_FUNCPTR(FT_Library_Version)
3467 LOAD_FUNCPTR(FT_Load_Glyph)
3468 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3469 LOAD_FUNCPTR(FT_Matrix_Multiply)
3470 #ifndef FT_MULFIX_INLINED
3471 LOAD_FUNCPTR(FT_MulFix)
3472 #endif
3473 LOAD_FUNCPTR(FT_New_Face)
3474 LOAD_FUNCPTR(FT_New_Memory_Face)
3475 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3476 LOAD_FUNCPTR(FT_Outline_Transform)
3477 LOAD_FUNCPTR(FT_Outline_Translate)
3478 LOAD_FUNCPTR(FT_Render_Glyph)
3479 LOAD_FUNCPTR(FT_Select_Charmap)
3480 LOAD_FUNCPTR(FT_Set_Charmap)
3481 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3482 LOAD_FUNCPTR(FT_Vector_Transform)
3483 LOAD_FUNCPTR(FT_Vector_Unit)
3484 #undef LOAD_FUNCPTR
3485 /* Don't warn if these ones are missing */
3486 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3487 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3488 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3489 #endif
3491 if(pFT_Init_FreeType(&library) != 0) {
3492 ERR("Can't init FreeType library\n");
3493 wine_dlclose(ft_handle, NULL, 0);
3494 ft_handle = NULL;
3495 return FALSE;
3497 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3499 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3500 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3501 ((FT_Version.minor << 8) & 0x00ff00) |
3502 ((FT_Version.patch ) & 0x0000ff);
3504 font_driver = &freetype_funcs;
3505 return TRUE;
3507 sym_not_found:
3508 WINE_MESSAGE(
3509 "Wine cannot find certain functions that it needs inside the FreeType\n"
3510 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3511 "FreeType to at least version 2.1.4.\n"
3512 "http://www.freetype.org\n");
3513 wine_dlclose(ft_handle, NULL, 0);
3514 ft_handle = NULL;
3515 return FALSE;
3518 static void init_font_list(void)
3520 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3521 static const WCHAR pathW[] = {'P','a','t','h',0};
3522 HKEY hkey;
3523 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3524 WCHAR windowsdir[MAX_PATH];
3525 char *unixname;
3526 const char *data_dir;
3528 delete_external_font_keys();
3530 /* load the system bitmap fonts */
3531 load_system_fonts();
3533 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3534 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3535 strcatW(windowsdir, fontsW);
3536 if((unixname = wine_get_unix_file_name(windowsdir)))
3538 ReadFontDir(unixname, FALSE);
3539 HeapFree(GetProcessHeap(), 0, unixname);
3542 /* load the system truetype fonts */
3543 data_dir = wine_get_data_dir();
3544 if (!data_dir) data_dir = wine_get_build_dir();
3545 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3547 strcpy(unixname, data_dir);
3548 strcat(unixname, "/fonts/");
3549 ReadFontDir(unixname, TRUE);
3550 HeapFree(GetProcessHeap(), 0, unixname);
3553 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3554 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3555 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3556 will skip these. */
3557 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3558 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3559 &hkey) == ERROR_SUCCESS)
3561 LPWSTR data, valueW;
3562 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3563 &valuelen, &datalen, NULL, NULL);
3565 valuelen++; /* returned value doesn't include room for '\0' */
3566 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3567 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3568 if (valueW && data)
3570 dlen = datalen * sizeof(WCHAR);
3571 vlen = valuelen;
3572 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3573 &dlen) == ERROR_SUCCESS)
3575 if(data[0] && (data[1] == ':'))
3577 if((unixname = wine_get_unix_file_name(data)))
3579 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3580 HeapFree(GetProcessHeap(), 0, unixname);
3583 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3585 WCHAR pathW[MAX_PATH];
3586 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3587 BOOL added = FALSE;
3589 sprintfW(pathW, fmtW, windowsdir, data);
3590 if((unixname = wine_get_unix_file_name(pathW)))
3592 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3593 HeapFree(GetProcessHeap(), 0, unixname);
3595 if (!added)
3596 load_font_from_data_dir(data);
3598 /* reset dlen and vlen */
3599 dlen = datalen;
3600 vlen = valuelen;
3603 HeapFree(GetProcessHeap(), 0, data);
3604 HeapFree(GetProcessHeap(), 0, valueW);
3605 RegCloseKey(hkey);
3608 #ifdef SONAME_LIBFONTCONFIG
3609 load_fontconfig_fonts();
3610 #elif defined(HAVE_CARBON_CARBON_H)
3611 load_mac_fonts();
3612 #endif
3614 /* then look in any directories that we've specified in the config file */
3615 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3616 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3618 DWORD len;
3619 LPWSTR valueW;
3620 LPSTR valueA, ptr;
3622 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3624 len += sizeof(WCHAR);
3625 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3626 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3628 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3629 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3630 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3631 TRACE( "got font path %s\n", debugstr_a(valueA) );
3632 ptr = valueA;
3633 while (ptr)
3635 const char* home;
3636 LPSTR next = strchr( ptr, ':' );
3637 if (next) *next++ = 0;
3638 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3639 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3641 strcpy( unixname, home );
3642 strcat( unixname, ptr + 1 );
3643 ReadFontDir( unixname, TRUE );
3644 HeapFree( GetProcessHeap(), 0, unixname );
3646 else
3647 ReadFontDir( ptr, TRUE );
3648 ptr = next;
3650 HeapFree( GetProcessHeap(), 0, valueA );
3652 HeapFree( GetProcessHeap(), 0, valueW );
3654 RegCloseKey(hkey);
3658 static BOOL move_to_front(const WCHAR *name)
3660 Family *family, *cursor2;
3661 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3663 if(!strcmpiW(family->FamilyName, name))
3665 list_remove(&family->entry);
3666 list_add_head(&font_list, &family->entry);
3667 return TRUE;
3670 return FALSE;
3673 static BOOL set_default(const WCHAR **name_list)
3675 while (*name_list)
3677 if (move_to_front(*name_list)) return TRUE;
3678 name_list++;
3681 return FALSE;
3684 static void reorder_font_list(void)
3686 set_default( default_serif_list );
3687 set_default( default_fixed_list );
3688 set_default( default_sans_list );
3691 /*************************************************************
3692 * WineEngInit
3694 * Initialize FreeType library and create a list of available faces
3696 BOOL WineEngInit(void)
3698 HKEY hkey_font_cache;
3699 DWORD disposition;
3700 HANDLE font_mutex;
3702 /* update locale dependent font info in registry */
3703 update_font_info();
3705 if(!init_freetype()) return FALSE;
3707 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3709 ERR("Failed to create font mutex\n");
3710 return FALSE;
3712 WaitForSingleObject(font_mutex, INFINITE);
3714 create_font_cache_key(&hkey_font_cache, &disposition);
3716 if(disposition == REG_CREATED_NEW_KEY)
3717 init_font_list();
3718 else
3719 load_font_list_from_cache(hkey_font_cache);
3721 RegCloseKey(hkey_font_cache);
3723 reorder_font_list();
3725 DumpFontList();
3726 LoadSubstList();
3727 DumpSubstList();
3728 LoadReplaceList();
3730 if(disposition == REG_CREATED_NEW_KEY)
3731 update_reg_entries();
3733 init_system_links();
3735 ReleaseMutex(font_mutex);
3736 return TRUE;
3740 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3742 TT_OS2 *pOS2;
3743 TT_HoriHeader *pHori;
3745 LONG ppem;
3747 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3748 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3750 if(height == 0) height = 16;
3752 /* Calc. height of EM square:
3754 * For +ve lfHeight we have
3755 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3756 * Re-arranging gives:
3757 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3759 * For -ve lfHeight we have
3760 * |lfHeight| = ppem
3761 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3762 * with il = winAscent + winDescent - units_per_em]
3766 if(height > 0) {
3767 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3768 ppem = MulDiv(ft_face->units_per_EM, height,
3769 pHori->Ascender - pHori->Descender);
3770 else
3771 ppem = MulDiv(ft_face->units_per_EM, height,
3772 pOS2->usWinAscent + pOS2->usWinDescent);
3774 else
3775 ppem = -height;
3777 return ppem;
3780 static struct font_mapping *map_font_file( const char *name )
3782 struct font_mapping *mapping;
3783 struct stat st;
3784 int fd;
3786 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3787 if (fstat( fd, &st ) == -1) goto error;
3789 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3791 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3793 mapping->refcount++;
3794 close( fd );
3795 return mapping;
3798 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3799 goto error;
3801 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3802 close( fd );
3804 if (mapping->data == MAP_FAILED)
3806 HeapFree( GetProcessHeap(), 0, mapping );
3807 return NULL;
3809 mapping->refcount = 1;
3810 mapping->dev = st.st_dev;
3811 mapping->ino = st.st_ino;
3812 mapping->size = st.st_size;
3813 list_add_tail( &mappings_list, &mapping->entry );
3814 return mapping;
3816 error:
3817 close( fd );
3818 return NULL;
3821 static void unmap_font_file( struct font_mapping *mapping )
3823 if (!--mapping->refcount)
3825 list_remove( &mapping->entry );
3826 munmap( mapping->data, mapping->size );
3827 HeapFree( GetProcessHeap(), 0, mapping );
3831 static LONG load_VDMX(GdiFont*, LONG);
3833 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3835 FT_Error err;
3836 FT_Face ft_face;
3837 void *data_ptr;
3838 DWORD data_size;
3840 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3842 if (face->file)
3844 if (!(font->mapping = map_font_file( face->file )))
3846 WARN("failed to map %s\n", debugstr_a(face->file));
3847 return 0;
3849 data_ptr = font->mapping->data;
3850 data_size = font->mapping->size;
3852 else
3854 data_ptr = face->font_data_ptr;
3855 data_size = face->font_data_size;
3858 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3859 if(err) {
3860 ERR("FT_New_Face rets %d\n", err);
3861 return 0;
3864 /* set it here, as load_VDMX needs it */
3865 font->ft_face = ft_face;
3867 if(FT_IS_SCALABLE(ft_face)) {
3868 /* load the VDMX table if we have one */
3869 font->ppem = load_VDMX(font, height);
3870 if(font->ppem == 0)
3871 font->ppem = calc_ppem_for_height(ft_face, height);
3872 TRACE("height %d => ppem %d\n", height, font->ppem);
3874 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3875 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3876 } else {
3877 font->ppem = height;
3878 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3879 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3881 return ft_face;
3885 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3887 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3888 a single face with the requested charset. The idea is to check if
3889 the selected font supports the current ANSI codepage, if it does
3890 return the corresponding charset, else return the first charset */
3892 CHARSETINFO csi;
3893 int acp = GetACP(), i;
3894 DWORD fs0;
3896 *cp = acp;
3897 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3899 const SYSTEM_LINKS *font_link;
3901 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
3902 return csi.ciCharset;
3904 font_link = find_font_link(family_name);
3905 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
3906 return csi.ciCharset;
3909 for(i = 0; i < 32; i++) {
3910 fs0 = 1L << i;
3911 if(face->fs.fsCsb[0] & fs0) {
3912 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3913 *cp = csi.ciACP;
3914 return csi.ciCharset;
3916 else
3917 FIXME("TCI failing on %x\n", fs0);
3921 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3922 face->fs.fsCsb[0], face->file);
3923 *cp = acp;
3924 return DEFAULT_CHARSET;
3927 static GdiFont *alloc_font(void)
3929 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3930 ret->gmsize = 1;
3931 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3932 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3933 ret->potm = NULL;
3934 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3935 ret->total_kern_pairs = (DWORD)-1;
3936 ret->kern_pairs = NULL;
3937 list_init(&ret->hfontlist);
3938 list_init(&ret->child_fonts);
3939 return ret;
3942 static void free_font(GdiFont *font)
3944 struct list *cursor, *cursor2;
3945 DWORD i;
3947 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3949 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3950 list_remove(cursor);
3951 if(child->font)
3952 free_font(child->font);
3953 HeapFree(GetProcessHeap(), 0, child);
3956 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3958 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3959 DeleteObject(hfontlist->hfont);
3960 list_remove(&hfontlist->entry);
3961 HeapFree(GetProcessHeap(), 0, hfontlist);
3964 if (font->ft_face) pFT_Done_Face(font->ft_face);
3965 if (font->mapping) unmap_font_file( font->mapping );
3966 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3967 HeapFree(GetProcessHeap(), 0, font->potm);
3968 HeapFree(GetProcessHeap(), 0, font->name);
3969 for (i = 0; i < font->gmsize; i++)
3970 HeapFree(GetProcessHeap(),0,font->gm[i]);
3971 HeapFree(GetProcessHeap(), 0, font->gm);
3972 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3973 HeapFree(GetProcessHeap(), 0, font);
3977 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3979 FT_Face ft_face = font->ft_face;
3980 FT_ULong len;
3981 FT_Error err;
3983 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3985 if(!buf)
3986 len = 0;
3987 else
3988 len = cbData;
3990 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3992 /* make sure value of len is the value freetype says it needs */
3993 if (buf && len)
3995 FT_ULong needed = 0;
3996 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3997 if( !err && needed < len) len = needed;
3999 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4000 if (err)
4002 TRACE("Can't find table %c%c%c%c\n",
4003 /* bytes were reversed */
4004 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4005 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4006 return GDI_ERROR;
4008 return len;
4011 /*************************************************************
4012 * load_VDMX
4014 * load the vdmx entry for the specified height
4017 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4018 ( ( (FT_ULong)_x4 << 24 ) | \
4019 ( (FT_ULong)_x3 << 16 ) | \
4020 ( (FT_ULong)_x2 << 8 ) | \
4021 (FT_ULong)_x1 )
4023 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4025 typedef struct {
4026 BYTE bCharSet;
4027 BYTE xRatio;
4028 BYTE yStartRatio;
4029 BYTE yEndRatio;
4030 } Ratios;
4032 typedef struct {
4033 WORD recs;
4034 BYTE startsz;
4035 BYTE endsz;
4036 } VDMX_group;
4038 static LONG load_VDMX(GdiFont *font, LONG height)
4040 WORD hdr[3], tmp;
4041 VDMX_group group;
4042 BYTE devXRatio, devYRatio;
4043 USHORT numRecs, numRatios;
4044 DWORD result, offset = -1;
4045 LONG ppem = 0;
4046 int i;
4048 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
4050 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4051 return ppem;
4053 /* FIXME: need the real device aspect ratio */
4054 devXRatio = 1;
4055 devYRatio = 1;
4057 numRecs = GET_BE_WORD(hdr[1]);
4058 numRatios = GET_BE_WORD(hdr[2]);
4060 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4061 for(i = 0; i < numRatios; i++) {
4062 Ratios ratio;
4064 offset = (3 * 2) + (i * sizeof(Ratios));
4065 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4066 offset = -1;
4068 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4070 if((ratio.xRatio == 0 &&
4071 ratio.yStartRatio == 0 &&
4072 ratio.yEndRatio == 0) ||
4073 (devXRatio == ratio.xRatio &&
4074 devYRatio >= ratio.yStartRatio &&
4075 devYRatio <= ratio.yEndRatio))
4077 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4078 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4079 offset = GET_BE_WORD(tmp);
4080 break;
4084 if(offset == -1) {
4085 FIXME("No suitable ratio found\n");
4086 return ppem;
4089 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4090 USHORT recs;
4091 BYTE startsz, endsz;
4092 WORD *vTable;
4094 recs = GET_BE_WORD(group.recs);
4095 startsz = group.startsz;
4096 endsz = group.endsz;
4098 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4100 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4101 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4102 if(result == GDI_ERROR) {
4103 FIXME("Failed to retrieve vTable\n");
4104 goto end;
4107 if(height > 0) {
4108 for(i = 0; i < recs; i++) {
4109 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4110 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4111 ppem = GET_BE_WORD(vTable[i * 3]);
4113 if(yMax + -yMin == height) {
4114 font->yMax = yMax;
4115 font->yMin = yMin;
4116 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4117 break;
4119 if(yMax + -yMin > height) {
4120 if(--i < 0) {
4121 ppem = 0;
4122 goto end; /* failed */
4124 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4125 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4126 ppem = GET_BE_WORD(vTable[i * 3]);
4127 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4128 break;
4131 if(!font->yMax) {
4132 ppem = 0;
4133 TRACE("ppem not found for height %d\n", height);
4136 end:
4137 HeapFree(GetProcessHeap(), 0, vTable);
4140 return ppem;
4143 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4145 if(font->font_desc.hash != fd->hash) return TRUE;
4146 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4147 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4148 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4149 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4152 static void calc_hash(FONT_DESC *pfd)
4154 DWORD hash = 0, *ptr, two_chars;
4155 WORD *pwc;
4156 unsigned int i;
4158 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4159 hash ^= *ptr;
4160 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4161 hash ^= *ptr;
4162 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4163 two_chars = *ptr;
4164 pwc = (WCHAR *)&two_chars;
4165 if(!*pwc) break;
4166 *pwc = toupperW(*pwc);
4167 pwc++;
4168 *pwc = toupperW(*pwc);
4169 hash ^= two_chars;
4170 if(!*pwc) break;
4172 hash ^= !pfd->can_use_bitmap;
4173 pfd->hash = hash;
4174 return;
4177 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4179 GdiFont *ret;
4180 FONT_DESC fd;
4181 HFONTLIST *hflist;
4182 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4184 fd.lf = *plf;
4185 fd.matrix = *pmat;
4186 fd.can_use_bitmap = can_use_bitmap;
4187 calc_hash(&fd);
4189 /* try the child list */
4190 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
4191 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4192 if(!fontcmp(ret, &fd)) {
4193 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4194 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4195 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4196 if(hflist->hfont == hfont)
4197 return ret;
4202 /* try the in-use list */
4203 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
4204 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4205 if(!fontcmp(ret, &fd)) {
4206 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4207 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4208 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4209 if(hflist->hfont == hfont)
4210 return ret;
4212 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4213 hflist->hfont = hfont;
4214 list_add_head(&ret->hfontlist, &hflist->entry);
4215 return ret;
4219 /* then the unused list */
4220 font_elem_ptr = list_head(&unused_gdi_font_list);
4221 while(font_elem_ptr) {
4222 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4223 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4224 if(!fontcmp(ret, &fd)) {
4225 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4226 assert(list_empty(&ret->hfontlist));
4227 TRACE("Found %p in unused list\n", ret);
4228 list_remove(&ret->entry);
4229 list_add_head(&gdi_font_list, &ret->entry);
4230 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4231 hflist->hfont = hfont;
4232 list_add_head(&ret->hfontlist, &hflist->entry);
4233 return ret;
4236 return NULL;
4239 static void add_to_cache(GdiFont *font)
4241 static DWORD cache_num = 1;
4243 font->cache_num = cache_num++;
4244 list_add_head(&gdi_font_list, &font->entry);
4247 /*************************************************************
4248 * create_child_font_list
4250 static BOOL create_child_font_list(GdiFont *font)
4252 BOOL ret = FALSE;
4253 SYSTEM_LINKS *font_link;
4254 CHILD_FONT *font_link_entry, *new_child;
4255 FontSubst *psub;
4256 WCHAR* font_name;
4258 psub = get_font_subst(&font_subst_list, font->name, -1);
4259 font_name = psub ? psub->to.name : font->name;
4260 font_link = find_font_link(font_name);
4261 if (font_link != NULL)
4263 TRACE("found entry in system list\n");
4264 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4266 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4267 new_child->face = font_link_entry->face;
4268 new_child->font = NULL;
4269 list_add_tail(&font->child_fonts, &new_child->entry);
4270 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
4272 ret = TRUE;
4275 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4276 * Sans Serif. This is how asian windows get default fallbacks for fonts
4278 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4279 font->charset != OEM_CHARSET &&
4280 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4282 font_link = find_font_link(szDefaultFallbackLink);
4283 if (font_link != NULL)
4285 TRACE("found entry in default fallback list\n");
4286 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4288 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4289 new_child->face = font_link_entry->face;
4290 new_child->font = NULL;
4291 list_add_tail(&font->child_fonts, &new_child->entry);
4292 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
4294 ret = TRUE;
4298 return ret;
4301 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4303 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4305 if (pFT_Set_Charmap)
4307 FT_Int i;
4308 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4310 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4312 for (i = 0; i < ft_face->num_charmaps; i++)
4314 if (ft_face->charmaps[i]->encoding == encoding)
4316 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4317 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4319 switch (ft_face->charmaps[i]->platform_id)
4321 default:
4322 cmap_def = ft_face->charmaps[i];
4323 break;
4324 case 0: /* Apple Unicode */
4325 cmap0 = ft_face->charmaps[i];
4326 break;
4327 case 1: /* Macintosh */
4328 cmap1 = ft_face->charmaps[i];
4329 break;
4330 case 2: /* ISO */
4331 cmap2 = ft_face->charmaps[i];
4332 break;
4333 case 3: /* Microsoft */
4334 cmap3 = ft_face->charmaps[i];
4335 break;
4339 if (cmap3) /* prefer Microsoft cmap table */
4340 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4341 else if (cmap1)
4342 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4343 else if (cmap2)
4344 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4345 else if (cmap0)
4346 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4347 else if (cmap_def)
4348 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4350 return ft_err == FT_Err_Ok;
4353 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4357 /*************************************************************
4358 * freetype_CreateDC
4360 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4361 LPCWSTR output, const DEVMODEW *devmode )
4363 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4365 if (!physdev) return FALSE;
4366 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4367 return TRUE;
4371 /*************************************************************
4372 * freetype_DeleteDC
4374 static BOOL freetype_DeleteDC( PHYSDEV dev )
4376 struct freetype_physdev *physdev = get_freetype_dev( dev );
4377 HeapFree( GetProcessHeap(), 0, physdev );
4378 return TRUE;
4382 /*************************************************************
4383 * freetype_SelectFont
4385 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
4387 struct freetype_physdev *physdev = get_freetype_dev( dev );
4388 GdiFont *ret;
4389 Face *face, *best, *best_bitmap;
4390 Family *family, *last_resort_family;
4391 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
4392 INT height, width = 0;
4393 unsigned int score = 0, new_score;
4394 signed int diff = 0, newdiff;
4395 BOOL bd, it, can_use_bitmap, want_vertical;
4396 LOGFONTW lf;
4397 CHARSETINFO csi;
4398 HFONTLIST *hflist;
4399 FMAT2 dcmat;
4400 FontSubst *psub = NULL;
4401 DC *dc = get_dc_ptr( dev->hdc );
4402 const SYSTEM_LINKS *font_link;
4404 if (!hfont) /* notification that the font has been changed by another driver */
4406 dc->gdiFont = NULL;
4407 physdev->font = NULL;
4408 release_dc_ptr( dc );
4409 return 0;
4412 GetObjectW( hfont, sizeof(lf), &lf );
4413 lf.lfWidth = abs(lf.lfWidth);
4415 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4417 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4418 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4419 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4420 lf.lfEscapement);
4422 if(dc->GraphicsMode == GM_ADVANCED)
4424 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4425 /* Try to avoid not necessary glyph transformations */
4426 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4428 lf.lfHeight *= fabs(dcmat.eM11);
4429 lf.lfWidth *= fabs(dcmat.eM11);
4430 dcmat.eM11 = dcmat.eM22 = 1.0;
4433 else
4435 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4436 font scaling abilities. */
4437 dcmat.eM11 = dcmat.eM22 = 1.0;
4438 dcmat.eM21 = dcmat.eM12 = 0;
4439 if (dc->vport2WorldValid)
4441 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4442 lf.lfOrientation = -lf.lfOrientation;
4443 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4444 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4448 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4449 dcmat.eM21, dcmat.eM22);
4451 GDI_CheckNotLock();
4452 EnterCriticalSection( &freetype_cs );
4454 /* check the cache first */
4455 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4456 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4457 goto done;
4460 if(list_empty(&font_list)) /* No fonts installed */
4462 TRACE("No fonts installed\n");
4463 goto done;
4466 TRACE("not in cache\n");
4467 ret = alloc_font();
4469 ret->font_desc.matrix = dcmat;
4470 ret->font_desc.lf = lf;
4471 ret->font_desc.can_use_bitmap = can_use_bitmap;
4472 calc_hash(&ret->font_desc);
4473 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4474 hflist->hfont = hfont;
4475 list_add_head(&ret->hfontlist, &hflist->entry);
4477 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4478 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4479 original value lfCharSet. Note this is a special case for
4480 Symbol and doesn't happen at least for "Wingdings*" */
4482 if(!strcmpiW(lf.lfFaceName, SymbolW))
4483 lf.lfCharSet = SYMBOL_CHARSET;
4485 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4486 switch(lf.lfCharSet) {
4487 case DEFAULT_CHARSET:
4488 csi.fs.fsCsb[0] = 0;
4489 break;
4490 default:
4491 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4492 csi.fs.fsCsb[0] = 0;
4493 break;
4497 family = NULL;
4498 if(lf.lfFaceName[0] != '\0') {
4499 CHILD_FONT *font_link_entry;
4500 LPWSTR FaceName = lf.lfFaceName;
4502 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4504 if(psub) {
4505 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4506 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4507 if (psub->to.charset != -1)
4508 lf.lfCharSet = psub->to.charset;
4511 /* We want a match on name and charset or just name if
4512 charset was DEFAULT_CHARSET. If the latter then
4513 we fixup the returned charset later in get_nearest_charset
4514 where we'll either use the charset of the current ansi codepage
4515 or if that's unavailable the first charset that the font supports.
4517 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4518 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4519 if (!strcmpiW(family->FamilyName, FaceName) ||
4520 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4522 font_link = find_font_link(family->FamilyName);
4523 face_list = get_face_list_from_family(family);
4524 LIST_FOR_EACH(face_elem_ptr, face_list) {
4525 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4526 if (!(face->scalable || can_use_bitmap))
4527 continue;
4528 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4529 goto found;
4530 if (font_link != NULL &&
4531 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4532 goto found;
4533 if (!csi.fs.fsCsb[0])
4534 goto found;
4539 /* Search by full face name. */
4540 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4541 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4542 face_list = get_face_list_from_family(family);
4543 LIST_FOR_EACH(face_elem_ptr, face_list) {
4544 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4545 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4546 (face->scalable || can_use_bitmap))
4548 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4549 goto found_face;
4550 font_link = find_font_link(family->FamilyName);
4551 if (font_link != NULL &&
4552 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4553 goto found_face;
4559 * Try check the SystemLink list first for a replacement font.
4560 * We may find good replacements there.
4562 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4564 if(!strcmpiW(font_link->font_name, FaceName) ||
4565 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4567 TRACE("found entry in system list\n");
4568 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4570 const SYSTEM_LINKS *links;
4572 face = font_link_entry->face;
4573 if (!(face->scalable || can_use_bitmap))
4574 continue;
4575 family = face->family;
4576 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4577 goto found;
4578 links = find_font_link(family->FamilyName);
4579 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4580 goto found;
4586 psub = NULL; /* substitution is no more relevant */
4588 /* If requested charset was DEFAULT_CHARSET then try using charset
4589 corresponding to the current ansi codepage */
4590 if (!csi.fs.fsCsb[0])
4592 INT acp = GetACP();
4593 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4594 FIXME("TCI failed on codepage %d\n", acp);
4595 csi.fs.fsCsb[0] = 0;
4596 } else
4597 lf.lfCharSet = csi.ciCharset;
4600 want_vertical = (lf.lfFaceName[0] == '@');
4602 /* Face families are in the top 4 bits of lfPitchAndFamily,
4603 so mask with 0xF0 before testing */
4605 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4606 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4607 strcpyW(lf.lfFaceName, defFixed);
4608 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4609 strcpyW(lf.lfFaceName, defSerif);
4610 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4611 strcpyW(lf.lfFaceName, defSans);
4612 else
4613 strcpyW(lf.lfFaceName, defSans);
4614 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4615 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4616 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4617 font_link = find_font_link(family->FamilyName);
4618 face_list = get_face_list_from_family(family);
4619 LIST_FOR_EACH(face_elem_ptr, face_list) {
4620 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4621 if (!(face->scalable || can_use_bitmap))
4622 continue;
4623 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4624 goto found;
4625 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4626 goto found;
4631 last_resort_family = NULL;
4632 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4633 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4634 font_link = find_font_link(family->FamilyName);
4635 face_list = get_face_list_from_family(family);
4636 LIST_FOR_EACH(face_elem_ptr, face_list) {
4637 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4638 if(face->vertical == want_vertical &&
4639 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4640 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4641 if(face->scalable)
4642 goto found;
4643 if(can_use_bitmap && !last_resort_family)
4644 last_resort_family = family;
4649 if(last_resort_family) {
4650 family = last_resort_family;
4651 csi.fs.fsCsb[0] = 0;
4652 goto found;
4655 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4656 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4657 face_list = get_face_list_from_family(family);
4658 LIST_FOR_EACH(face_elem_ptr, face_list) {
4659 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4660 if(face->scalable && face->vertical == want_vertical) {
4661 csi.fs.fsCsb[0] = 0;
4662 WARN("just using first face for now\n");
4663 goto found;
4665 if(can_use_bitmap && !last_resort_family)
4666 last_resort_family = family;
4669 if(!last_resort_family) {
4670 FIXME("can't find a single appropriate font - bailing\n");
4671 free_font(ret);
4672 ret = NULL;
4673 goto done;
4676 WARN("could only find a bitmap font - this will probably look awful!\n");
4677 family = last_resort_family;
4678 csi.fs.fsCsb[0] = 0;
4680 found:
4681 it = lf.lfItalic ? 1 : 0;
4682 bd = lf.lfWeight > 550 ? 1 : 0;
4684 height = lf.lfHeight;
4686 face = best = best_bitmap = NULL;
4687 font_link = find_font_link(family->FamilyName);
4688 face_list = get_face_list_from_family(family);
4689 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4691 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4692 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4693 !csi.fs.fsCsb[0])
4695 BOOL italic, bold;
4697 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4698 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4699 new_score = (italic ^ it) + (bold ^ bd);
4700 if(!best || new_score <= score)
4702 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4703 italic, bold, it, bd);
4704 score = new_score;
4705 best = face;
4706 if(best->scalable && score == 0) break;
4707 if(!best->scalable)
4709 if(height > 0)
4710 newdiff = height - (signed int)(best->size.height);
4711 else
4712 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4713 if(!best_bitmap || new_score < score ||
4714 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4716 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4717 diff = newdiff;
4718 best_bitmap = best;
4719 if(score == 0 && diff == 0) break;
4725 if(best)
4726 face = best->scalable ? best : best_bitmap;
4727 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4728 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4730 found_face:
4731 height = lf.lfHeight;
4733 ret->fs = face->fs;
4735 if(csi.fs.fsCsb[0]) {
4736 ret->charset = lf.lfCharSet;
4737 ret->codepage = csi.ciACP;
4739 else
4740 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4742 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4743 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4745 ret->aveWidth = height ? lf.lfWidth : 0;
4747 if(!face->scalable) {
4748 /* Windows uses integer scaling factors for bitmap fonts */
4749 INT scale, scaled_height;
4750 GdiFont *cachedfont;
4752 /* FIXME: rotation of bitmap fonts is ignored */
4753 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4754 if (ret->aveWidth)
4755 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4756 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4757 dcmat.eM11 = dcmat.eM22 = 1.0;
4758 /* As we changed the matrix, we need to search the cache for the font again,
4759 * otherwise we might explode the cache. */
4760 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4761 TRACE("Found cached font after non-scalable matrix rescale!\n");
4762 free_font( ret );
4763 ret = cachedfont;
4764 goto done;
4766 calc_hash(&ret->font_desc);
4768 if (height != 0) height = diff;
4769 height += face->size.height;
4771 scale = (height + face->size.height - 1) / face->size.height;
4772 scaled_height = scale * face->size.height;
4773 /* Only jump to the next height if the difference <= 25% original height */
4774 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4775 /* The jump between unscaled and doubled is delayed by 1 */
4776 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4777 ret->scale_y = scale;
4779 width = face->size.x_ppem >> 6;
4780 height = face->size.y_ppem >> 6;
4782 else
4783 ret->scale_y = 1.0;
4784 TRACE("font scale y: %f\n", ret->scale_y);
4786 ret->ft_face = OpenFontFace(ret, face, width, height);
4788 if (!ret->ft_face)
4790 free_font( ret );
4791 ret = NULL;
4792 goto done;
4795 ret->ntmFlags = face->ntmFlags;
4797 if (ret->charset == SYMBOL_CHARSET &&
4798 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4799 /* No ops */
4801 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4802 /* No ops */
4804 else {
4805 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4808 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4809 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4810 ret->underline = lf.lfUnderline ? 0xff : 0;
4811 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4812 create_child_font_list(ret);
4814 if (face->vertical) /* We need to try to load the GSUB table */
4816 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4817 if (length != GDI_ERROR)
4819 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4820 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4821 TRACE("Loaded GSUB table of %i bytes\n",length);
4825 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4827 add_to_cache(ret);
4828 done:
4829 if (ret)
4831 dc->gdiFont = ret;
4832 physdev->font = ret;
4834 LeaveCriticalSection( &freetype_cs );
4835 release_dc_ptr( dc );
4836 return ret ? hfont : 0;
4839 static void dump_gdi_font_list(void)
4841 GdiFont *gdiFont;
4842 struct list *elem_ptr;
4844 TRACE("---------- gdiFont Cache ----------\n");
4845 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4846 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4847 TRACE("gdiFont=%p %s %d\n",
4848 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4851 TRACE("---------- Unused gdiFont Cache ----------\n");
4852 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4853 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4854 TRACE("gdiFont=%p %s %d\n",
4855 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4858 TRACE("---------- Child gdiFont Cache ----------\n");
4859 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4860 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4861 TRACE("gdiFont=%p %s %d\n",
4862 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4866 /*************************************************************
4867 * WineEngDestroyFontInstance
4869 * free the gdiFont associated with this handle
4872 BOOL WineEngDestroyFontInstance(HFONT handle)
4874 GdiFont *gdiFont;
4875 HFONTLIST *hflist;
4876 BOOL ret = FALSE;
4877 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4878 int i = 0;
4880 GDI_CheckNotLock();
4881 EnterCriticalSection( &freetype_cs );
4883 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4885 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4886 while(hfontlist_elem_ptr) {
4887 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4888 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4889 if(hflist->hfont == handle) {
4890 TRACE("removing child font %p from child list\n", gdiFont);
4891 list_remove(&gdiFont->entry);
4892 LeaveCriticalSection( &freetype_cs );
4893 return TRUE;
4898 TRACE("destroying hfont=%p\n", handle);
4899 if(TRACE_ON(font))
4900 dump_gdi_font_list();
4902 font_elem_ptr = list_head(&gdi_font_list);
4903 while(font_elem_ptr) {
4904 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4905 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4907 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4908 while(hfontlist_elem_ptr) {
4909 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4910 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4911 if(hflist->hfont == handle) {
4912 list_remove(&hflist->entry);
4913 HeapFree(GetProcessHeap(), 0, hflist);
4914 ret = TRUE;
4917 if(list_empty(&gdiFont->hfontlist)) {
4918 TRACE("Moving to Unused list\n");
4919 list_remove(&gdiFont->entry);
4920 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4925 font_elem_ptr = list_head(&unused_gdi_font_list);
4926 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4927 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4928 while(font_elem_ptr) {
4929 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4930 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4931 TRACE("freeing %p\n", gdiFont);
4932 list_remove(&gdiFont->entry);
4933 free_font(gdiFont);
4935 LeaveCriticalSection( &freetype_cs );
4936 return ret;
4939 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4941 HRSRC rsrc;
4942 HGLOBAL hMem;
4943 WCHAR *p;
4944 int i;
4946 id += IDS_FIRST_SCRIPT;
4947 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4948 if (!rsrc) return 0;
4949 hMem = LoadResource( gdi32_module, rsrc );
4950 if (!hMem) return 0;
4952 p = LockResource( hMem );
4953 id &= 0x000f;
4954 while (id--) p += *p + 1;
4956 i = min(LF_FACESIZE - 1, *p);
4957 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4958 buffer[i] = 0;
4959 return i;
4963 /***************************************************
4964 * create_enum_charset_list
4966 * This function creates charset enumeration list because in DEFAULT_CHARSET
4967 * case, the ANSI codepage's charset takes precedence over other charsets.
4968 * This function works as a filter other than DEFAULT_CHARSET case.
4970 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4972 CHARSETINFO csi;
4973 DWORD n = 0;
4975 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4976 csi.fs.fsCsb[0] != 0) {
4977 list->element[n].mask = csi.fs.fsCsb[0];
4978 list->element[n].charset = csi.ciCharset;
4979 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4980 n++;
4982 else { /* charset is DEFAULT_CHARSET or invalid. */
4983 INT acp, i;
4985 /* Set the current codepage's charset as the first element. */
4986 acp = GetACP();
4987 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4988 csi.fs.fsCsb[0] != 0) {
4989 list->element[n].mask = csi.fs.fsCsb[0];
4990 list->element[n].charset = csi.ciCharset;
4991 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4992 n++;
4995 /* Fill out left elements. */
4996 for (i = 0; i < 32; i++) {
4997 FONTSIGNATURE fs;
4998 fs.fsCsb[0] = 1L << i;
4999 fs.fsCsb[1] = 0;
5000 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
5001 continue; /* skip, already added. */
5002 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5003 continue; /* skip, this is an invalid fsCsb bit. */
5005 list->element[n].mask = fs.fsCsb[0];
5006 list->element[n].charset = csi.ciCharset;
5007 load_script_name( i, list->element[n].name );
5008 n++;
5011 list->total = n;
5013 return n;
5016 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
5017 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5019 GdiFont *font;
5020 LONG width, height;
5022 if (face->cached_enum_data)
5024 TRACE("Cached\n");
5025 *pelf = face->cached_enum_data->elf;
5026 *pntm = face->cached_enum_data->ntm;
5027 *ptype = face->cached_enum_data->type;
5028 return;
5031 font = alloc_font();
5033 if(face->scalable) {
5034 height = -2048; /* 2048 is the most common em size */
5035 width = 0;
5036 } else {
5037 height = face->size.y_ppem >> 6;
5038 width = face->size.x_ppem >> 6;
5040 font->scale_y = 1.0;
5042 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5044 free_font(font);
5045 return;
5048 font->name = strdupW(face->family->FamilyName);
5049 font->ntmFlags = face->ntmFlags;
5051 if (get_outline_text_metrics(font))
5053 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5055 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5057 lstrcpynW(pelf->elfLogFont.lfFaceName,
5058 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5059 LF_FACESIZE);
5060 lstrcpynW(pelf->elfFullName,
5061 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
5062 LF_FULLFACESIZE);
5063 lstrcpynW(pelf->elfStyle,
5064 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5065 LF_FACESIZE);
5067 else
5069 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5071 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5073 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
5074 if (face->FullName)
5075 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5076 else
5077 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
5078 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5081 pntm->ntmTm.ntmFlags = face->ntmFlags;
5082 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5083 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5084 pntm->ntmFontSig = face->fs;
5086 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5088 pelf->elfLogFont.lfEscapement = 0;
5089 pelf->elfLogFont.lfOrientation = 0;
5090 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5091 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5092 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5093 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5094 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5095 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5096 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5097 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5098 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5099 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5100 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5102 *ptype = 0;
5103 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5104 *ptype |= TRUETYPE_FONTTYPE;
5105 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5106 *ptype |= DEVICE_FONTTYPE;
5107 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5108 *ptype |= RASTER_FONTTYPE;
5110 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5111 if (face->cached_enum_data)
5113 face->cached_enum_data->elf = *pelf;
5114 face->cached_enum_data->ntm = *pntm;
5115 face->cached_enum_data->type = *ptype;
5118 free_font(font);
5121 static void create_full_name(WCHAR *full_name, const WCHAR *family_name, const WCHAR *style_name)
5123 static const WCHAR spaceW[] = { ' ', 0 };
5125 strcpyW(full_name, family_name);
5126 strcatW(full_name, spaceW);
5127 strcatW(full_name, style_name);
5130 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5132 const struct list *face_list, *face_elem_ptr;
5134 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5136 face_list = get_face_list_from_family(family);
5137 LIST_FOR_EACH(face_elem_ptr, face_list)
5139 WCHAR full_family_name[LF_FULLFACESIZE];
5140 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
5142 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
5144 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
5145 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
5146 continue;
5149 create_full_name(full_family_name, family->FamilyName, face->StyleName);
5150 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
5153 return FALSE;
5156 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5158 WCHAR full_family_name[LF_FULLFACESIZE];
5160 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5162 if (strlenW(family_name) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
5164 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
5165 debugstr_w(family_name), debugstr_w(face->StyleName));
5166 return FALSE;
5169 create_full_name(full_family_name, family_name, face->StyleName);
5170 return !strcmpiW(lf->lfFaceName, full_family_name);
5173 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5174 FONTENUMPROCW proc, LPARAM lparam)
5176 ENUMLOGFONTEXW elf;
5177 NEWTEXTMETRICEXW ntm;
5178 DWORD type = 0;
5179 int i;
5181 GetEnumStructs(face, &elf, &ntm, &type);
5182 for(i = 0; i < list->total; i++) {
5183 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5184 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5185 load_script_name( IDS_OEM_DOS, elf.elfScript );
5186 i = list->total; /* break out of loop after enumeration */
5187 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
5188 continue;
5189 else {
5190 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5191 strcpyW(elf.elfScript, list->element[i].name);
5192 if (!elf.elfScript[0])
5193 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5195 /* Font Replacement */
5196 if (family != face->family)
5198 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5199 create_full_name(elf.elfFullName, family->FamilyName, face->StyleName);
5201 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5202 debugstr_w(elf.elfLogFont.lfFaceName),
5203 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5204 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5205 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5206 ntm.ntmTm.ntmFlags);
5207 /* release section before callback (FIXME) */
5208 LeaveCriticalSection( &freetype_cs );
5209 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5210 EnterCriticalSection( &freetype_cs );
5212 return TRUE;
5215 /*************************************************************
5216 * freetype_EnumFonts
5218 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5220 Family *family;
5221 Face *face;
5222 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
5223 LOGFONTW lf;
5224 struct enum_charset_list enum_charsets;
5226 if (!plf)
5228 lf.lfCharSet = DEFAULT_CHARSET;
5229 lf.lfPitchAndFamily = 0;
5230 lf.lfFaceName[0] = 0;
5231 plf = &lf;
5234 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5236 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5238 GDI_CheckNotLock();
5239 EnterCriticalSection( &freetype_cs );
5240 if(plf->lfFaceName[0]) {
5241 FontSubst *psub;
5242 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5244 if(psub) {
5245 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5246 debugstr_w(psub->to.name));
5247 lf = *plf;
5248 strcpyW(lf.lfFaceName, psub->to.name);
5249 plf = &lf;
5252 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5253 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5254 if(family_matches(family, plf)) {
5255 face_list = get_face_list_from_family(family);
5256 LIST_FOR_EACH(face_elem_ptr, face_list) {
5257 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5258 if (!face_matches(family->FamilyName, face, plf)) continue;
5259 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5263 } else {
5264 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5265 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5266 face_list = get_face_list_from_family(family);
5267 face_elem_ptr = list_head(face_list);
5268 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5269 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5272 LeaveCriticalSection( &freetype_cs );
5273 return TRUE;
5276 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5278 pt->x.value = vec->x >> 6;
5279 pt->x.fract = (vec->x & 0x3f) << 10;
5280 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5281 pt->y.value = vec->y >> 6;
5282 pt->y.fract = (vec->y & 0x3f) << 10;
5283 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5284 return;
5287 /***************************************************
5288 * According to the MSDN documentation on WideCharToMultiByte,
5289 * certain codepages cannot set the default_used parameter.
5290 * This returns TRUE if the codepage can set that parameter, false else
5291 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5293 static BOOL codepage_sets_default_used(UINT codepage)
5295 switch (codepage)
5297 case CP_UTF7:
5298 case CP_UTF8:
5299 case CP_SYMBOL:
5300 return FALSE;
5301 default:
5302 return TRUE;
5307 * GSUB Table handling functions
5310 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5312 const GSUB_CoverageFormat1* cf1;
5314 cf1 = table;
5316 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5318 int count = GET_BE_WORD(cf1->GlyphCount);
5319 int i;
5320 TRACE("Coverage Format 1, %i glyphs\n",count);
5321 for (i = 0; i < count; i++)
5322 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5323 return i;
5324 return -1;
5326 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5328 const GSUB_CoverageFormat2* cf2;
5329 int i;
5330 int count;
5331 cf2 = (const GSUB_CoverageFormat2*)cf1;
5333 count = GET_BE_WORD(cf2->RangeCount);
5334 TRACE("Coverage Format 2, %i ranges\n",count);
5335 for (i = 0; i < count; i++)
5337 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5338 return -1;
5339 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5340 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5342 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5343 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5346 return -1;
5348 else
5349 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5351 return -1;
5354 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5356 const GSUB_ScriptList *script;
5357 const GSUB_Script *deflt = NULL;
5358 int i;
5359 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5361 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5362 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5364 const GSUB_Script *scr;
5365 int offset;
5367 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5368 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5370 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5371 return scr;
5372 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5373 deflt = scr;
5375 return deflt;
5378 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5380 int i;
5381 int offset;
5382 const GSUB_LangSys *Lang;
5384 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5386 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5388 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5389 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5391 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5392 return Lang;
5394 offset = GET_BE_WORD(script->DefaultLangSys);
5395 if (offset)
5397 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5398 return Lang;
5400 return NULL;
5403 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5405 int i;
5406 const GSUB_FeatureList *feature;
5407 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5409 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5410 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5412 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5413 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5415 const GSUB_Feature *feat;
5416 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5417 return feat;
5420 return NULL;
5423 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5425 int i;
5426 int offset;
5427 const GSUB_LookupList *lookup;
5428 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5430 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5431 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5433 const GSUB_LookupTable *look;
5434 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5435 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5436 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5437 if (GET_BE_WORD(look->LookupType) != 1)
5438 FIXME("We only handle SubType 1\n");
5439 else
5441 int j;
5443 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5445 const GSUB_SingleSubstFormat1 *ssf1;
5446 offset = GET_BE_WORD(look->SubTable[j]);
5447 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5448 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5450 int offset = GET_BE_WORD(ssf1->Coverage);
5451 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5452 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5454 TRACE(" Glyph 0x%x ->",glyph);
5455 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5456 TRACE(" 0x%x\n",glyph);
5459 else
5461 const GSUB_SingleSubstFormat2 *ssf2;
5462 INT index;
5463 INT offset;
5465 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5466 offset = GET_BE_WORD(ssf1->Coverage);
5467 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5468 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5469 TRACE(" Coverage index %i\n",index);
5470 if (index != -1)
5472 TRACE(" Glyph is 0x%x ->",glyph);
5473 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5474 TRACE("0x%x\n",glyph);
5480 return glyph;
5483 static const char* get_opentype_script(const GdiFont *font)
5486 * I am not sure if this is the correct way to generate our script tag
5489 switch (font->charset)
5491 case ANSI_CHARSET: return "latn";
5492 case BALTIC_CHARSET: return "latn"; /* ?? */
5493 case CHINESEBIG5_CHARSET: return "hani";
5494 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5495 case GB2312_CHARSET: return "hani";
5496 case GREEK_CHARSET: return "grek";
5497 case HANGUL_CHARSET: return "hang";
5498 case RUSSIAN_CHARSET: return "cyrl";
5499 case SHIFTJIS_CHARSET: return "kana";
5500 case TURKISH_CHARSET: return "latn"; /* ?? */
5501 case VIETNAMESE_CHARSET: return "latn";
5502 case JOHAB_CHARSET: return "latn"; /* ?? */
5503 case ARABIC_CHARSET: return "arab";
5504 case HEBREW_CHARSET: return "hebr";
5505 case THAI_CHARSET: return "thai";
5506 default: return "latn";
5510 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5512 const GSUB_Header *header;
5513 const GSUB_Script *script;
5514 const GSUB_LangSys *language;
5515 const GSUB_Feature *feature;
5517 if (!font->GSUB_Table)
5518 return glyph;
5520 header = font->GSUB_Table;
5522 script = GSUB_get_script_table(header, get_opentype_script(font));
5523 if (!script)
5525 TRACE("Script not found\n");
5526 return glyph;
5528 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5529 if (!language)
5531 TRACE("Language not found\n");
5532 return glyph;
5534 feature = GSUB_get_feature(header, language, "vrt2");
5535 if (!feature)
5536 feature = GSUB_get_feature(header, language, "vert");
5537 if (!feature)
5539 TRACE("vrt2/vert feature not found\n");
5540 return glyph;
5542 return GSUB_apply_feature(header, feature, glyph);
5545 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5547 FT_UInt glyphId;
5549 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5550 WCHAR wc = (WCHAR)glyph;
5551 BOOL default_used;
5552 BOOL *default_used_pointer;
5553 FT_UInt ret;
5554 char buf;
5555 default_used_pointer = NULL;
5556 default_used = FALSE;
5557 if (codepage_sets_default_used(font->codepage))
5558 default_used_pointer = &default_used;
5559 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5560 ret = 0;
5561 else
5562 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5563 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5564 return ret;
5567 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5569 if (glyph < 0x100) glyph += 0xf000;
5570 /* there is a number of old pre-Unicode "broken" TTFs, which
5571 do have symbols at U+00XX instead of U+f0XX */
5572 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5573 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5575 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5577 return glyphId;
5580 /*************************************************************
5581 * freetype_GetGlyphIndices
5583 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5585 struct freetype_physdev *physdev = get_freetype_dev( dev );
5586 int i;
5587 WORD default_char;
5588 BOOL got_default = FALSE;
5590 if (!physdev->font)
5592 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5593 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5596 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5598 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5599 got_default = TRUE;
5602 GDI_CheckNotLock();
5603 EnterCriticalSection( &freetype_cs );
5605 for(i = 0; i < count; i++)
5607 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5608 if (pgi[i] == 0)
5610 if (!got_default)
5612 if (FT_IS_SFNT(physdev->font->ft_face))
5614 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5615 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5617 else
5619 TEXTMETRICW textm;
5620 get_text_metrics(physdev->font, &textm);
5621 default_char = textm.tmDefaultChar;
5623 got_default = TRUE;
5625 pgi[i] = default_char;
5628 LeaveCriticalSection( &freetype_cs );
5629 return count;
5632 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5634 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5635 return !memcmp(matrix, &identity, sizeof(FMAT2));
5638 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5640 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5641 return !memcmp(matrix, &identity, sizeof(MAT2));
5644 static inline BYTE get_max_level( UINT format )
5646 switch( format )
5648 case GGO_GRAY2_BITMAP: return 4;
5649 case GGO_GRAY4_BITMAP: return 16;
5650 case GGO_GRAY8_BITMAP: return 64;
5652 return 255;
5655 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5657 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5658 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5659 const MAT2* lpmat)
5661 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5662 FT_Face ft_face = incoming_font->ft_face;
5663 GdiFont *font = incoming_font;
5664 FT_UInt glyph_index;
5665 DWORD width, height, pitch, needed = 0;
5666 FT_Bitmap ft_bitmap;
5667 FT_Error err;
5668 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5669 FT_Angle angle = 0;
5670 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5671 double widthRatio = 1.0;
5672 FT_Matrix transMat = identityMat;
5673 FT_Matrix transMatUnrotated;
5674 BOOL needsTransform = FALSE;
5675 BOOL tategaki = (font->GSUB_Table != NULL);
5676 UINT original_index;
5678 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5679 buflen, buf, lpmat);
5681 TRACE("font transform %f %f %f %f\n",
5682 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5683 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5685 if(format & GGO_GLYPH_INDEX) {
5686 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5687 original_index = glyph;
5688 format &= ~GGO_GLYPH_INDEX;
5689 } else {
5690 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5691 ft_face = font->ft_face;
5692 original_index = glyph_index;
5695 if(format & GGO_UNHINTED) {
5696 load_flags |= FT_LOAD_NO_HINTING;
5697 format &= ~GGO_UNHINTED;
5700 /* tategaki never appears to happen to lower glyph index */
5701 if (glyph_index < TATEGAKI_LOWER_BOUND )
5702 tategaki = FALSE;
5704 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5705 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5706 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5707 font->gmsize * sizeof(GM*));
5708 } else {
5709 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5710 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5712 *lpgm = FONT_GM(font,original_index)->gm;
5713 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5714 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5715 lpgm->gmCellIncX, lpgm->gmCellIncY);
5716 return 1; /* FIXME */
5720 if (!font->gm[original_index / GM_BLOCK_SIZE])
5721 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5723 /* Scaling factor */
5724 if (font->aveWidth)
5726 TEXTMETRICW tm;
5728 get_text_metrics(font, &tm);
5730 widthRatio = (double)font->aveWidth;
5731 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5733 else
5734 widthRatio = font->scale_y;
5736 /* Scaling transform */
5737 if (widthRatio != 1.0 || font->scale_y != 1.0)
5739 FT_Matrix scaleMat;
5740 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5741 scaleMat.xy = 0;
5742 scaleMat.yx = 0;
5743 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5745 pFT_Matrix_Multiply(&scaleMat, &transMat);
5746 needsTransform = TRUE;
5749 /* Slant transform */
5750 if (font->fake_italic) {
5751 FT_Matrix slantMat;
5753 slantMat.xx = (1 << 16);
5754 slantMat.xy = ((1 << 16) >> 2);
5755 slantMat.yx = 0;
5756 slantMat.yy = (1 << 16);
5757 pFT_Matrix_Multiply(&slantMat, &transMat);
5758 needsTransform = TRUE;
5761 /* Rotation transform */
5762 transMatUnrotated = transMat;
5763 if(font->orientation && !tategaki) {
5764 FT_Matrix rotationMat;
5765 FT_Vector vecAngle;
5766 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5767 pFT_Vector_Unit(&vecAngle, angle);
5768 rotationMat.xx = vecAngle.x;
5769 rotationMat.xy = -vecAngle.y;
5770 rotationMat.yx = -rotationMat.xy;
5771 rotationMat.yy = rotationMat.xx;
5773 pFT_Matrix_Multiply(&rotationMat, &transMat);
5774 needsTransform = TRUE;
5777 /* World transform */
5778 if (!is_identity_FMAT2(&font->font_desc.matrix))
5780 FT_Matrix worldMat;
5781 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5782 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5783 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5784 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5785 pFT_Matrix_Multiply(&worldMat, &transMat);
5786 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5787 needsTransform = TRUE;
5790 /* Extra transformation specified by caller */
5791 if (!is_identity_MAT2(lpmat))
5793 FT_Matrix extraMat;
5794 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5795 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5796 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5797 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5798 pFT_Matrix_Multiply(&extraMat, &transMat);
5799 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5800 needsTransform = TRUE;
5803 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5804 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5805 format == GGO_GRAY8_BITMAP))
5807 load_flags |= FT_LOAD_NO_BITMAP;
5810 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5812 if(err) {
5813 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5814 return GDI_ERROR;
5817 if(!needsTransform) {
5818 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5819 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5820 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5822 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5823 bottom = (ft_face->glyph->metrics.horiBearingY -
5824 ft_face->glyph->metrics.height) & -64;
5825 lpgm->gmCellIncX = adv;
5826 lpgm->gmCellIncY = 0;
5827 } else {
5828 INT xc, yc;
5829 FT_Vector vec;
5831 left = right = 0;
5833 for(xc = 0; xc < 2; xc++) {
5834 for(yc = 0; yc < 2; yc++) {
5835 vec.x = (ft_face->glyph->metrics.horiBearingX +
5836 xc * ft_face->glyph->metrics.width);
5837 vec.y = ft_face->glyph->metrics.horiBearingY -
5838 yc * ft_face->glyph->metrics.height;
5839 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5840 pFT_Vector_Transform(&vec, &transMat);
5841 if(xc == 0 && yc == 0) {
5842 left = right = vec.x;
5843 top = bottom = vec.y;
5844 } else {
5845 if(vec.x < left) left = vec.x;
5846 else if(vec.x > right) right = vec.x;
5847 if(vec.y < bottom) bottom = vec.y;
5848 else if(vec.y > top) top = vec.y;
5852 left = left & -64;
5853 right = (right + 63) & -64;
5854 bottom = bottom & -64;
5855 top = (top + 63) & -64;
5857 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5858 vec.x = ft_face->glyph->metrics.horiAdvance;
5859 vec.y = 0;
5860 pFT_Vector_Transform(&vec, &transMat);
5861 lpgm->gmCellIncX = (vec.x+63) >> 6;
5862 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5864 vec.x = ft_face->glyph->metrics.horiAdvance;
5865 vec.y = 0;
5866 pFT_Vector_Transform(&vec, &transMatUnrotated);
5867 adv = (vec.x+63) >> 6;
5870 lsb = left >> 6;
5871 bbx = (right - left) >> 6;
5872 lpgm->gmBlackBoxX = (right - left) >> 6;
5873 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5874 lpgm->gmptGlyphOrigin.x = left >> 6;
5875 lpgm->gmptGlyphOrigin.y = top >> 6;
5877 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5878 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5879 lpgm->gmCellIncX, lpgm->gmCellIncY);
5881 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5882 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5884 FONT_GM(font,original_index)->gm = *lpgm;
5885 FONT_GM(font,original_index)->adv = adv;
5886 FONT_GM(font,original_index)->lsb = lsb;
5887 FONT_GM(font,original_index)->bbx = bbx;
5888 FONT_GM(font,original_index)->init = TRUE;
5891 if(format == GGO_METRICS)
5893 return 1; /* FIXME */
5896 if(ft_face->glyph->format != ft_glyph_format_outline &&
5897 (format == GGO_NATIVE || format == GGO_BEZIER))
5899 TRACE("loaded a bitmap\n");
5900 return GDI_ERROR;
5903 switch(format) {
5904 case GGO_BITMAP:
5905 width = lpgm->gmBlackBoxX;
5906 height = lpgm->gmBlackBoxY;
5907 pitch = ((width + 31) >> 5) << 2;
5908 needed = pitch * height;
5910 if(!buf || !buflen) break;
5912 switch(ft_face->glyph->format) {
5913 case ft_glyph_format_bitmap:
5915 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5916 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5917 INT h = ft_face->glyph->bitmap.rows;
5918 while(h--) {
5919 memcpy(dst, src, w);
5920 src += ft_face->glyph->bitmap.pitch;
5921 dst += pitch;
5923 break;
5926 case ft_glyph_format_outline:
5927 ft_bitmap.width = width;
5928 ft_bitmap.rows = height;
5929 ft_bitmap.pitch = pitch;
5930 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5931 ft_bitmap.buffer = buf;
5933 if(needsTransform)
5934 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5936 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5938 /* Note: FreeType will only set 'black' bits for us. */
5939 memset(buf, 0, needed);
5940 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5941 break;
5943 default:
5944 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5945 return GDI_ERROR;
5947 break;
5949 case GGO_GRAY2_BITMAP:
5950 case GGO_GRAY4_BITMAP:
5951 case GGO_GRAY8_BITMAP:
5952 case WINE_GGO_GRAY16_BITMAP:
5954 unsigned int max_level, row, col;
5955 BYTE *start, *ptr;
5957 width = lpgm->gmBlackBoxX;
5958 height = lpgm->gmBlackBoxY;
5959 pitch = (width + 3) / 4 * 4;
5960 needed = pitch * height;
5962 if(!buf || !buflen) break;
5964 max_level = get_max_level( format );
5966 switch(ft_face->glyph->format) {
5967 case ft_glyph_format_bitmap:
5969 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5970 INT h = ft_face->glyph->bitmap.rows;
5971 INT x;
5972 memset( buf, 0, needed );
5973 while(h--) {
5974 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5975 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5976 src += ft_face->glyph->bitmap.pitch;
5977 dst += pitch;
5979 return needed;
5981 case ft_glyph_format_outline:
5983 ft_bitmap.width = width;
5984 ft_bitmap.rows = height;
5985 ft_bitmap.pitch = pitch;
5986 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5987 ft_bitmap.buffer = buf;
5989 if(needsTransform)
5990 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5992 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5994 memset(ft_bitmap.buffer, 0, buflen);
5996 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5998 if (max_level != 255)
6000 for (row = 0, start = buf; row < height; row++)
6002 for (col = 0, ptr = start; col < width; col++, ptr++)
6003 *ptr = (((int)*ptr) * max_level + 128) / 256;
6004 start += pitch;
6007 return needed;
6010 default:
6011 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6012 return GDI_ERROR;
6014 break;
6017 case WINE_GGO_HRGB_BITMAP:
6018 case WINE_GGO_HBGR_BITMAP:
6019 case WINE_GGO_VRGB_BITMAP:
6020 case WINE_GGO_VBGR_BITMAP:
6021 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6023 switch (ft_face->glyph->format)
6025 case FT_GLYPH_FORMAT_BITMAP:
6027 BYTE *src, *dst;
6028 INT src_pitch, x;
6030 width = lpgm->gmBlackBoxX;
6031 height = lpgm->gmBlackBoxY;
6032 pitch = width * 4;
6033 needed = pitch * height;
6035 if (!buf || !buflen) break;
6037 memset(buf, 0, buflen);
6038 dst = buf;
6039 src = ft_face->glyph->bitmap.buffer;
6040 src_pitch = ft_face->glyph->bitmap.pitch;
6042 height = min( height, ft_face->glyph->bitmap.rows );
6043 while ( height-- )
6045 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6047 if ( src[x / 8] & masks[x % 8] )
6048 ((unsigned int *)dst)[x] = ~0u;
6050 src += src_pitch;
6051 dst += pitch;
6054 break;
6057 case FT_GLYPH_FORMAT_OUTLINE:
6059 unsigned int *dst;
6060 BYTE *src;
6061 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6062 INT x_shift, y_shift;
6063 BOOL rgb;
6064 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6065 FT_Render_Mode render_mode =
6066 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6067 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6069 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6071 if ( render_mode == FT_RENDER_MODE_LCD)
6073 lpgm->gmBlackBoxX += 2;
6074 lpgm->gmptGlyphOrigin.x -= 1;
6076 else
6078 lpgm->gmBlackBoxY += 2;
6079 lpgm->gmptGlyphOrigin.y += 1;
6083 width = lpgm->gmBlackBoxX;
6084 height = lpgm->gmBlackBoxY;
6085 pitch = width * 4;
6086 needed = pitch * height;
6088 if (!buf || !buflen) break;
6090 memset(buf, 0, buflen);
6091 dst = buf;
6092 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6094 if ( needsTransform )
6095 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
6097 if ( pFT_Library_SetLcdFilter )
6098 pFT_Library_SetLcdFilter( library, lcdfilter );
6099 pFT_Render_Glyph (ft_face->glyph, render_mode);
6101 src = ft_face->glyph->bitmap.buffer;
6102 src_pitch = ft_face->glyph->bitmap.pitch;
6103 src_width = ft_face->glyph->bitmap.width;
6104 src_height = ft_face->glyph->bitmap.rows;
6106 if ( render_mode == FT_RENDER_MODE_LCD)
6108 rgb_interval = 1;
6109 hmul = 3;
6110 vmul = 1;
6112 else
6114 rgb_interval = src_pitch;
6115 hmul = 1;
6116 vmul = 3;
6119 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6120 if ( x_shift < 0 ) x_shift = 0;
6121 if ( x_shift + (src_width / hmul) > width )
6122 x_shift = width - (src_width / hmul);
6124 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6125 if ( y_shift < 0 ) y_shift = 0;
6126 if ( y_shift + (src_height / vmul) > height )
6127 y_shift = height - (src_height / vmul);
6129 dst += x_shift + y_shift * ( pitch / 4 );
6130 while ( src_height )
6132 for ( x = 0; x < src_width / hmul; x++ )
6134 if ( rgb )
6136 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6137 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6138 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6139 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6141 else
6143 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6144 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6145 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6146 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6149 src += src_pitch * vmul;
6150 dst += pitch / 4;
6151 src_height -= vmul;
6154 break;
6157 default:
6158 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6159 return GDI_ERROR;
6162 break;
6164 #else
6165 return GDI_ERROR;
6166 #endif
6168 case GGO_NATIVE:
6170 int contour, point = 0, first_pt;
6171 FT_Outline *outline = &ft_face->glyph->outline;
6172 TTPOLYGONHEADER *pph;
6173 TTPOLYCURVE *ppc;
6174 DWORD pph_start, cpfx, type;
6176 if(buflen == 0) buf = NULL;
6178 if (needsTransform && buf) {
6179 pFT_Outline_Transform(outline, &transMat);
6182 for(contour = 0; contour < outline->n_contours; contour++) {
6183 pph_start = needed;
6184 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6185 first_pt = point;
6186 if(buf) {
6187 pph->dwType = TT_POLYGON_TYPE;
6188 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6190 needed += sizeof(*pph);
6191 point++;
6192 while(point <= outline->contours[contour]) {
6193 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6194 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6195 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6196 cpfx = 0;
6197 do {
6198 if(buf)
6199 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6200 cpfx++;
6201 point++;
6202 } while(point <= outline->contours[contour] &&
6203 (outline->tags[point] & FT_Curve_Tag_On) ==
6204 (outline->tags[point-1] & FT_Curve_Tag_On));
6205 /* At the end of a contour Windows adds the start point, but
6206 only for Beziers */
6207 if(point > outline->contours[contour] &&
6208 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6209 if(buf)
6210 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6211 cpfx++;
6212 } else if(point <= outline->contours[contour] &&
6213 outline->tags[point] & FT_Curve_Tag_On) {
6214 /* add closing pt for bezier */
6215 if(buf)
6216 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6217 cpfx++;
6218 point++;
6220 if(buf) {
6221 ppc->wType = type;
6222 ppc->cpfx = cpfx;
6224 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6226 if(buf)
6227 pph->cb = needed - pph_start;
6229 break;
6231 case GGO_BEZIER:
6233 /* Convert the quadratic Beziers to cubic Beziers.
6234 The parametric eqn for a cubic Bezier is, from PLRM:
6235 r(t) = at^3 + bt^2 + ct + r0
6236 with the control points:
6237 r1 = r0 + c/3
6238 r2 = r1 + (c + b)/3
6239 r3 = r0 + c + b + a
6241 A quadratic Bezier has the form:
6242 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6244 So equating powers of t leads to:
6245 r1 = 2/3 p1 + 1/3 p0
6246 r2 = 2/3 p1 + 1/3 p2
6247 and of course r0 = p0, r3 = p2
6250 int contour, point = 0, first_pt;
6251 FT_Outline *outline = &ft_face->glyph->outline;
6252 TTPOLYGONHEADER *pph;
6253 TTPOLYCURVE *ppc;
6254 DWORD pph_start, cpfx, type;
6255 FT_Vector cubic_control[4];
6256 if(buflen == 0) buf = NULL;
6258 if (needsTransform && buf) {
6259 pFT_Outline_Transform(outline, &transMat);
6262 for(contour = 0; contour < outline->n_contours; contour++) {
6263 pph_start = needed;
6264 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6265 first_pt = point;
6266 if(buf) {
6267 pph->dwType = TT_POLYGON_TYPE;
6268 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6270 needed += sizeof(*pph);
6271 point++;
6272 while(point <= outline->contours[contour]) {
6273 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6274 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6275 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6276 cpfx = 0;
6277 do {
6278 if(type == TT_PRIM_LINE) {
6279 if(buf)
6280 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6281 cpfx++;
6282 point++;
6283 } else {
6284 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6285 so cpfx = 3n */
6287 /* FIXME: Possible optimization in endpoint calculation
6288 if there are two consecutive curves */
6289 cubic_control[0] = outline->points[point-1];
6290 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6291 cubic_control[0].x += outline->points[point].x + 1;
6292 cubic_control[0].y += outline->points[point].y + 1;
6293 cubic_control[0].x >>= 1;
6294 cubic_control[0].y >>= 1;
6296 if(point+1 > outline->contours[contour])
6297 cubic_control[3] = outline->points[first_pt];
6298 else {
6299 cubic_control[3] = outline->points[point+1];
6300 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6301 cubic_control[3].x += outline->points[point].x + 1;
6302 cubic_control[3].y += outline->points[point].y + 1;
6303 cubic_control[3].x >>= 1;
6304 cubic_control[3].y >>= 1;
6307 /* r1 = 1/3 p0 + 2/3 p1
6308 r2 = 1/3 p2 + 2/3 p1 */
6309 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6310 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6311 cubic_control[2] = cubic_control[1];
6312 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6313 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6314 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6315 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6316 if(buf) {
6317 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6318 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6319 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6321 cpfx += 3;
6322 point++;
6324 } while(point <= outline->contours[contour] &&
6325 (outline->tags[point] & FT_Curve_Tag_On) ==
6326 (outline->tags[point-1] & FT_Curve_Tag_On));
6327 /* At the end of a contour Windows adds the start point,
6328 but only for Beziers and we've already done that.
6330 if(point <= outline->contours[contour] &&
6331 outline->tags[point] & FT_Curve_Tag_On) {
6332 /* This is the closing pt of a bezier, but we've already
6333 added it, so just inc point and carry on */
6334 point++;
6336 if(buf) {
6337 ppc->wType = type;
6338 ppc->cpfx = cpfx;
6340 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6342 if(buf)
6343 pph->cb = needed - pph_start;
6345 break;
6348 default:
6349 FIXME("Unsupported format %d\n", format);
6350 return GDI_ERROR;
6352 return needed;
6355 static BOOL get_bitmap_text_metrics(GdiFont *font)
6357 FT_Face ft_face = font->ft_face;
6358 FT_WinFNT_HeaderRec winfnt_header;
6359 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6360 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6361 font->potm->otmSize = size;
6363 #define TM font->potm->otmTextMetrics
6364 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6366 TM.tmHeight = winfnt_header.pixel_height;
6367 TM.tmAscent = winfnt_header.ascent;
6368 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6369 TM.tmInternalLeading = winfnt_header.internal_leading;
6370 TM.tmExternalLeading = winfnt_header.external_leading;
6371 TM.tmAveCharWidth = winfnt_header.avg_width;
6372 TM.tmMaxCharWidth = winfnt_header.max_width;
6373 TM.tmWeight = winfnt_header.weight;
6374 TM.tmOverhang = 0;
6375 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6376 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6377 TM.tmFirstChar = winfnt_header.first_char;
6378 TM.tmLastChar = winfnt_header.last_char;
6379 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6380 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6381 TM.tmItalic = winfnt_header.italic;
6382 TM.tmUnderlined = font->underline;
6383 TM.tmStruckOut = font->strikeout;
6384 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6385 TM.tmCharSet = winfnt_header.charset;
6387 else
6389 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6390 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6391 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6392 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6393 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6394 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6395 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6396 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6397 TM.tmOverhang = 0;
6398 TM.tmDigitizedAspectX = 96; /* FIXME */
6399 TM.tmDigitizedAspectY = 96; /* FIXME */
6400 TM.tmFirstChar = 1;
6401 TM.tmLastChar = 255;
6402 TM.tmDefaultChar = 32;
6403 TM.tmBreakChar = 32;
6404 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6405 TM.tmUnderlined = font->underline;
6406 TM.tmStruckOut = font->strikeout;
6407 /* NB inverted meaning of TMPF_FIXED_PITCH */
6408 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6409 TM.tmCharSet = font->charset;
6411 #undef TM
6413 return TRUE;
6417 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6419 double scale_x, scale_y;
6421 if (font->aveWidth)
6423 scale_x = (double)font->aveWidth;
6424 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6426 else
6427 scale_x = font->scale_y;
6429 scale_x *= fabs(font->font_desc.matrix.eM11);
6430 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6432 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6433 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6435 SCALE_Y(ptm->tmHeight);
6436 SCALE_Y(ptm->tmAscent);
6437 SCALE_Y(ptm->tmDescent);
6438 SCALE_Y(ptm->tmInternalLeading);
6439 SCALE_Y(ptm->tmExternalLeading);
6440 SCALE_Y(ptm->tmOverhang);
6442 SCALE_X(ptm->tmAveCharWidth);
6443 SCALE_X(ptm->tmMaxCharWidth);
6445 #undef SCALE_X
6446 #undef SCALE_Y
6449 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6451 double scale_x, scale_y;
6453 if (font->aveWidth)
6455 scale_x = (double)font->aveWidth;
6456 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6458 else
6459 scale_x = font->scale_y;
6461 scale_x *= fabs(font->font_desc.matrix.eM11);
6462 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6464 scale_font_metrics(font, &potm->otmTextMetrics);
6466 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6467 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6469 SCALE_Y(potm->otmAscent);
6470 SCALE_Y(potm->otmDescent);
6471 SCALE_Y(potm->otmLineGap);
6472 SCALE_Y(potm->otmsCapEmHeight);
6473 SCALE_Y(potm->otmsXHeight);
6474 SCALE_Y(potm->otmrcFontBox.top);
6475 SCALE_Y(potm->otmrcFontBox.bottom);
6476 SCALE_X(potm->otmrcFontBox.left);
6477 SCALE_X(potm->otmrcFontBox.right);
6478 SCALE_Y(potm->otmMacAscent);
6479 SCALE_Y(potm->otmMacDescent);
6480 SCALE_Y(potm->otmMacLineGap);
6481 SCALE_X(potm->otmptSubscriptSize.x);
6482 SCALE_Y(potm->otmptSubscriptSize.y);
6483 SCALE_X(potm->otmptSubscriptOffset.x);
6484 SCALE_Y(potm->otmptSubscriptOffset.y);
6485 SCALE_X(potm->otmptSuperscriptSize.x);
6486 SCALE_Y(potm->otmptSuperscriptSize.y);
6487 SCALE_X(potm->otmptSuperscriptOffset.x);
6488 SCALE_Y(potm->otmptSuperscriptOffset.y);
6489 SCALE_Y(potm->otmsStrikeoutSize);
6490 SCALE_Y(potm->otmsStrikeoutPosition);
6491 SCALE_Y(potm->otmsUnderscoreSize);
6492 SCALE_Y(potm->otmsUnderscorePosition);
6494 #undef SCALE_X
6495 #undef SCALE_Y
6498 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6500 if(!font->potm)
6502 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6504 /* Make sure that the font has sane width/height ratio */
6505 if (font->aveWidth)
6507 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6509 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6510 font->aveWidth = 0;
6514 *ptm = font->potm->otmTextMetrics;
6515 scale_font_metrics(font, ptm);
6516 return TRUE;
6519 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6521 int i;
6523 for(i = 0; i < ft_face->num_charmaps; i++)
6525 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6526 return TRUE;
6528 return FALSE;
6531 static BOOL get_outline_text_metrics(GdiFont *font)
6533 BOOL ret = FALSE;
6534 FT_Face ft_face = font->ft_face;
6535 UINT needed, lenfam, lensty;
6536 TT_OS2 *pOS2;
6537 TT_HoriHeader *pHori;
6538 TT_Postscript *pPost;
6539 FT_Fixed x_scale, y_scale;
6540 WCHAR *family_nameW, *style_nameW;
6541 static const WCHAR spaceW[] = {' ', '\0'};
6542 char *cp;
6543 INT ascent, descent;
6545 TRACE("font=%p\n", font);
6547 if(!FT_IS_SCALABLE(ft_face))
6548 return FALSE;
6550 needed = sizeof(*font->potm);
6552 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6553 family_nameW = strdupW(font->name);
6555 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6556 * sizeof(WCHAR);
6557 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6558 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6559 style_nameW, lensty/sizeof(WCHAR));
6561 /* These names should be read from the TT name table */
6563 /* length of otmpFamilyName */
6564 needed += lenfam;
6566 /* length of otmpFaceName */
6567 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
6568 needed += lenfam; /* just the family name */
6569 } else {
6570 needed += lenfam + lensty; /* family + " " + style */
6573 /* length of otmpStyleName */
6574 needed += lensty;
6576 /* length of otmpFullName */
6577 needed += lenfam + lensty;
6580 x_scale = ft_face->size->metrics.x_scale;
6581 y_scale = ft_face->size->metrics.y_scale;
6583 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6584 if(!pOS2) {
6585 FIXME("Can't find OS/2 table - not TT font?\n");
6586 goto end;
6589 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6590 if(!pHori) {
6591 FIXME("Can't find HHEA table - not TT font?\n");
6592 goto end;
6595 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6597 TRACE("OS/2 winA = %d winD = %d typoA = %d typoD = %d typoLG = %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
6598 pOS2->usWinAscent, pOS2->usWinDescent,
6599 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6600 ft_face->ascender, ft_face->descender, ft_face->height,
6601 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6602 ft_face->bbox.yMax, ft_face->bbox.yMin);
6604 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6605 font->potm->otmSize = needed;
6607 #define TM font->potm->otmTextMetrics
6609 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6610 ascent = pHori->Ascender;
6611 descent = -pHori->Descender;
6612 } else {
6613 ascent = pOS2->usWinAscent;
6614 descent = pOS2->usWinDescent;
6617 if(font->yMax) {
6618 TM.tmAscent = font->yMax;
6619 TM.tmDescent = -font->yMin;
6620 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6621 } else {
6622 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6623 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6624 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6625 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6628 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6630 /* MSDN says:
6631 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6633 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6634 ((ascent + descent) -
6635 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6637 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6638 if (TM.tmAveCharWidth == 0) {
6639 TM.tmAveCharWidth = 1;
6641 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6642 TM.tmWeight = FW_REGULAR;
6643 if (font->fake_bold)
6644 TM.tmWeight = FW_BOLD;
6645 else
6647 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6649 if (pOS2->usWeightClass > FW_MEDIUM)
6650 TM.tmWeight = pOS2->usWeightClass;
6652 else if (pOS2->usWeightClass <= FW_MEDIUM)
6653 TM.tmWeight = pOS2->usWeightClass;
6655 TM.tmOverhang = 0;
6656 TM.tmDigitizedAspectX = 300;
6657 TM.tmDigitizedAspectY = 300;
6658 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6659 * symbol range to 0 - f0ff
6662 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6664 TM.tmFirstChar = 0;
6665 switch(GetACP())
6667 case 1257: /* Baltic */
6668 TM.tmLastChar = 0xf8fd;
6669 break;
6670 default:
6671 TM.tmLastChar = 0xf0ff;
6673 TM.tmBreakChar = 0x20;
6674 TM.tmDefaultChar = 0x1f;
6676 else
6678 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6679 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6681 if(pOS2->usFirstCharIndex <= 1)
6682 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6683 else if (pOS2->usFirstCharIndex > 0xff)
6684 TM.tmBreakChar = 0x20;
6685 else
6686 TM.tmBreakChar = pOS2->usFirstCharIndex;
6687 TM.tmDefaultChar = TM.tmBreakChar - 1;
6689 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6690 TM.tmUnderlined = font->underline;
6691 TM.tmStruckOut = font->strikeout;
6693 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6694 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6695 (pOS2->version == 0xFFFFU ||
6696 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6697 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6698 else
6699 TM.tmPitchAndFamily = 0;
6701 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6703 case PAN_FAMILY_SCRIPT:
6704 TM.tmPitchAndFamily |= FF_SCRIPT;
6705 break;
6707 case PAN_FAMILY_DECORATIVE:
6708 TM.tmPitchAndFamily |= FF_DECORATIVE;
6709 break;
6711 case PAN_ANY:
6712 case PAN_NO_FIT:
6713 case PAN_FAMILY_TEXT_DISPLAY:
6714 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6715 /* which is clearly not what the panose spec says. */
6716 default:
6717 if(TM.tmPitchAndFamily == 0 || /* fixed */
6718 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6719 TM.tmPitchAndFamily = FF_MODERN;
6720 else
6722 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6724 case PAN_ANY:
6725 case PAN_NO_FIT:
6726 default:
6727 TM.tmPitchAndFamily |= FF_DONTCARE;
6728 break;
6730 case PAN_SERIF_COVE:
6731 case PAN_SERIF_OBTUSE_COVE:
6732 case PAN_SERIF_SQUARE_COVE:
6733 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6734 case PAN_SERIF_SQUARE:
6735 case PAN_SERIF_THIN:
6736 case PAN_SERIF_BONE:
6737 case PAN_SERIF_EXAGGERATED:
6738 case PAN_SERIF_TRIANGLE:
6739 TM.tmPitchAndFamily |= FF_ROMAN;
6740 break;
6742 case PAN_SERIF_NORMAL_SANS:
6743 case PAN_SERIF_OBTUSE_SANS:
6744 case PAN_SERIF_PERP_SANS:
6745 case PAN_SERIF_FLARED:
6746 case PAN_SERIF_ROUNDED:
6747 TM.tmPitchAndFamily |= FF_SWISS;
6748 break;
6751 break;
6754 if(FT_IS_SCALABLE(ft_face))
6755 TM.tmPitchAndFamily |= TMPF_VECTOR;
6757 if(FT_IS_SFNT(ft_face))
6759 if (font->ntmFlags & NTM_PS_OPENTYPE)
6760 TM.tmPitchAndFamily |= TMPF_DEVICE;
6761 else
6762 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6765 TM.tmCharSet = font->charset;
6767 font->potm->otmFiller = 0;
6768 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6769 font->potm->otmfsSelection = pOS2->fsSelection;
6770 font->potm->otmfsType = pOS2->fsType;
6771 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6772 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6773 font->potm->otmItalicAngle = 0; /* POST table */
6774 font->potm->otmEMSquare = ft_face->units_per_EM;
6775 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6776 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6777 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6778 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6779 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6780 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6781 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6782 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6783 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6784 font->potm->otmMacAscent = TM.tmAscent;
6785 font->potm->otmMacDescent = -TM.tmDescent;
6786 font->potm->otmMacLineGap = font->potm->otmLineGap;
6787 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6788 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6789 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6790 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6791 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6792 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6793 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6794 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6795 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6796 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6797 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6798 if(!pPost) {
6799 font->potm->otmsUnderscoreSize = 0;
6800 font->potm->otmsUnderscorePosition = 0;
6801 } else {
6802 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6803 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6805 #undef TM
6807 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6808 cp = (char*)font->potm + sizeof(*font->potm);
6809 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6810 strcpyW((WCHAR*)cp, family_nameW);
6811 cp += lenfam;
6812 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6813 strcpyW((WCHAR*)cp, style_nameW);
6814 cp += lensty;
6815 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6816 strcpyW((WCHAR*)cp, family_nameW);
6817 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6818 strcatW((WCHAR*)cp, spaceW);
6819 strcatW((WCHAR*)cp, style_nameW);
6820 cp += lenfam + lensty;
6821 } else
6822 cp += lenfam;
6823 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6824 strcpyW((WCHAR*)cp, family_nameW);
6825 strcatW((WCHAR*)cp, spaceW);
6826 strcatW((WCHAR*)cp, style_nameW);
6827 ret = TRUE;
6829 end:
6830 HeapFree(GetProcessHeap(), 0, style_nameW);
6831 HeapFree(GetProcessHeap(), 0, family_nameW);
6832 return ret;
6835 /*************************************************************
6836 * freetype_GetGlyphOutline
6838 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6839 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6841 struct freetype_physdev *physdev = get_freetype_dev( dev );
6842 DWORD ret;
6844 if (!physdev->font)
6846 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6847 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6850 GDI_CheckNotLock();
6851 EnterCriticalSection( &freetype_cs );
6852 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6853 LeaveCriticalSection( &freetype_cs );
6854 return ret;
6857 /*************************************************************
6858 * freetype_GetTextMetrics
6860 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6862 struct freetype_physdev *physdev = get_freetype_dev( dev );
6863 BOOL ret;
6865 if (!physdev->font)
6867 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6868 return dev->funcs->pGetTextMetrics( dev, metrics );
6871 GDI_CheckNotLock();
6872 EnterCriticalSection( &freetype_cs );
6873 ret = get_text_metrics( physdev->font, metrics );
6874 LeaveCriticalSection( &freetype_cs );
6875 return ret;
6878 /*************************************************************
6879 * freetype_GetOutlineTextMetrics
6881 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6883 struct freetype_physdev *physdev = get_freetype_dev( dev );
6884 UINT ret = 0;
6886 if (!physdev->font)
6888 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6889 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6892 TRACE("font=%p\n", physdev->font);
6894 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6896 GDI_CheckNotLock();
6897 EnterCriticalSection( &freetype_cs );
6899 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6901 if(cbSize >= physdev->font->potm->otmSize)
6903 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6904 scale_outline_font_metrics(physdev->font, potm);
6906 ret = physdev->font->potm->otmSize;
6908 LeaveCriticalSection( &freetype_cs );
6909 return ret;
6912 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6914 HFONTLIST *hfontlist;
6915 child->font = alloc_font();
6916 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6917 if(!child->font->ft_face)
6919 free_font(child->font);
6920 child->font = NULL;
6921 return FALSE;
6924 child->font->font_desc = font->font_desc;
6925 child->font->ntmFlags = child->face->ntmFlags;
6926 child->font->orientation = font->orientation;
6927 child->font->scale_y = font->scale_y;
6928 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6929 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6930 child->font->name = strdupW(child->face->family->FamilyName);
6931 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6932 child->font->base_font = font;
6933 list_add_head(&child_font_list, &child->font->entry);
6934 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6935 return TRUE;
6938 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6940 FT_UInt g;
6941 CHILD_FONT *child_font;
6943 if(font->base_font)
6944 font = font->base_font;
6946 *linked_font = font;
6948 if((*glyph = get_glyph_index(font, c)))
6950 *glyph = get_GSUB_vert_glyph(font, *glyph);
6951 return TRUE;
6954 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6956 if(!child_font->font)
6957 if(!load_child_font(font, child_font))
6958 continue;
6960 if(!child_font->font->ft_face)
6961 continue;
6962 g = get_glyph_index(child_font->font, c);
6963 g = get_GSUB_vert_glyph(child_font->font, g);
6964 if(g)
6966 *glyph = g;
6967 *linked_font = child_font->font;
6968 return TRUE;
6971 return FALSE;
6974 /*************************************************************
6975 * freetype_GetCharWidth
6977 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6979 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6980 UINT c;
6981 GLYPHMETRICS gm;
6982 FT_UInt glyph_index;
6983 GdiFont *linked_font;
6984 struct freetype_physdev *physdev = get_freetype_dev( dev );
6986 if (!physdev->font)
6988 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6989 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6992 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6994 GDI_CheckNotLock();
6995 EnterCriticalSection( &freetype_cs );
6996 for(c = firstChar; c <= lastChar; c++) {
6997 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6998 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6999 &gm, 0, NULL, &identity);
7000 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
7002 LeaveCriticalSection( &freetype_cs );
7003 return TRUE;
7006 /*************************************************************
7007 * freetype_GetCharABCWidths
7009 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7011 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7012 UINT c;
7013 GLYPHMETRICS gm;
7014 FT_UInt glyph_index;
7015 GdiFont *linked_font;
7016 struct freetype_physdev *physdev = get_freetype_dev( dev );
7018 if (!physdev->font)
7020 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7021 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7024 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7026 GDI_CheckNotLock();
7027 EnterCriticalSection( &freetype_cs );
7029 for(c = firstChar; c <= lastChar; c++) {
7030 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
7031 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7032 &gm, 0, NULL, &identity);
7033 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
7034 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
7035 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
7036 FONT_GM(linked_font,glyph_index)->bbx;
7038 LeaveCriticalSection( &freetype_cs );
7039 return TRUE;
7042 /*************************************************************
7043 * freetype_GetCharABCWidthsI
7045 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7047 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7048 UINT c;
7049 GLYPHMETRICS gm;
7050 FT_UInt glyph_index;
7051 GdiFont *linked_font;
7052 struct freetype_physdev *physdev = get_freetype_dev( dev );
7054 if (!physdev->font)
7056 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7057 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7060 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7061 return FALSE;
7063 GDI_CheckNotLock();
7064 EnterCriticalSection( &freetype_cs );
7066 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
7067 if (!pgi)
7068 for(c = firstChar; c < firstChar+count; c++) {
7069 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
7070 &gm, 0, NULL, &identity);
7071 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
7072 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
7073 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
7074 - FONT_GM(linked_font,c)->bbx;
7076 else
7077 for(c = 0; c < count; c++) {
7078 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
7079 &gm, 0, NULL, &identity);
7080 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
7081 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
7082 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
7083 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
7086 LeaveCriticalSection( &freetype_cs );
7087 return TRUE;
7090 /*************************************************************
7091 * freetype_GetTextExtentExPoint
7093 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
7094 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
7096 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7097 INT idx;
7098 INT nfit = 0, ext;
7099 GLYPHMETRICS gm;
7100 TEXTMETRICW tm;
7101 FT_UInt glyph_index;
7102 GdiFont *linked_font;
7103 struct freetype_physdev *physdev = get_freetype_dev( dev );
7105 if (!physdev->font)
7107 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7108 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
7111 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
7113 GDI_CheckNotLock();
7114 EnterCriticalSection( &freetype_cs );
7116 size->cx = 0;
7117 get_text_metrics( physdev->font, &tm );
7118 size->cy = tm.tmHeight;
7120 for(idx = 0; idx < count; idx++) {
7121 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
7122 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7123 &gm, 0, NULL, &identity);
7124 size->cx += FONT_GM(linked_font,glyph_index)->adv;
7125 ext = size->cx;
7126 if (! pnfit || ext <= max_ext) {
7127 ++nfit;
7128 if (dxs)
7129 dxs[idx] = ext;
7133 if (pnfit)
7134 *pnfit = nfit;
7136 LeaveCriticalSection( &freetype_cs );
7137 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7138 return TRUE;
7141 /*************************************************************
7142 * freetype_GetTextExtentExPointI
7144 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
7145 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
7147 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7148 INT idx;
7149 INT nfit = 0, ext;
7150 GLYPHMETRICS gm;
7151 TEXTMETRICW tm;
7152 struct freetype_physdev *physdev = get_freetype_dev( dev );
7154 if (!physdev->font)
7156 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7157 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
7160 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
7162 GDI_CheckNotLock();
7163 EnterCriticalSection( &freetype_cs );
7165 size->cx = 0;
7166 get_text_metrics(physdev->font, &tm);
7167 size->cy = tm.tmHeight;
7169 for(idx = 0; idx < count; idx++) {
7170 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
7171 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
7172 ext = size->cx;
7173 if (! pnfit || ext <= max_ext) {
7174 ++nfit;
7175 if (dxs)
7176 dxs[idx] = ext;
7180 if (pnfit)
7181 *pnfit = nfit;
7183 LeaveCriticalSection( &freetype_cs );
7184 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7185 return TRUE;
7188 /*************************************************************
7189 * freetype_GetFontData
7191 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7193 struct freetype_physdev *physdev = get_freetype_dev( dev );
7195 if (!physdev->font)
7197 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7198 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7201 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7202 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7203 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7205 return get_font_data( physdev->font, table, offset, buf, cbData );
7208 /*************************************************************
7209 * freetype_GetTextFace
7211 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7213 INT n;
7214 struct freetype_physdev *physdev = get_freetype_dev( dev );
7216 if (!physdev->font)
7218 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7219 return dev->funcs->pGetTextFace( dev, count, str );
7222 n = strlenW(physdev->font->name) + 1;
7223 if (str)
7225 lstrcpynW(str, physdev->font->name, count);
7226 n = min(count, n);
7228 return n;
7231 /*************************************************************
7232 * freetype_GetTextCharsetInfo
7234 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7236 struct freetype_physdev *physdev = get_freetype_dev( dev );
7238 if (!physdev->font)
7240 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7241 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7243 if (fs) *fs = physdev->font->fs;
7244 return physdev->font->charset;
7247 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7249 GdiFont *font = dc->gdiFont, *linked_font;
7250 struct list *first_hfont;
7251 BOOL ret;
7253 GDI_CheckNotLock();
7254 EnterCriticalSection( &freetype_cs );
7255 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
7256 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
7257 if(font == linked_font)
7258 *new_hfont = dc->hFont;
7259 else
7261 first_hfont = list_head(&linked_font->hfontlist);
7262 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
7264 LeaveCriticalSection( &freetype_cs );
7265 return ret;
7268 /* Retrieve a list of supported Unicode ranges for a given font.
7269 * Can be called with NULL gs to calculate the buffer size. Returns
7270 * the number of ranges found.
7272 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7274 DWORD num_ranges = 0;
7276 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7278 FT_UInt glyph_code;
7279 FT_ULong char_code, char_code_prev;
7281 glyph_code = 0;
7282 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7284 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7285 face->num_glyphs, glyph_code, char_code);
7287 if (!glyph_code) return 0;
7289 if (gs)
7291 gs->ranges[0].wcLow = (USHORT)char_code;
7292 gs->ranges[0].cGlyphs = 0;
7293 gs->cGlyphsSupported = 0;
7296 num_ranges = 1;
7297 while (glyph_code)
7299 if (char_code < char_code_prev)
7301 ERR("expected increasing char code from FT_Get_Next_Char\n");
7302 return 0;
7304 if (char_code - char_code_prev > 1)
7306 num_ranges++;
7307 if (gs)
7309 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7310 gs->ranges[num_ranges - 1].cGlyphs = 1;
7311 gs->cGlyphsSupported++;
7314 else if (gs)
7316 gs->ranges[num_ranges - 1].cGlyphs++;
7317 gs->cGlyphsSupported++;
7319 char_code_prev = char_code;
7320 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7323 else
7324 FIXME("encoding %u not supported\n", face->charmap->encoding);
7326 return num_ranges;
7329 /*************************************************************
7330 * freetype_GetFontUnicodeRanges
7332 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7334 struct freetype_physdev *physdev = get_freetype_dev( dev );
7335 DWORD size, num_ranges;
7337 if (!physdev->font)
7339 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7340 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7343 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7344 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7345 if (glyphset)
7347 glyphset->cbThis = size;
7348 glyphset->cRanges = num_ranges;
7349 glyphset->flAccel = 0;
7351 return size;
7354 /*************************************************************
7355 * freetype_FontIsLinked
7357 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7359 struct freetype_physdev *physdev = get_freetype_dev( dev );
7360 BOOL ret;
7362 if (!physdev->font)
7364 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7365 return dev->funcs->pFontIsLinked( dev );
7368 GDI_CheckNotLock();
7369 EnterCriticalSection( &freetype_cs );
7370 ret = !list_empty(&physdev->font->child_fonts);
7371 LeaveCriticalSection( &freetype_cs );
7372 return ret;
7375 static BOOL is_hinting_enabled(void)
7377 /* Use the >= 2.2.0 function if available */
7378 if(pFT_Get_TrueType_Engine_Type)
7380 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
7381 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
7383 #ifdef FT_DRIVER_HAS_HINTER
7384 else
7386 FT_Module mod;
7388 /* otherwise if we've been compiled with < 2.2.0 headers
7389 use the internal macro */
7390 mod = pFT_Get_Module(library, "truetype");
7391 if(mod && FT_DRIVER_HAS_HINTER(mod))
7392 return TRUE;
7394 #endif
7396 return FALSE;
7399 static BOOL is_subpixel_rendering_enabled( void )
7401 #ifdef HAVE_FREETYPE_FTLCDFIL_H
7402 return pFT_Library_SetLcdFilter &&
7403 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
7404 #else
7405 return FALSE;
7406 #endif
7409 /*************************************************************************
7410 * GetRasterizerCaps (GDI32.@)
7412 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7414 static int hinting = -1;
7415 static int subpixel = -1;
7417 if(hinting == -1)
7419 hinting = is_hinting_enabled();
7420 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
7423 if ( subpixel == -1 )
7425 subpixel = is_subpixel_rendering_enabled();
7426 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
7429 lprs->nSize = sizeof(RASTERIZER_STATUS);
7430 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
7431 if ( subpixel )
7432 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
7433 lprs->nLanguageID = 0;
7434 return TRUE;
7437 /*************************************************************
7438 * freetype_GdiRealizationInfo
7440 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7442 struct freetype_physdev *physdev = get_freetype_dev( dev );
7443 realization_info_t *info = ptr;
7445 if (!physdev->font)
7447 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7448 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7451 FIXME("(%p, %p): stub!\n", physdev->font, info);
7453 info->flags = 1;
7454 if(FT_IS_SCALABLE(physdev->font->ft_face))
7455 info->flags |= 2;
7457 info->cache_num = physdev->font->cache_num;
7458 info->unknown2 = -1;
7459 return TRUE;
7462 /*************************************************************************
7463 * Kerning support for TrueType fonts
7465 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7467 struct TT_kern_table
7469 USHORT version;
7470 USHORT nTables;
7473 struct TT_kern_subtable
7475 USHORT version;
7476 USHORT length;
7477 union
7479 USHORT word;
7480 struct
7482 USHORT horizontal : 1;
7483 USHORT minimum : 1;
7484 USHORT cross_stream: 1;
7485 USHORT override : 1;
7486 USHORT reserved1 : 4;
7487 USHORT format : 8;
7488 } bits;
7489 } coverage;
7492 struct TT_format0_kern_subtable
7494 USHORT nPairs;
7495 USHORT searchRange;
7496 USHORT entrySelector;
7497 USHORT rangeShift;
7500 struct TT_kern_pair
7502 USHORT left;
7503 USHORT right;
7504 short value;
7507 static DWORD parse_format0_kern_subtable(GdiFont *font,
7508 const struct TT_format0_kern_subtable *tt_f0_ks,
7509 const USHORT *glyph_to_char,
7510 KERNINGPAIR *kern_pair, DWORD cPairs)
7512 USHORT i, nPairs;
7513 const struct TT_kern_pair *tt_kern_pair;
7515 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7517 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7519 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7520 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7521 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7523 if (!kern_pair || !cPairs)
7524 return nPairs;
7526 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7528 nPairs = min(nPairs, cPairs);
7530 for (i = 0; i < nPairs; i++)
7532 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7533 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7534 /* this algorithm appears to better match what Windows does */
7535 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7536 if (kern_pair->iKernAmount < 0)
7538 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7539 kern_pair->iKernAmount -= font->ppem;
7541 else if (kern_pair->iKernAmount > 0)
7543 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7544 kern_pair->iKernAmount += font->ppem;
7546 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7548 TRACE("left %u right %u value %d\n",
7549 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7551 kern_pair++;
7553 TRACE("copied %u entries\n", nPairs);
7554 return nPairs;
7557 /*************************************************************
7558 * freetype_GetKerningPairs
7560 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7562 DWORD length;
7563 void *buf;
7564 const struct TT_kern_table *tt_kern_table;
7565 const struct TT_kern_subtable *tt_kern_subtable;
7566 USHORT i, nTables;
7567 USHORT *glyph_to_char;
7568 GdiFont *font;
7569 struct freetype_physdev *physdev = get_freetype_dev( dev );
7571 if (!(font = physdev->font))
7573 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7574 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7577 GDI_CheckNotLock();
7578 EnterCriticalSection( &freetype_cs );
7579 if (font->total_kern_pairs != (DWORD)-1)
7581 if (cPairs && kern_pair)
7583 cPairs = min(cPairs, font->total_kern_pairs);
7584 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7586 else cPairs = font->total_kern_pairs;
7588 LeaveCriticalSection( &freetype_cs );
7589 return cPairs;
7592 font->total_kern_pairs = 0;
7594 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7596 if (length == GDI_ERROR)
7598 TRACE("no kerning data in the font\n");
7599 LeaveCriticalSection( &freetype_cs );
7600 return 0;
7603 buf = HeapAlloc(GetProcessHeap(), 0, length);
7604 if (!buf)
7606 WARN("Out of memory\n");
7607 LeaveCriticalSection( &freetype_cs );
7608 return 0;
7611 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7613 /* build a glyph index to char code map */
7614 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7615 if (!glyph_to_char)
7617 WARN("Out of memory allocating a glyph index to char code map\n");
7618 HeapFree(GetProcessHeap(), 0, buf);
7619 LeaveCriticalSection( &freetype_cs );
7620 return 0;
7623 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7625 FT_UInt glyph_code;
7626 FT_ULong char_code;
7628 glyph_code = 0;
7629 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7631 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7632 font->ft_face->num_glyphs, glyph_code, char_code);
7634 while (glyph_code)
7636 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7638 /* FIXME: This doesn't match what Windows does: it does some fancy
7639 * things with duplicate glyph index to char code mappings, while
7640 * we just avoid overriding existing entries.
7642 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7643 glyph_to_char[glyph_code] = (USHORT)char_code;
7645 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7648 else
7650 ULONG n;
7652 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7653 for (n = 0; n <= 65535; n++)
7654 glyph_to_char[n] = (USHORT)n;
7657 tt_kern_table = buf;
7658 nTables = GET_BE_WORD(tt_kern_table->nTables);
7659 TRACE("version %u, nTables %u\n",
7660 GET_BE_WORD(tt_kern_table->version), nTables);
7662 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7664 for (i = 0; i < nTables; i++)
7666 struct TT_kern_subtable tt_kern_subtable_copy;
7668 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7669 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7670 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7672 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7673 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7674 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7676 /* According to the TrueType specification this is the only format
7677 * that will be properly interpreted by Windows and OS/2
7679 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7681 DWORD new_chunk, old_total = font->total_kern_pairs;
7683 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7684 glyph_to_char, NULL, 0);
7685 font->total_kern_pairs += new_chunk;
7687 if (!font->kern_pairs)
7688 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7689 font->total_kern_pairs * sizeof(*font->kern_pairs));
7690 else
7691 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7692 font->total_kern_pairs * sizeof(*font->kern_pairs));
7694 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7695 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7697 else
7698 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7700 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7703 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7704 HeapFree(GetProcessHeap(), 0, buf);
7706 if (cPairs && kern_pair)
7708 cPairs = min(cPairs, font->total_kern_pairs);
7709 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7711 else cPairs = font->total_kern_pairs;
7713 LeaveCriticalSection( &freetype_cs );
7714 return cPairs;
7717 static const struct gdi_dc_funcs freetype_funcs =
7719 NULL, /* pAbortDoc */
7720 NULL, /* pAbortPath */
7721 NULL, /* pAlphaBlend */
7722 NULL, /* pAngleArc */
7723 NULL, /* pArc */
7724 NULL, /* pArcTo */
7725 NULL, /* pBeginPath */
7726 NULL, /* pBlendImage */
7727 NULL, /* pChoosePixelFormat */
7728 NULL, /* pChord */
7729 NULL, /* pCloseFigure */
7730 NULL, /* pCopyBitmap */
7731 NULL, /* pCreateBitmap */
7732 NULL, /* pCreateCompatibleDC */
7733 freetype_CreateDC, /* pCreateDC */
7734 NULL, /* pDeleteBitmap */
7735 freetype_DeleteDC, /* pDeleteDC */
7736 NULL, /* pDeleteObject */
7737 NULL, /* pDescribePixelFormat */
7738 NULL, /* pDeviceCapabilities */
7739 NULL, /* pEllipse */
7740 NULL, /* pEndDoc */
7741 NULL, /* pEndPage */
7742 NULL, /* pEndPath */
7743 freetype_EnumFonts, /* pEnumFonts */
7744 NULL, /* pEnumICMProfiles */
7745 NULL, /* pExcludeClipRect */
7746 NULL, /* pExtDeviceMode */
7747 NULL, /* pExtEscape */
7748 NULL, /* pExtFloodFill */
7749 NULL, /* pExtSelectClipRgn */
7750 NULL, /* pExtTextOut */
7751 NULL, /* pFillPath */
7752 NULL, /* pFillRgn */
7753 NULL, /* pFlattenPath */
7754 freetype_FontIsLinked, /* pFontIsLinked */
7755 NULL, /* pFrameRgn */
7756 NULL, /* pGdiComment */
7757 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7758 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7759 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7760 freetype_GetCharWidth, /* pGetCharWidth */
7761 NULL, /* pGetDeviceCaps */
7762 NULL, /* pGetDeviceGammaRamp */
7763 freetype_GetFontData, /* pGetFontData */
7764 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7765 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7766 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7767 NULL, /* pGetICMProfile */
7768 NULL, /* pGetImage */
7769 freetype_GetKerningPairs, /* pGetKerningPairs */
7770 NULL, /* pGetNearestColor */
7771 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7772 NULL, /* pGetPixel */
7773 NULL, /* pGetPixelFormat */
7774 NULL, /* pGetSystemPaletteEntries */
7775 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7776 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7777 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7778 freetype_GetTextFace, /* pGetTextFace */
7779 freetype_GetTextMetrics, /* pGetTextMetrics */
7780 NULL, /* pGradientFill */
7781 NULL, /* pIntersectClipRect */
7782 NULL, /* pInvertRgn */
7783 NULL, /* pLineTo */
7784 NULL, /* pModifyWorldTransform */
7785 NULL, /* pMoveTo */
7786 NULL, /* pOffsetClipRgn */
7787 NULL, /* pOffsetViewportOrg */
7788 NULL, /* pOffsetWindowOrg */
7789 NULL, /* pPaintRgn */
7790 NULL, /* pPatBlt */
7791 NULL, /* pPie */
7792 NULL, /* pPolyBezier */
7793 NULL, /* pPolyBezierTo */
7794 NULL, /* pPolyDraw */
7795 NULL, /* pPolyPolygon */
7796 NULL, /* pPolyPolyline */
7797 NULL, /* pPolygon */
7798 NULL, /* pPolyline */
7799 NULL, /* pPolylineTo */
7800 NULL, /* pPutImage */
7801 NULL, /* pRealizeDefaultPalette */
7802 NULL, /* pRealizePalette */
7803 NULL, /* pRectangle */
7804 NULL, /* pResetDC */
7805 NULL, /* pRestoreDC */
7806 NULL, /* pRoundRect */
7807 NULL, /* pSaveDC */
7808 NULL, /* pScaleViewportExt */
7809 NULL, /* pScaleWindowExt */
7810 NULL, /* pSelectBitmap */
7811 NULL, /* pSelectBrush */
7812 NULL, /* pSelectClipPath */
7813 freetype_SelectFont, /* pSelectFont */
7814 NULL, /* pSelectPalette */
7815 NULL, /* pSelectPen */
7816 NULL, /* pSetArcDirection */
7817 NULL, /* pSetBkColor */
7818 NULL, /* pSetBkMode */
7819 NULL, /* pSetDCBrushColor */
7820 NULL, /* pSetDCPenColor */
7821 NULL, /* pSetDIBColorTable */
7822 NULL, /* pSetDIBitsToDevice */
7823 NULL, /* pSetDeviceClipping */
7824 NULL, /* pSetDeviceGammaRamp */
7825 NULL, /* pSetLayout */
7826 NULL, /* pSetMapMode */
7827 NULL, /* pSetMapperFlags */
7828 NULL, /* pSetPixel */
7829 NULL, /* pSetPixelFormat */
7830 NULL, /* pSetPolyFillMode */
7831 NULL, /* pSetROP2 */
7832 NULL, /* pSetRelAbs */
7833 NULL, /* pSetStretchBltMode */
7834 NULL, /* pSetTextAlign */
7835 NULL, /* pSetTextCharacterExtra */
7836 NULL, /* pSetTextColor */
7837 NULL, /* pSetTextJustification */
7838 NULL, /* pSetViewportExt */
7839 NULL, /* pSetViewportOrg */
7840 NULL, /* pSetWindowExt */
7841 NULL, /* pSetWindowOrg */
7842 NULL, /* pSetWorldTransform */
7843 NULL, /* pStartDoc */
7844 NULL, /* pStartPage */
7845 NULL, /* pStretchBlt */
7846 NULL, /* pStretchDIBits */
7847 NULL, /* pStrokeAndFillPath */
7848 NULL, /* pStrokePath */
7849 NULL, /* pSwapBuffers */
7850 NULL, /* pUnrealizePalette */
7851 NULL, /* pWidenPath */
7852 /* OpenGL not supported */
7855 #else /* HAVE_FREETYPE */
7857 /*************************************************************************/
7859 BOOL WineEngInit(void)
7861 return FALSE;
7863 BOOL WineEngDestroyFontInstance(HFONT hfont)
7865 return FALSE;
7868 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7870 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7871 return 1;
7874 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7876 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7877 return TRUE;
7880 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7882 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7883 return NULL;
7886 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
7887 LPCWSTR font_file, LPCWSTR font_path )
7889 FIXME("stub\n");
7890 return FALSE;
7893 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7895 return FALSE;
7898 /*************************************************************************
7899 * GetRasterizerCaps (GDI32.@)
7901 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7903 lprs->nSize = sizeof(RASTERIZER_STATUS);
7904 lprs->wFlags = 0;
7905 lprs->nLanguageID = 0;
7906 return TRUE;
7909 #endif /* HAVE_FREETYPE */