gdi32: For symbol fonts check whether the char has been converted to Unicode.
[wine.git] / dlls / gdi32 / freetype.c
blobb7e24137532240253242c0a96b3b62619938a63d
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 #ifdef HAVE_FT2BUILD_H
81 #include <ft2build.h>
82 #include FT_FREETYPE_H
83 #include FT_GLYPH_H
84 #include FT_TYPES_H
85 #include FT_TRUETYPE_TABLES_H
86 #include FT_SFNT_NAMES_H
87 #include FT_TRUETYPE_IDS_H
88 #include FT_OUTLINE_H
89 #include FT_TRIGONOMETRY_H
90 #include FT_MODULE_H
91 #include FT_WINFONTS_H
92 #ifdef FT_LCD_FILTER_H
93 #include FT_LCD_FILTER_H
94 #endif
95 #endif /* HAVE_FT2BUILD_H */
97 #include "windef.h"
98 #include "winbase.h"
99 #include "winternl.h"
100 #include "winerror.h"
101 #include "winreg.h"
102 #include "wingdi.h"
103 #include "gdi_private.h"
104 #include "wine/library.h"
105 #include "wine/unicode.h"
106 #include "wine/debug.h"
107 #include "wine/list.h"
109 #include "resource.h"
111 WINE_DEFAULT_DEBUG_CHANNEL(font);
113 #ifdef HAVE_FREETYPE
115 #ifndef HAVE_FT_TRUETYPEENGINETYPE
116 typedef enum
118 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
119 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
120 FT_TRUETYPE_ENGINE_TYPE_PATENTED
121 } FT_TrueTypeEngineType;
122 #endif
124 static FT_Library library = 0;
125 typedef struct
127 FT_Int major;
128 FT_Int minor;
129 FT_Int patch;
130 } FT_Version_t;
131 static FT_Version_t FT_Version;
132 static DWORD FT_SimpleVersion;
134 static void *ft_handle = NULL;
136 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
137 MAKE_FUNCPTR(FT_Done_Face);
138 MAKE_FUNCPTR(FT_Get_Char_Index);
139 MAKE_FUNCPTR(FT_Get_First_Char);
140 MAKE_FUNCPTR(FT_Get_Next_Char);
141 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
142 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
143 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
144 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
145 MAKE_FUNCPTR(FT_Init_FreeType);
146 MAKE_FUNCPTR(FT_Library_Version);
147 MAKE_FUNCPTR(FT_Load_Glyph);
148 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
149 MAKE_FUNCPTR(FT_Matrix_Multiply);
150 #ifdef FT_MULFIX_INLINED
151 #define pFT_MulFix FT_MULFIX_INLINED
152 #else
153 MAKE_FUNCPTR(FT_MulFix);
154 #endif
155 MAKE_FUNCPTR(FT_New_Face);
156 MAKE_FUNCPTR(FT_New_Memory_Face);
157 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
158 MAKE_FUNCPTR(FT_Outline_Get_CBox);
159 MAKE_FUNCPTR(FT_Outline_Transform);
160 MAKE_FUNCPTR(FT_Outline_Translate);
161 MAKE_FUNCPTR(FT_Render_Glyph);
162 MAKE_FUNCPTR(FT_Set_Charmap);
163 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
164 MAKE_FUNCPTR(FT_Vector_Length);
165 MAKE_FUNCPTR(FT_Vector_Transform);
166 MAKE_FUNCPTR(FT_Vector_Unit);
167 static FT_Error (*pFT_Outline_Embolden)(FT_Outline *, FT_Pos);
168 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
169 #ifdef FT_LCD_FILTER_H
170 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
171 #endif
173 #ifdef SONAME_LIBFONTCONFIG
174 #include <fontconfig/fontconfig.h>
175 MAKE_FUNCPTR(FcConfigSubstitute);
176 MAKE_FUNCPTR(FcFontList);
177 MAKE_FUNCPTR(FcFontSetDestroy);
178 MAKE_FUNCPTR(FcInit);
179 MAKE_FUNCPTR(FcObjectSetAdd);
180 MAKE_FUNCPTR(FcObjectSetCreate);
181 MAKE_FUNCPTR(FcObjectSetDestroy);
182 MAKE_FUNCPTR(FcPatternCreate);
183 MAKE_FUNCPTR(FcPatternDestroy);
184 MAKE_FUNCPTR(FcPatternGetBool);
185 MAKE_FUNCPTR(FcPatternGetInteger);
186 MAKE_FUNCPTR(FcPatternGetString);
187 #endif
189 #undef MAKE_FUNCPTR
191 #ifndef FT_MAKE_TAG
192 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
193 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
194 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
195 #endif
197 #ifndef ft_encoding_none
198 #define FT_ENCODING_NONE ft_encoding_none
199 #endif
200 #ifndef ft_encoding_ms_symbol
201 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
202 #endif
203 #ifndef ft_encoding_unicode
204 #define FT_ENCODING_UNICODE ft_encoding_unicode
205 #endif
206 #ifndef ft_encoding_apple_roman
207 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
208 #endif
210 #ifdef WORDS_BIGENDIAN
211 #define GET_BE_WORD(x) (x)
212 #define GET_BE_DWORD(x) (x)
213 #else
214 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
215 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
216 #endif
218 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
219 ( ( (FT_ULong)_x4 << 24 ) | \
220 ( (FT_ULong)_x3 << 16 ) | \
221 ( (FT_ULong)_x2 << 8 ) | \
222 (FT_ULong)_x1 )
224 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
225 #define MS_GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
226 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
227 #define MS_TTCF_TAG MS_MAKE_TAG('t', 't', 'c', 'f')
228 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
230 /* 'gasp' flags */
231 #define GASP_GRIDFIT 0x01
232 #define GASP_DOGRAY 0x02
234 #ifndef WINE_FONT_DIR
235 #define WINE_FONT_DIR "fonts"
236 #endif
238 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
239 typedef struct {
240 FT_Short height;
241 FT_Short width;
242 FT_Pos size;
243 FT_Pos x_ppem;
244 FT_Pos y_ppem;
245 FT_Short internal_leading;
246 } Bitmap_Size;
248 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
249 So to let this compile on older versions of FreeType we'll define the
250 new structure here. */
251 typedef struct {
252 FT_Short height, width;
253 FT_Pos size, x_ppem, y_ppem;
254 } My_FT_Bitmap_Size;
256 struct enum_data
258 ENUMLOGFONTEXW elf;
259 NEWTEXTMETRICEXW ntm;
260 DWORD type;
263 typedef struct tagFace {
264 struct list entry;
265 unsigned int refcount;
266 WCHAR *StyleName;
267 WCHAR *FullName;
268 WCHAR *file;
269 dev_t dev;
270 ino_t ino;
271 void *font_data_ptr;
272 DWORD font_data_size;
273 FT_Long face_index;
274 FONTSIGNATURE fs;
275 DWORD ntmFlags;
276 FT_Fixed font_version;
277 BOOL scalable;
278 Bitmap_Size size; /* set if face is a bitmap */
279 DWORD flags; /* ADDFONT flags */
280 struct tagFamily *family;
281 /* Cached data for Enum */
282 struct enum_data *cached_enum_data;
283 } Face;
285 #define ADDFONT_EXTERNAL_FONT 0x01
286 #define ADDFONT_ALLOW_BITMAP 0x02
287 #define ADDFONT_ADD_TO_CACHE 0x04
288 #define ADDFONT_ADD_RESOURCE 0x08 /* added through AddFontResource */
289 #define ADDFONT_VERTICAL_FONT 0x10
290 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
292 typedef struct tagFamily {
293 struct list entry;
294 unsigned int refcount;
295 WCHAR *FamilyName;
296 WCHAR *EnglishName;
297 struct list faces;
298 struct list *replacement;
299 } Family;
301 typedef struct {
302 GLYPHMETRICS gm;
303 ABC abc; /* metrics of the unrotated char */
304 BOOL init;
305 } GM;
307 typedef struct {
308 FLOAT eM11, eM12;
309 FLOAT eM21, eM22;
310 } FMAT2;
312 typedef struct {
313 DWORD hash;
314 LOGFONTW lf;
315 FMAT2 matrix;
316 BOOL can_use_bitmap;
317 } FONT_DESC;
319 typedef struct tagGdiFont GdiFont;
321 #define FIRST_FONT_HANDLE 1
322 #define MAX_FONT_HANDLES 256
324 struct font_handle_entry
326 void *obj;
327 WORD generation; /* generation count for reusing handle values */
330 static struct font_handle_entry font_handles[MAX_FONT_HANDLES];
331 static struct font_handle_entry *next_free;
332 static struct font_handle_entry *next_unused = font_handles;
334 static inline DWORD entry_to_handle( struct font_handle_entry *entry )
336 unsigned int idx = entry - font_handles + FIRST_FONT_HANDLE;
337 return idx | (entry->generation << 16);
340 static inline struct font_handle_entry *handle_entry( DWORD handle )
342 unsigned int idx = LOWORD(handle) - FIRST_FONT_HANDLE;
344 if (idx < MAX_FONT_HANDLES)
346 if (!HIWORD( handle ) || HIWORD( handle ) == font_handles[idx].generation)
347 return &font_handles[idx];
349 if (handle) WARN( "invalid handle 0x%08x\n", handle );
350 return NULL;
353 static DWORD alloc_font_handle( void *obj )
355 struct font_handle_entry *entry;
357 entry = next_free;
358 if (entry)
359 next_free = entry->obj;
360 else if (next_unused < font_handles + MAX_FONT_HANDLES)
361 entry = next_unused++;
362 else
364 ERR( "out of realized font handles\n" );
365 return 0;
367 entry->obj = obj;
368 if (++entry->generation == 0xffff) entry->generation = 1;
369 return entry_to_handle( entry );
372 static void free_font_handle( DWORD handle )
374 struct font_handle_entry *entry;
376 if ((entry = handle_entry( handle )))
378 entry->obj = next_free;
379 next_free = entry;
383 typedef struct {
384 struct list entry;
385 Face *face;
386 GdiFont *font;
387 } CHILD_FONT;
389 struct font_fileinfo {
390 FILETIME writetime;
391 LARGE_INTEGER size;
392 WCHAR path[1];
395 struct tagGdiFont {
396 struct list entry;
397 struct list unused_entry;
398 unsigned int refcount;
399 GM **gm;
400 DWORD gmsize;
401 OUTLINETEXTMETRICW *potm;
402 DWORD total_kern_pairs;
403 KERNINGPAIR *kern_pairs;
404 struct list child_fonts;
406 /* the following members can be accessed without locking, they are never modified after creation */
407 FT_Face ft_face;
408 struct font_mapping *mapping;
409 LPWSTR name;
410 int charset;
411 int codepage;
412 BOOL fake_italic;
413 BOOL fake_bold;
414 BYTE underline;
415 BYTE strikeout;
416 INT orientation;
417 FONT_DESC font_desc;
418 LONG aveWidth, ppem;
419 double scale_y;
420 SHORT yMax;
421 SHORT yMin;
422 DWORD ntmFlags;
423 DWORD aa_flags;
424 UINT ntmCellHeight, ntmAvgWidth;
425 FONTSIGNATURE fs;
426 GdiFont *base_font;
427 VOID *GSUB_Table;
428 const VOID *vert_feature;
429 ULONG ttc_item_offset; /* 0 if font is not a part of TrueType collection */
430 DWORD cache_num;
431 DWORD instance_id;
432 struct font_fileinfo *fileinfo;
435 typedef struct {
436 struct list entry;
437 const WCHAR *font_name;
438 FONTSIGNATURE fs;
439 struct list links;
440 } SYSTEM_LINKS;
442 struct enum_charset_element {
443 DWORD mask;
444 DWORD charset;
445 WCHAR name[LF_FACESIZE];
448 struct enum_charset_list {
449 DWORD total;
450 struct enum_charset_element element[32];
453 #define GM_BLOCK_SIZE 128
454 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
456 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
457 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
458 static unsigned int unused_font_count;
459 #define UNUSED_CACHE_SIZE 10
460 static struct list system_links = LIST_INIT(system_links);
462 static struct list font_subst_list = LIST_INIT(font_subst_list);
464 static struct list font_list = LIST_INIT(font_list);
466 struct freetype_physdev
468 struct gdi_physdev dev;
469 GdiFont *font;
472 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
474 return (struct freetype_physdev *)dev;
477 static const struct gdi_dc_funcs freetype_funcs;
479 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
480 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
481 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
483 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
484 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
485 'W','i','n','d','o','w','s','\\',
486 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
487 'F','o','n','t','s','\0'};
489 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
490 'W','i','n','d','o','w','s',' ','N','T','\\',
491 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
492 'F','o','n','t','s','\0'};
494 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
495 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
496 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
497 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
499 static const WCHAR * const SystemFontValues[] = {
500 System_Value,
501 OEMFont_Value,
502 FixedSys_Value,
503 NULL
506 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
507 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
509 /* Interesting and well-known (frequently-assumed!) font names */
510 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
511 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 };
512 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
513 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
514 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
515 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
516 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
517 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
519 static const WCHAR arial[] = {'A','r','i','a','l',0};
520 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
521 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};
522 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};
523 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
524 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
525 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
526 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
527 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
528 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
530 static const WCHAR *default_serif_list[] =
532 times_new_roman,
533 liberation_serif,
534 bitstream_vera_serif,
535 NULL
538 static const WCHAR *default_fixed_list[] =
540 courier_new,
541 liberation_mono,
542 bitstream_vera_sans_mono,
543 NULL
546 static const WCHAR *default_sans_list[] =
548 arial,
549 liberation_sans,
550 bitstream_vera_sans,
551 NULL
554 typedef struct {
555 WCHAR *name;
556 INT charset;
557 } NameCs;
559 typedef struct tagFontSubst {
560 struct list entry;
561 NameCs from;
562 NameCs to;
563 } FontSubst;
565 /* Registry font cache key and value names */
566 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
567 'F','o','n','t','s',0};
568 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
569 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
570 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
571 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
572 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
573 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
574 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
575 static const WCHAR face_size_value[] = {'S','i','z','e',0};
576 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
577 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
578 static const WCHAR face_flags_value[] = {'F','l','a','g','s',0};
579 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
580 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
581 static const WCHAR face_file_name_value[] = {'F','i','l','e',' ','N','a','m','e','\0'};
582 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
585 struct font_mapping
587 struct list entry;
588 int refcount;
589 dev_t dev;
590 ino_t ino;
591 void *data;
592 size_t size;
595 static struct list mappings_list = LIST_INIT( mappings_list );
597 static UINT default_aa_flags;
598 static HKEY hkey_font_cache;
599 static BOOL antialias_fakes = TRUE;
601 static CRITICAL_SECTION freetype_cs;
602 static CRITICAL_SECTION_DEBUG critsect_debug =
604 0, 0, &freetype_cs,
605 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
606 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
608 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
610 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
612 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
613 static BOOL use_default_fallback = FALSE;
615 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL *vert);
616 static BOOL get_outline_text_metrics(GdiFont *font);
617 static BOOL get_bitmap_text_metrics(GdiFont *font);
618 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
619 static void remove_face_from_cache( Face *face );
621 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
622 'W','i','n','d','o','w','s',' ','N','T','\\',
623 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
624 'S','y','s','t','e','m','L','i','n','k',0};
626 /****************************************
627 * Notes on .fon files
629 * The fonts System, FixedSys and Terminal are special. There are typically multiple
630 * versions installed for different resolutions and codepages. Windows stores which one to use
631 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
632 * Key Meaning
633 * FIXEDFON.FON FixedSys
634 * FONTS.FON System
635 * OEMFONT.FON Terminal
636 * LogPixels Current dpi set by the display control panel applet
637 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
638 * also has a LogPixels value that appears to mirror this)
640 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
641 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
642 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
643 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
644 * so that makes sense.
646 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
647 * to be mapped into the registry on Windows 2000 at least).
648 * I have
649 * woafont=app850.fon
650 * ega80woa.fon=ega80850.fon
651 * ega40woa.fon=ega40850.fon
652 * cga80woa.fon=cga80850.fon
653 * cga40woa.fon=cga40850.fon
656 /* These are all structures needed for the GSUB table */
659 typedef struct {
660 DWORD version;
661 WORD ScriptList;
662 WORD FeatureList;
663 WORD LookupList;
664 } GSUB_Header;
666 typedef struct {
667 CHAR ScriptTag[4];
668 WORD Script;
669 } GSUB_ScriptRecord;
671 typedef struct {
672 WORD ScriptCount;
673 GSUB_ScriptRecord ScriptRecord[1];
674 } GSUB_ScriptList;
676 typedef struct {
677 CHAR LangSysTag[4];
678 WORD LangSys;
679 } GSUB_LangSysRecord;
681 typedef struct {
682 WORD DefaultLangSys;
683 WORD LangSysCount;
684 GSUB_LangSysRecord LangSysRecord[1];
685 } GSUB_Script;
687 typedef struct {
688 WORD LookupOrder; /* Reserved */
689 WORD ReqFeatureIndex;
690 WORD FeatureCount;
691 WORD FeatureIndex[1];
692 } GSUB_LangSys;
694 typedef struct {
695 CHAR FeatureTag[4];
696 WORD Feature;
697 } GSUB_FeatureRecord;
699 typedef struct {
700 WORD FeatureCount;
701 GSUB_FeatureRecord FeatureRecord[1];
702 } GSUB_FeatureList;
704 typedef struct {
705 WORD FeatureParams; /* Reserved */
706 WORD LookupCount;
707 WORD LookupListIndex[1];
708 } GSUB_Feature;
710 typedef struct {
711 WORD LookupCount;
712 WORD Lookup[1];
713 } GSUB_LookupList;
715 typedef struct {
716 WORD LookupType;
717 WORD LookupFlag;
718 WORD SubTableCount;
719 WORD SubTable[1];
720 } GSUB_LookupTable;
722 typedef struct {
723 WORD CoverageFormat;
724 WORD GlyphCount;
725 WORD GlyphArray[1];
726 } GSUB_CoverageFormat1;
728 typedef struct {
729 WORD Start;
730 WORD End;
731 WORD StartCoverageIndex;
732 } GSUB_RangeRecord;
734 typedef struct {
735 WORD CoverageFormat;
736 WORD RangeCount;
737 GSUB_RangeRecord RangeRecord[1];
738 } GSUB_CoverageFormat2;
740 typedef struct {
741 WORD SubstFormat; /* = 1 */
742 WORD Coverage;
743 WORD DeltaGlyphID;
744 } GSUB_SingleSubstFormat1;
746 typedef struct {
747 WORD SubstFormat; /* = 2 */
748 WORD Coverage;
749 WORD GlyphCount;
750 WORD Substitute[1];
751 }GSUB_SingleSubstFormat2;
753 #ifdef HAVE_CARBON_CARBON_H
754 static char *find_cache_dir(void)
756 FSRef ref;
757 OSErr err;
758 static char cached_path[MAX_PATH];
759 static const char *wine = "/Wine", *fonts = "/Fonts";
761 if(*cached_path) return cached_path;
763 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
764 if(err != noErr)
766 WARN("can't create cached data folder\n");
767 return NULL;
769 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
770 if(err != noErr)
772 WARN("can't create cached data path\n");
773 *cached_path = '\0';
774 return NULL;
776 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
778 ERR("Could not create full path\n");
779 *cached_path = '\0';
780 return NULL;
782 strcat(cached_path, wine);
784 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
786 WARN("Couldn't mkdir %s\n", cached_path);
787 *cached_path = '\0';
788 return NULL;
790 strcat(cached_path, fonts);
791 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
793 WARN("Couldn't mkdir %s\n", cached_path);
794 *cached_path = '\0';
795 return NULL;
797 return cached_path;
800 /******************************************************************
801 * expand_mac_font
803 * Extracts individual TrueType font files from a Mac suitcase font
804 * and saves them into the user's caches directory (see
805 * find_cache_dir()).
806 * Returns a NULL terminated array of filenames.
808 * We do this because they are apps that try to read ttf files
809 * themselves and they don't like Mac suitcase files.
811 static char **expand_mac_font(const char *path)
813 FSRef ref;
814 SInt16 res_ref;
815 OSStatus s;
816 unsigned int idx;
817 const char *out_dir;
818 const char *filename;
819 int output_len;
820 struct {
821 char **array;
822 unsigned int size, max_size;
823 } ret;
825 TRACE("path %s\n", path);
827 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
828 if(s != noErr)
830 WARN("failed to get ref\n");
831 return NULL;
834 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
835 if(s != noErr)
837 TRACE("no data fork, so trying resource fork\n");
838 res_ref = FSOpenResFile(&ref, fsRdPerm);
839 if(res_ref == -1)
841 TRACE("unable to open resource fork\n");
842 return NULL;
846 ret.size = 0;
847 ret.max_size = 10;
848 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
849 if(!ret.array)
851 CloseResFile(res_ref);
852 return NULL;
855 out_dir = find_cache_dir();
857 filename = strrchr(path, '/');
858 if(!filename) filename = path;
859 else filename++;
861 /* output filename has the form out_dir/filename_%04x.ttf */
862 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
864 UseResFile(res_ref);
865 idx = 1;
866 while(1)
868 FamRec *fam_rec;
869 unsigned short *num_faces_ptr, num_faces, face;
870 AsscEntry *assoc;
871 Handle fond;
872 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
874 fond = Get1IndResource(fond_res, idx);
875 if(!fond) break;
876 TRACE("got fond resource %d\n", idx);
877 HLock(fond);
879 fam_rec = *(FamRec**)fond;
880 num_faces_ptr = (unsigned short *)(fam_rec + 1);
881 num_faces = GET_BE_WORD(*num_faces_ptr);
882 num_faces++;
883 assoc = (AsscEntry*)(num_faces_ptr + 1);
884 TRACE("num faces %04x\n", num_faces);
885 for(face = 0; face < num_faces; face++, assoc++)
887 Handle sfnt;
888 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
889 unsigned short size, font_id;
890 char *output;
892 size = GET_BE_WORD(assoc->fontSize);
893 font_id = GET_BE_WORD(assoc->fontID);
894 if(size != 0)
896 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
897 continue;
900 TRACE("trying to load sfnt id %04x\n", font_id);
901 sfnt = GetResource(sfnt_res, font_id);
902 if(!sfnt)
904 TRACE("can't get sfnt resource %04x\n", font_id);
905 continue;
908 output = HeapAlloc(GetProcessHeap(), 0, output_len);
909 if(output)
911 int fd;
913 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
915 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
916 if(fd != -1 || errno == EEXIST)
918 if(fd != -1)
920 unsigned char *sfnt_data;
922 HLock(sfnt);
923 sfnt_data = *(unsigned char**)sfnt;
924 write(fd, sfnt_data, GetHandleSize(sfnt));
925 HUnlock(sfnt);
926 close(fd);
928 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
930 ret.max_size *= 2;
931 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
933 ret.array[ret.size++] = output;
935 else
937 WARN("unable to create %s\n", output);
938 HeapFree(GetProcessHeap(), 0, output);
941 ReleaseResource(sfnt);
943 HUnlock(fond);
944 ReleaseResource(fond);
945 idx++;
947 CloseResFile(res_ref);
949 return ret.array;
952 #endif /* HAVE_CARBON_CARBON_H */
954 static inline BOOL is_win9x(void)
956 return GetVersion() & 0x80000000;
959 This function builds an FT_Fixed from a double. It fails if the absolute
960 value of the float number is greater than 32768.
962 static inline FT_Fixed FT_FixedFromFloat(double f)
964 return f * 0x10000;
968 This function builds an FT_Fixed from a FIXED. It simply put f.value
969 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
971 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
973 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
976 static BOOL is_hinting_enabled(void)
978 static int enabled = -1;
980 if (enabled == -1)
982 /* Use the >= 2.2.0 function if available */
983 if (pFT_Get_TrueType_Engine_Type)
985 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
986 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
988 else enabled = FALSE;
989 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
991 return enabled;
994 static BOOL is_subpixel_rendering_enabled( void )
996 #ifdef FT_LCD_FILTER_H
997 static int enabled = -1;
998 if (enabled == -1)
1000 enabled = (pFT_Library_SetLcdFilter &&
1001 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature);
1002 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
1004 return enabled;
1005 #else
1006 return FALSE;
1007 #endif
1011 static const struct list *get_face_list_from_family(const Family *family)
1013 if (!list_empty(&family->faces))
1014 return &family->faces;
1015 else
1016 return family->replacement;
1019 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
1021 Family *family;
1022 Face *face;
1023 const WCHAR *file;
1025 TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
1027 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1029 const struct list *face_list;
1030 if(face_name && strncmpiW(face_name, family->FamilyName, LF_FACESIZE - 1))
1031 continue;
1032 face_list = get_face_list_from_family(family);
1033 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
1035 if (!face->file)
1036 continue;
1037 file = strrchrW(face->file, '/');
1038 if(!file)
1039 file = face->file;
1040 else
1041 file++;
1042 if(strcmpiW(file, file_name)) continue;
1043 face->refcount++;
1044 return face;
1047 return NULL;
1050 static Family *find_family_from_name(const WCHAR *name)
1052 Family *family;
1054 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1056 if(!strncmpiW(family->FamilyName, name, LF_FACESIZE -1))
1057 return family;
1060 return NULL;
1063 static Family *find_family_from_any_name(const WCHAR *name)
1065 Family *family;
1067 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1069 if(!strncmpiW(family->FamilyName, name, LF_FACESIZE - 1))
1070 return family;
1071 if(family->EnglishName && !strncmpiW(family->EnglishName, name, LF_FACESIZE - 1))
1072 return family;
1075 return NULL;
1078 static void DumpSubstList(void)
1080 FontSubst *psub;
1082 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
1084 if(psub->from.charset != -1 || psub->to.charset != -1)
1085 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
1086 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
1087 else
1088 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
1089 debugstr_w(psub->to.name));
1093 static LPWSTR strdupW(LPCWSTR p)
1095 LPWSTR ret;
1096 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
1097 ret = HeapAlloc(GetProcessHeap(), 0, len);
1098 memcpy(ret, p, len);
1099 return ret;
1102 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1103 INT from_charset)
1105 FontSubst *element;
1107 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1109 if(!strcmpiW(element->from.name, from_name) &&
1110 (element->from.charset == from_charset ||
1111 element->from.charset == -1))
1112 return element;
1115 return NULL;
1118 #define ADD_FONT_SUBST_FORCE 1
1120 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1122 FontSubst *from_exist, *to_exist;
1124 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1126 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1128 list_remove(&from_exist->entry);
1129 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
1130 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
1131 HeapFree(GetProcessHeap(), 0, from_exist);
1132 from_exist = NULL;
1135 if(!from_exist)
1137 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1139 if(to_exist)
1141 HeapFree(GetProcessHeap(), 0, subst->to.name);
1142 subst->to.name = strdupW(to_exist->to.name);
1145 list_add_tail(subst_list, &subst->entry);
1147 return TRUE;
1150 HeapFree(GetProcessHeap(), 0, subst->from.name);
1151 HeapFree(GetProcessHeap(), 0, subst->to.name);
1152 HeapFree(GetProcessHeap(), 0, subst);
1153 return FALSE;
1156 static WCHAR *towstr(UINT cp, const char *str)
1158 int len;
1159 WCHAR *wstr;
1161 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1162 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1163 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1164 return wstr;
1167 static char *strWtoA(UINT cp, const WCHAR *str)
1169 int len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL );
1170 char *ret = HeapAlloc( GetProcessHeap(), 0, len );
1171 WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL );
1172 return ret;
1175 static void split_subst_info(NameCs *nc, LPSTR str)
1177 CHAR *p = strrchr(str, ',');
1179 nc->charset = -1;
1180 if(p && *(p+1)) {
1181 nc->charset = strtol(p+1, NULL, 10);
1182 *p = '\0';
1184 nc->name = towstr(CP_ACP, str);
1187 static void LoadSubstList(void)
1189 FontSubst *psub;
1190 HKEY hkey;
1191 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1192 LPSTR value;
1193 LPVOID data;
1195 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1196 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1197 &hkey) == ERROR_SUCCESS) {
1199 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1200 &valuelen, &datalen, NULL, NULL);
1202 valuelen++; /* returned value doesn't include room for '\0' */
1203 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1204 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1206 dlen = datalen;
1207 vlen = valuelen;
1208 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1209 &dlen) == ERROR_SUCCESS) {
1210 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1212 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1213 split_subst_info(&psub->from, value);
1214 split_subst_info(&psub->to, data);
1216 /* Win 2000 doesn't allow mapping between different charsets
1217 or mapping of DEFAULT_CHARSET */
1218 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1219 psub->to.charset == DEFAULT_CHARSET) {
1220 HeapFree(GetProcessHeap(), 0, psub->to.name);
1221 HeapFree(GetProcessHeap(), 0, psub->from.name);
1222 HeapFree(GetProcessHeap(), 0, psub);
1223 } else {
1224 add_font_subst(&font_subst_list, psub, 0);
1226 /* reset dlen and vlen */
1227 dlen = datalen;
1228 vlen = valuelen;
1230 HeapFree(GetProcessHeap(), 0, data);
1231 HeapFree(GetProcessHeap(), 0, value);
1232 RegCloseKey(hkey);
1237 static const LANGID mac_langid_table[] =
1239 MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */
1240 MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */
1241 MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */
1242 MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */
1243 MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */
1244 MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */
1245 MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */
1246 MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */
1247 MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */
1248 MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */
1249 MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */
1250 MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */
1251 MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */
1252 MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */
1253 MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */
1254 MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */
1255 MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */
1256 MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */
1257 MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */
1258 MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
1259 MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */
1260 MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */
1261 MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */
1262 MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */
1263 MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */
1264 MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */
1265 MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */
1266 MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */
1267 MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */
1268 MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */
1269 MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */
1270 MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */
1271 MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */
1272 MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
1273 MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */
1274 MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */
1275 MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */
1276 MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */
1277 MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */
1278 MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */
1279 MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */
1280 0, /* TT_MAC_LANGID_YIDDISH */
1281 MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */
1282 MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */
1283 MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */
1284 MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */
1285 MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */
1286 MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */
1287 MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */
1288 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */
1289 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
1290 MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */
1291 MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */
1292 0, /* TT_MAC_LANGID_MOLDAVIAN */
1293 MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */
1294 MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */
1295 MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */
1296 MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */
1297 MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
1298 MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */
1299 0, /* TT_MAC_LANGID_KURDISH */
1300 MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */
1301 MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */
1302 MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */
1303 MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */
1304 MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */
1305 MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */
1306 MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */
1307 MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */
1308 MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */
1309 MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */
1310 MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */
1311 MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */
1312 MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */
1313 MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */
1314 MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */
1315 MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */
1316 0, /* TT_MAC_LANGID_BURMESE */
1317 MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */
1318 MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */
1319 MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */
1320 MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */
1321 0, /* TT_MAC_LANGID_TAGALOG */
1322 MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
1323 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
1324 MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */
1325 MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */
1326 0, /* TT_MAC_LANGID_GALLA */
1327 0, /* TT_MAC_LANGID_SOMALI */
1328 MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */
1329 0, /* TT_MAC_LANGID_RUANDA */
1330 0, /* TT_MAC_LANGID_RUNDI */
1331 0, /* TT_MAC_LANGID_CHEWA */
1332 MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */
1333 MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */
1334 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
1335 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
1336 MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */
1337 MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */
1338 MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */
1339 0, /* TT_MAC_LANGID_LATIN */
1340 MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */
1341 0, /* TT_MAC_LANGID_GUARANI */
1342 0, /* TT_MAC_LANGID_AYMARA */
1343 MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */
1344 MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */
1345 0, /* TT_MAC_LANGID_DZONGKHA */
1346 0, /* TT_MAC_LANGID_JAVANESE */
1347 0, /* TT_MAC_LANGID_SUNDANESE */
1348 MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */
1349 MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */
1350 MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */
1351 MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */
1352 MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
1353 MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */
1354 MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */
1355 0, /* TT_MAC_LANGID_TONGAN */
1356 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
1357 MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */
1358 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
1361 static inline WORD get_mac_code_page( const FT_SfntName *name )
1363 if (name->encoding_id == TT_MAC_ID_SIMPLIFIED_CHINESE) return 10008; /* special case */
1364 return 10000 + name->encoding_id;
1367 static int match_name_table_language( const FT_SfntName *name, LANGID lang )
1369 LANGID name_lang;
1370 int res = 0;
1372 switch (name->platform_id)
1374 case TT_PLATFORM_MICROSOFT:
1375 res += 5; /* prefer the Microsoft name */
1376 switch (name->encoding_id)
1378 case TT_MS_ID_UNICODE_CS:
1379 case TT_MS_ID_SYMBOL_CS:
1380 name_lang = name->language_id;
1381 break;
1382 default:
1383 return 0;
1385 break;
1386 case TT_PLATFORM_MACINTOSH:
1387 if (!IsValidCodePage( get_mac_code_page( name ))) return 0;
1388 if (name->language_id >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
1389 name_lang = mac_langid_table[name->language_id];
1390 break;
1391 case TT_PLATFORM_APPLE_UNICODE:
1392 res += 2; /* prefer Unicode encodings */
1393 switch (name->encoding_id)
1395 case TT_APPLE_ID_DEFAULT:
1396 case TT_APPLE_ID_ISO_10646:
1397 case TT_APPLE_ID_UNICODE_2_0:
1398 if (name->language_id >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
1399 name_lang = mac_langid_table[name->language_id];
1400 break;
1401 default:
1402 return 0;
1404 break;
1405 default:
1406 return 0;
1408 if (name_lang == lang) res += 30;
1409 else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20;
1410 else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10;
1411 return res;
1414 static WCHAR *copy_name_table_string( const FT_SfntName *name )
1416 WCHAR *ret;
1417 WORD codepage;
1418 int i;
1420 switch (name->platform_id)
1422 case TT_PLATFORM_APPLE_UNICODE:
1423 case TT_PLATFORM_MICROSOFT:
1424 ret = HeapAlloc( GetProcessHeap(), 0, name->string_len + sizeof(WCHAR) );
1425 for (i = 0; i < name->string_len / 2; i++)
1426 ret[i] = (name->string[i * 2] << 8) | name->string[i * 2 + 1];
1427 ret[i] = 0;
1428 return ret;
1429 case TT_PLATFORM_MACINTOSH:
1430 codepage = get_mac_code_page( name );
1431 i = MultiByteToWideChar( codepage, 0, (char *)name->string, name->string_len, NULL, 0 );
1432 ret = HeapAlloc( GetProcessHeap(), 0, (i + 1) * sizeof(WCHAR) );
1433 MultiByteToWideChar( codepage, 0, (char *)name->string, name->string_len, ret, i );
1434 ret[i] = 0;
1435 return ret;
1437 return NULL;
1440 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, LANGID language_id)
1442 FT_SfntName name;
1443 FT_UInt num_names, name_index;
1444 int res, best_lang = 0, best_index = -1;
1446 if (!FT_IS_SFNT(ft_face)) return NULL;
1448 num_names = pFT_Get_Sfnt_Name_Count( ft_face );
1450 for (name_index = 0; name_index < num_names; name_index++)
1452 if (pFT_Get_Sfnt_Name( ft_face, name_index, &name )) continue;
1453 if (name.name_id != name_id) continue;
1454 res = match_name_table_language( &name, language_id );
1455 if (res > best_lang)
1457 best_lang = res;
1458 best_index = name_index;
1462 if (best_index != -1 && !pFT_Get_Sfnt_Name( ft_face, best_index, &name ))
1464 WCHAR *ret = copy_name_table_string( &name );
1465 TRACE( "name %u found platform %u lang %04x %s\n",
1466 name_id, name.platform_id, name.language_id, debugstr_w( ret ));
1467 return ret;
1469 return NULL;
1472 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1474 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1475 if (f1->scalable) return TRUE;
1476 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1477 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1480 static void release_family( Family *family )
1482 if (--family->refcount) return;
1483 assert( list_empty( &family->faces ));
1484 list_remove( &family->entry );
1485 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1486 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1487 HeapFree( GetProcessHeap(), 0, family );
1490 static void release_face( Face *face )
1492 if (--face->refcount) return;
1493 if (face->family)
1495 if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
1496 list_remove( &face->entry );
1497 release_family( face->family );
1499 HeapFree( GetProcessHeap(), 0, face->file );
1500 HeapFree( GetProcessHeap(), 0, face->StyleName );
1501 HeapFree( GetProcessHeap(), 0, face->FullName );
1502 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1503 HeapFree( GetProcessHeap(), 0, face );
1506 static inline int style_order(const Face *face)
1508 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1510 case NTM_REGULAR:
1511 return 0;
1512 case NTM_BOLD:
1513 return 1;
1514 case NTM_ITALIC:
1515 return 2;
1516 case NTM_BOLD | NTM_ITALIC:
1517 return 3;
1518 default:
1519 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1520 debugstr_w(face->family->FamilyName),
1521 debugstr_w(face->StyleName),
1522 face->ntmFlags);
1523 return 9999;
1527 static BOOL insert_face_in_family_list( Face *face, Family *family )
1529 Face *cursor;
1531 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1533 if (faces_equal( face, cursor ))
1535 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1536 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1537 cursor->font_version, face->font_version);
1539 if (face->file && face->dev == cursor->dev && face->ino == cursor->ino)
1541 cursor->refcount++;
1542 TRACE("Font %s already in list, refcount now %d\n",
1543 debugstr_w(face->file), cursor->refcount);
1544 return FALSE;
1546 if (face->font_version <= cursor->font_version)
1548 TRACE("Original font %s is newer so skipping %s\n",
1549 debugstr_w(cursor->file), debugstr_w(face->file));
1550 return FALSE;
1552 else
1554 TRACE("Replacing original %s with %s\n",
1555 debugstr_w(cursor->file), debugstr_w(face->file));
1556 list_add_before( &cursor->entry, &face->entry );
1557 face->family = family;
1558 family->refcount++;
1559 face->refcount++;
1560 release_face( cursor );
1561 return TRUE;
1564 else
1565 TRACE("Adding new %s\n", debugstr_w(face->file));
1567 if (style_order( face ) < style_order( cursor )) break;
1570 list_add_before( &cursor->entry, &face->entry );
1571 face->family = family;
1572 family->refcount++;
1573 face->refcount++;
1574 return TRUE;
1577 /****************************************************************
1578 * NB This function stores the ptrs to the strings to save copying.
1579 * Don't free them after calling.
1581 static Family *create_family( WCHAR *name, WCHAR *english_name )
1583 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1584 family->refcount = 1;
1585 family->FamilyName = name;
1586 family->EnglishName = english_name;
1587 list_init( &family->faces );
1588 family->replacement = &family->faces;
1589 list_add_tail( &font_list, &family->entry );
1591 return family;
1594 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1596 DWORD type, size = sizeof(DWORD);
1598 if (RegQueryValueExW(hkey, value, NULL, &type, (BYTE *)data, &size) ||
1599 type != REG_DWORD || size != sizeof(DWORD))
1601 *data = 0;
1602 return ERROR_BAD_CONFIGURATION;
1604 return ERROR_SUCCESS;
1607 static inline LONG reg_load_ftlong(HKEY hkey, const WCHAR *value, FT_Long *data)
1609 DWORD dw;
1610 LONG ret = reg_load_dword(hkey, value, &dw);
1611 *data = dw;
1612 return ret;
1615 static inline LONG reg_load_ftshort(HKEY hkey, const WCHAR *value, FT_Short *data)
1617 DWORD dw;
1618 LONG ret = reg_load_dword(hkey, value, &dw);
1619 *data = dw;
1620 return ret;
1623 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1625 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1628 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1630 DWORD needed, strike_index = 0;
1631 HKEY hkey_strike;
1633 /* If we have a File Name key then this is a real font, not just the parent
1634 key of a bunch of non-scalable strikes */
1635 needed = buffer_size;
1636 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1638 Face *face;
1639 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1640 face->cached_enum_data = NULL;
1641 face->family = NULL;
1643 face->refcount = 1;
1644 face->file = strdupW( buffer );
1645 face->StyleName = strdupW(face_name);
1647 needed = buffer_size;
1648 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1649 face->FullName = strdupW( buffer );
1650 else
1651 face->FullName = NULL;
1653 reg_load_ftlong(hkey_face, face_index_value, &face->face_index);
1654 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1655 reg_load_ftlong(hkey_face, face_version_value, &face->font_version);
1656 reg_load_dword(hkey_face, face_flags_value, &face->flags);
1658 needed = sizeof(face->fs);
1659 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1661 if(reg_load_ftshort(hkey_face, face_height_value, &face->size.height) != ERROR_SUCCESS)
1663 face->scalable = TRUE;
1664 memset(&face->size, 0, sizeof(face->size));
1666 else
1668 face->scalable = FALSE;
1669 reg_load_ftshort(hkey_face, face_width_value, &face->size.width);
1670 reg_load_ftlong(hkey_face, face_size_value, &face->size.size);
1671 reg_load_ftlong(hkey_face, face_x_ppem_value, &face->size.x_ppem);
1672 reg_load_ftlong(hkey_face, face_y_ppem_value, &face->size.y_ppem);
1673 reg_load_ftshort(hkey_face, face_internal_leading_value, &face->size.internal_leading);
1675 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1676 face->size.height, face->size.width, face->size.size >> 6,
1677 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1680 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1681 face->fs.fsCsb[0], face->fs.fsCsb[1],
1682 face->fs.fsUsb[0], face->fs.fsUsb[1],
1683 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1685 if (insert_face_in_family_list(face, family))
1686 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1688 release_face( face );
1691 /* load bitmap strikes */
1693 needed = buffer_size;
1694 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1696 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1698 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1699 RegCloseKey(hkey_strike);
1701 needed = buffer_size;
1705 /* move vertical fonts after their horizontal counterpart */
1706 /* assumes that font_list is already sorted by family name */
1707 static void reorder_vertical_fonts(void)
1709 Family *family, *next, *vert_family;
1710 struct list *ptr, *vptr;
1711 struct list vertical_families = LIST_INIT( vertical_families );
1713 LIST_FOR_EACH_ENTRY_SAFE( family, next, &font_list, Family, entry )
1715 if (family->FamilyName[0] != '@') continue;
1716 list_remove( &family->entry );
1717 list_add_tail( &vertical_families, &family->entry );
1720 ptr = list_head( &font_list );
1721 vptr = list_head( &vertical_families );
1722 while (ptr && vptr)
1724 family = LIST_ENTRY( ptr, Family, entry );
1725 vert_family = LIST_ENTRY( vptr, Family, entry );
1726 if (strcmpiW( family->FamilyName, vert_family->FamilyName + 1 ) > 0)
1728 list_remove( vptr );
1729 list_add_before( ptr, vptr );
1730 vptr = list_head( &vertical_families );
1732 else ptr = list_next( &font_list, ptr );
1734 list_move_tail( &font_list, &vertical_families );
1737 static void load_font_list_from_cache(HKEY hkey_font_cache)
1739 DWORD size, family_index = 0;
1740 Family *family;
1741 HKEY hkey_family;
1742 WCHAR buffer[4096];
1744 size = sizeof(buffer);
1745 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1747 WCHAR *english_family = NULL;
1748 WCHAR *family_name = strdupW( buffer );
1749 DWORD face_index = 0;
1751 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1752 TRACE("opened family key %s\n", debugstr_w(family_name));
1753 size = sizeof(buffer);
1754 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1755 english_family = strdupW( buffer );
1757 family = create_family(family_name, english_family);
1759 if(english_family)
1761 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1762 subst->from.name = strdupW(english_family);
1763 subst->from.charset = -1;
1764 subst->to.name = strdupW(family_name);
1765 subst->to.charset = -1;
1766 add_font_subst(&font_subst_list, subst, 0);
1769 size = sizeof(buffer);
1770 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1772 WCHAR *face_name = strdupW( buffer );
1773 HKEY hkey_face;
1775 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1777 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1778 RegCloseKey(hkey_face);
1780 HeapFree( GetProcessHeap(), 0, face_name );
1781 size = sizeof(buffer);
1783 RegCloseKey(hkey_family);
1784 release_family( family );
1785 size = sizeof(buffer);
1788 reorder_vertical_fonts();
1791 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1793 LONG ret;
1794 HKEY hkey_wine_fonts;
1796 /* We don't want to create the fonts key as volatile, so open this first */
1797 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1798 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1799 if(ret != ERROR_SUCCESS)
1801 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1802 return ret;
1805 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1806 KEY_ALL_ACCESS, NULL, hkey, disposition);
1807 RegCloseKey(hkey_wine_fonts);
1808 return ret;
1811 static void add_face_to_cache(Face *face)
1813 HKEY hkey_family, hkey_face;
1814 WCHAR *face_key_name;
1816 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1817 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1818 if(face->family->EnglishName)
1819 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1820 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1822 if(face->scalable)
1823 face_key_name = face->StyleName;
1824 else
1826 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1827 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1828 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1830 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1831 &hkey_face, NULL);
1832 if(!face->scalable)
1833 HeapFree(GetProcessHeap(), 0, face_key_name);
1835 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1836 (strlenW(face->file) + 1) * sizeof(WCHAR));
1837 if (face->FullName)
1838 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1839 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1841 reg_save_dword(hkey_face, face_index_value, face->face_index);
1842 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1843 reg_save_dword(hkey_face, face_version_value, face->font_version);
1844 if (face->flags) reg_save_dword(hkey_face, face_flags_value, face->flags);
1846 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1848 if(!face->scalable)
1850 reg_save_dword(hkey_face, face_height_value, face->size.height);
1851 reg_save_dword(hkey_face, face_width_value, face->size.width);
1852 reg_save_dword(hkey_face, face_size_value, face->size.size);
1853 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1854 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1855 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1857 RegCloseKey(hkey_face);
1858 RegCloseKey(hkey_family);
1861 static void remove_face_from_cache( Face *face )
1863 HKEY hkey_family;
1865 RegOpenKeyExW( hkey_font_cache, face->family->FamilyName, 0, KEY_ALL_ACCESS, &hkey_family );
1867 if (face->scalable)
1869 RegDeleteKeyW( hkey_family, face->StyleName );
1871 else
1873 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1874 WCHAR *face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1875 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1876 RegDeleteKeyW( hkey_family, face_key_name );
1877 HeapFree(GetProcessHeap(), 0, face_key_name);
1879 RegCloseKey(hkey_family);
1882 static WCHAR *prepend_at(WCHAR *family)
1884 WCHAR *str;
1886 if (!family)
1887 return NULL;
1889 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1890 str[0] = '@';
1891 strcpyW(str + 1, family);
1892 HeapFree(GetProcessHeap(), 0, family);
1893 return str;
1896 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1898 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT) );
1899 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1901 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1902 if (!*name)
1904 *name = *english;
1905 *english = NULL;
1907 else if (!strcmpiW( *name, *english ))
1909 HeapFree( GetProcessHeap(), 0, *english );
1910 *english = NULL;
1913 if (vertical)
1915 *name = prepend_at( *name );
1916 *english = prepend_at( *english );
1920 static Family *get_family( FT_Face ft_face, BOOL vertical )
1922 Family *family;
1923 WCHAR *name, *english_name;
1925 get_family_names( ft_face, &name, &english_name, vertical );
1927 family = find_family_from_name( name );
1929 if (!family)
1931 family = create_family( name, english_name );
1932 if (english_name)
1934 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1935 subst->from.name = strdupW( english_name );
1936 subst->from.charset = -1;
1937 subst->to.name = strdupW( name );
1938 subst->to.charset = -1;
1939 add_font_subst( &font_subst_list, subst, 0 );
1942 else
1944 HeapFree( GetProcessHeap(), 0, name );
1945 HeapFree( GetProcessHeap(), 0, english_name );
1946 family->refcount++;
1949 return family;
1952 static inline FT_Fixed get_font_version( FT_Face ft_face )
1954 FT_Fixed version = 0;
1955 TT_Header *header;
1957 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1958 if (header) version = header->Font_Revision;
1960 return version;
1963 static inline DWORD get_ntm_flags( FT_Face ft_face )
1965 DWORD flags = 0;
1966 FT_ULong table_size = 0;
1967 FT_WinFNT_HeaderRec winfnt_header;
1969 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1970 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1972 /* fixup the flag for our fake-bold implementation. */
1973 if (!FT_IS_SCALABLE( ft_face ) &&
1974 !pFT_Get_WinFNT_Header( ft_face, &winfnt_header ) &&
1975 winfnt_header.weight > FW_NORMAL )
1976 flags |= NTM_BOLD;
1978 if (flags == 0) flags = NTM_REGULAR;
1980 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1981 flags |= NTM_PS_OPENTYPE;
1983 return flags;
1986 static inline void get_bitmap_size( FT_Face ft_face, Bitmap_Size *face_size )
1988 My_FT_Bitmap_Size *size;
1989 FT_WinFNT_HeaderRec winfnt_header;
1991 size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1992 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1993 size->height, size->width, size->size >> 6,
1994 size->x_ppem >> 6, size->y_ppem >> 6);
1995 face_size->height = size->height;
1996 face_size->width = size->width;
1997 face_size->size = size->size;
1998 face_size->x_ppem = size->x_ppem;
1999 face_size->y_ppem = size->y_ppem;
2001 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header )) {
2002 face_size->internal_leading = winfnt_header.internal_leading;
2003 if (winfnt_header.external_leading > 0 &&
2004 (face_size->height ==
2005 winfnt_header.pixel_height + winfnt_header.external_leading))
2006 face_size->height = winfnt_header.pixel_height;
2010 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
2012 TT_OS2 *os2;
2013 FT_UInt dummy;
2014 CHARSETINFO csi;
2015 FT_WinFNT_HeaderRec winfnt_header;
2016 int i;
2018 memset( fs, 0, sizeof(*fs) );
2020 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
2021 if (os2)
2023 fs->fsUsb[0] = os2->ulUnicodeRange1;
2024 fs->fsUsb[1] = os2->ulUnicodeRange2;
2025 fs->fsUsb[2] = os2->ulUnicodeRange3;
2026 fs->fsUsb[3] = os2->ulUnicodeRange4;
2028 if (os2->version == 0)
2030 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
2031 fs->fsCsb[0] = FS_LATIN1;
2032 else
2033 fs->fsCsb[0] = FS_SYMBOL;
2035 else
2037 fs->fsCsb[0] = os2->ulCodePageRange1;
2038 fs->fsCsb[1] = os2->ulCodePageRange2;
2041 else
2043 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
2045 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
2046 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
2047 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
2048 *fs = csi.fs;
2052 if (fs->fsCsb[0] == 0)
2054 /* let's see if we can find any interesting cmaps */
2055 for (i = 0; i < ft_face->num_charmaps; i++)
2057 switch (ft_face->charmaps[i]->encoding)
2059 case FT_ENCODING_UNICODE:
2060 case FT_ENCODING_APPLE_ROMAN:
2061 fs->fsCsb[0] |= FS_LATIN1;
2062 break;
2063 case FT_ENCODING_MS_SYMBOL:
2064 fs->fsCsb[0] |= FS_SYMBOL;
2065 break;
2066 default:
2067 break;
2073 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
2074 DWORD flags )
2076 struct stat st;
2077 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
2079 face->refcount = 1;
2080 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
2081 if (!face->StyleName) face->StyleName = towstr( CP_ACP, ft_face->style_name );
2083 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
2084 if (flags & ADDFONT_VERTICAL_FONT)
2085 face->FullName = prepend_at( face->FullName );
2087 face->dev = 0;
2088 face->ino = 0;
2089 if (file)
2091 face->file = towstr( CP_UNIXCP, file );
2092 face->font_data_ptr = NULL;
2093 face->font_data_size = 0;
2094 if (!stat( file, &st ))
2096 face->dev = st.st_dev;
2097 face->ino = st.st_ino;
2100 else
2102 face->file = NULL;
2103 face->font_data_ptr = font_data_ptr;
2104 face->font_data_size = font_data_size;
2107 face->face_index = face_index;
2108 get_fontsig( ft_face, &face->fs );
2109 face->ntmFlags = get_ntm_flags( ft_face );
2110 face->font_version = get_font_version( ft_face );
2112 if (FT_IS_SCALABLE( ft_face ))
2114 memset( &face->size, 0, sizeof(face->size) );
2115 face->scalable = TRUE;
2117 else
2119 get_bitmap_size( ft_face, &face->size );
2120 face->scalable = FALSE;
2123 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
2124 face->flags = flags;
2125 face->family = NULL;
2126 face->cached_enum_data = NULL;
2128 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
2129 face->fs.fsCsb[0], face->fs.fsCsb[1],
2130 face->fs.fsUsb[0], face->fs.fsUsb[1],
2131 face->fs.fsUsb[2], face->fs.fsUsb[3]);
2133 return face;
2136 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
2137 FT_Long face_index, DWORD flags )
2139 Face *face;
2140 Family *family;
2142 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags );
2143 family = get_family( ft_face, flags & ADDFONT_VERTICAL_FONT );
2145 if (insert_face_in_family_list( face, family ))
2147 if (flags & ADDFONT_ADD_TO_CACHE)
2148 add_face_to_cache( face );
2150 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
2151 debugstr_w(face->StyleName));
2153 release_face( face );
2154 release_family( family );
2157 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
2158 FT_Long face_index, BOOL allow_bitmap )
2160 FT_Error err;
2161 TT_OS2 *pOS2;
2162 FT_Face ft_face;
2164 if (file)
2166 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
2167 err = pFT_New_Face(library, file, face_index, &ft_face);
2169 else
2171 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
2172 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
2175 if (err != 0)
2177 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
2178 return NULL;
2181 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
2182 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
2184 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
2185 goto fail;
2188 if (!FT_IS_SFNT( ft_face ))
2190 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
2192 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
2193 goto fail;
2196 else
2198 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
2199 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
2200 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
2202 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
2203 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
2204 goto fail;
2207 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
2208 we don't want to load these. */
2209 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
2211 FT_ULong len = 0;
2213 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
2215 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
2216 goto fail;
2221 if (!ft_face->family_name || !ft_face->style_name)
2223 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
2224 goto fail;
2227 return ft_face;
2228 fail:
2229 pFT_Done_Face( ft_face );
2230 return NULL;
2233 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
2235 FT_Face ft_face;
2236 FT_Long face_index = 0, num_faces;
2237 INT ret = 0;
2239 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
2240 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
2242 #ifdef HAVE_CARBON_CARBON_H
2243 if(file)
2245 char **mac_list = expand_mac_font(file);
2246 if(mac_list)
2248 BOOL had_one = FALSE;
2249 char **cursor;
2250 for(cursor = mac_list; *cursor; cursor++)
2252 had_one = TRUE;
2253 AddFontToList(*cursor, NULL, 0, flags);
2254 HeapFree(GetProcessHeap(), 0, *cursor);
2256 HeapFree(GetProcessHeap(), 0, mac_list);
2257 if(had_one)
2258 return 1;
2261 #endif /* HAVE_CARBON_CARBON_H */
2263 do {
2264 const DWORD FS_DBCS_MASK = FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB;
2265 FONTSIGNATURE fs;
2267 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_ALLOW_BITMAP );
2268 if (!ft_face) return 0;
2270 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
2272 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
2273 pFT_Done_Face(ft_face);
2274 return 0;
2277 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags);
2278 ++ret;
2280 get_fontsig(ft_face, &fs);
2281 if (fs.fsCsb[0] & FS_DBCS_MASK)
2283 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index,
2284 flags | ADDFONT_VERTICAL_FONT);
2285 ++ret;
2288 num_faces = ft_face->num_faces;
2289 pFT_Done_Face(ft_face);
2290 } while(num_faces > ++face_index);
2291 return ret;
2294 static int remove_font_resource( const char *file, DWORD flags )
2296 Family *family, *family_next;
2297 Face *face, *face_next;
2298 struct stat st;
2299 int count = 0;
2301 if (stat( file, &st ) == -1) return 0;
2302 LIST_FOR_EACH_ENTRY_SAFE( family, family_next, &font_list, Family, entry )
2304 family->refcount++;
2305 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, Face, entry )
2307 if (!face->file) continue;
2308 if (LOWORD(face->flags) != LOWORD(flags)) continue;
2309 if (st.st_dev == face->dev && st.st_ino == face->ino)
2311 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount );
2312 release_face( face );
2313 count++;
2316 release_family( family );
2318 return count;
2321 static void DumpFontList(void)
2323 Family *family;
2324 Face *face;
2326 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2327 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
2328 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2329 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
2330 if(!face->scalable)
2331 TRACE(" %d", face->size.height);
2332 TRACE("\n");
2337 static BOOL map_font_family(const WCHAR *orig, const WCHAR *repl)
2339 Family *family = find_family_from_any_name(repl);
2340 if (family != NULL)
2342 Family *new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2343 if (new_family != NULL)
2345 TRACE("mapping %s to %s\n", debugstr_w(repl), debugstr_w(orig));
2346 new_family->FamilyName = strdupW(orig);
2347 new_family->EnglishName = NULL;
2348 list_init(&new_family->faces);
2349 new_family->replacement = &family->faces;
2350 list_add_tail(&font_list, &new_family->entry);
2351 return TRUE;
2354 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(repl));
2355 return FALSE;
2358 /***********************************************************
2359 * The replacement list is a way to map an entire font
2360 * family onto another family. For example adding
2362 * [HKCU\Software\Wine\Fonts\Replacements]
2363 * "Wingdings"="Winedings"
2365 * would enumerate the Winedings font both as Winedings and
2366 * Wingdings. However if a real Wingdings font is present the
2367 * replacement does not take place.
2370 static void LoadReplaceList(void)
2372 HKEY hkey;
2373 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2374 LPWSTR value;
2375 LPVOID data;
2377 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2378 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
2380 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2381 &valuelen, &datalen, NULL, NULL);
2383 valuelen++; /* returned value doesn't include room for '\0' */
2384 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2385 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2387 dlen = datalen;
2388 vlen = valuelen;
2389 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data, &dlen) == ERROR_SUCCESS)
2391 /* "NewName"="Oldname" */
2392 if(!find_family_from_any_name(value))
2394 if (type == REG_MULTI_SZ)
2396 WCHAR *replace = data;
2397 while(*replace)
2399 if (map_font_family(value, replace))
2400 break;
2401 replace += strlenW(replace) + 1;
2404 else if (type == REG_SZ)
2405 map_font_family(value, data);
2407 else
2408 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2410 /* reset dlen and vlen */
2411 dlen = datalen;
2412 vlen = valuelen;
2414 HeapFree(GetProcessHeap(), 0, data);
2415 HeapFree(GetProcessHeap(), 0, value);
2416 RegCloseKey(hkey);
2420 static const WCHAR *font_links_list[] =
2422 Lucida_Sans_Unicode,
2423 Microsoft_Sans_Serif,
2424 Tahoma
2427 static const struct font_links_defaults_list
2429 /* Keyed off substitution for "MS Shell Dlg" */
2430 const WCHAR *shelldlg;
2431 /* Maximum of four substitutes, plus terminating NULL pointer */
2432 const WCHAR *substitutes[5];
2433 } font_links_defaults_list[] =
2435 /* Non East-Asian */
2436 { Tahoma, /* FIXME unverified ordering */
2437 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2439 /* Below lists are courtesy of
2440 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2442 /* Japanese */
2443 { MS_UI_Gothic,
2444 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2446 /* Chinese Simplified */
2447 { SimSun,
2448 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2450 /* Korean */
2451 { Gulim,
2452 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2454 /* Chinese Traditional */
2455 { PMingLiU,
2456 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2461 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2463 SYSTEM_LINKS *font_link;
2465 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2467 if(!strncmpiW(font_link->font_name, name, LF_FACESIZE - 1))
2468 return font_link;
2471 return NULL;
2474 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2476 const WCHAR *value;
2477 int i;
2478 FontSubst *psub;
2479 Family *family;
2480 Face *face;
2481 const WCHAR *file;
2483 if (values)
2485 SYSTEM_LINKS *font_link;
2487 psub = get_font_subst(&font_subst_list, name, -1);
2488 /* Don't store fonts that are only substitutes for other fonts */
2489 if(psub)
2491 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2492 return;
2495 font_link = find_font_link(name);
2496 if (font_link == NULL)
2498 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2499 font_link->font_name = strdupW(name);
2500 list_init(&font_link->links);
2501 list_add_tail(&system_links, &font_link->entry);
2504 memset(&font_link->fs, 0, sizeof font_link->fs);
2505 for (i = 0; values[i] != NULL; i++)
2507 const struct list *face_list;
2508 CHILD_FONT *child_font;
2510 value = values[i];
2511 if (!strcmpiW(name,value))
2512 continue;
2513 psub = get_font_subst(&font_subst_list, value, -1);
2514 if(psub)
2515 value = psub->to.name;
2516 family = find_family_from_name(value);
2517 if (!family)
2518 continue;
2519 file = NULL;
2520 /* Use first extant filename for this Family */
2521 face_list = get_face_list_from_family(family);
2522 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2524 if (!face->file)
2525 continue;
2526 file = strrchrW(face->file, '/');
2527 if (!file)
2528 file = face->file;
2529 else
2530 file++;
2531 break;
2533 if (!file)
2534 continue;
2535 face = find_face_from_filename(file, value);
2536 if(!face)
2538 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2539 continue;
2542 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2543 child_font->face = face;
2544 child_font->font = NULL;
2545 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2546 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2547 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2548 child_font->face->face_index);
2549 list_add_tail(&font_link->links, &child_font->entry);
2551 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2557 /*************************************************************
2558 * init_system_links
2560 static BOOL init_system_links(void)
2562 HKEY hkey;
2563 BOOL ret = FALSE;
2564 DWORD type, max_val, max_data, val_len, data_len, index;
2565 WCHAR *value, *data;
2566 WCHAR *entry, *next;
2567 SYSTEM_LINKS *font_link, *system_font_link;
2568 CHILD_FONT *child_font;
2569 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2570 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2571 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2572 Face *face;
2573 FontSubst *psub;
2574 UINT i, j;
2576 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2578 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2579 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2580 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2581 val_len = max_val + 1;
2582 data_len = max_data;
2583 index = 0;
2584 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2586 psub = get_font_subst(&font_subst_list, value, -1);
2587 /* Don't store fonts that are only substitutes for other fonts */
2588 if(psub)
2590 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2591 goto next;
2593 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2594 font_link->font_name = strdupW(value);
2595 memset(&font_link->fs, 0, sizeof font_link->fs);
2596 list_init(&font_link->links);
2597 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2599 WCHAR *face_name;
2600 CHILD_FONT *child_font;
2602 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2604 next = entry + strlenW(entry) + 1;
2606 face_name = strchrW(entry, ',');
2607 if(face_name)
2609 *face_name++ = 0;
2610 while(isspaceW(*face_name))
2611 face_name++;
2613 psub = get_font_subst(&font_subst_list, face_name, -1);
2614 if(psub)
2615 face_name = psub->to.name;
2617 face = find_face_from_filename(entry, face_name);
2618 if(!face)
2620 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2621 continue;
2624 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2625 child_font->face = face;
2626 child_font->font = NULL;
2627 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2628 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2629 TRACE("Adding file %s index %ld\n",
2630 debugstr_w(child_font->face->file), child_font->face->face_index);
2631 list_add_tail(&font_link->links, &child_font->entry);
2633 list_add_tail(&system_links, &font_link->entry);
2634 next:
2635 val_len = max_val + 1;
2636 data_len = max_data;
2639 HeapFree(GetProcessHeap(), 0, value);
2640 HeapFree(GetProcessHeap(), 0, data);
2641 RegCloseKey(hkey);
2645 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2646 if (!psub) {
2647 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2648 goto skip_internal;
2651 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2653 const FontSubst *psub2;
2654 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2656 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2658 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2659 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2661 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2662 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2664 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2666 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2670 skip_internal:
2672 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2673 that Tahoma has */
2675 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2676 system_font_link->font_name = strdupW(System);
2677 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2678 list_init(&system_font_link->links);
2680 face = find_face_from_filename(tahoma_ttf, Tahoma);
2681 if(face)
2683 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2684 child_font->face = face;
2685 child_font->font = NULL;
2686 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2687 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2688 TRACE("Found Tahoma in %s index %ld\n",
2689 debugstr_w(child_font->face->file), child_font->face->face_index);
2690 list_add_tail(&system_font_link->links, &child_font->entry);
2692 font_link = find_font_link(Tahoma);
2693 if (font_link != NULL)
2695 CHILD_FONT *font_link_entry;
2696 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2698 CHILD_FONT *new_child;
2699 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2700 new_child->face = font_link_entry->face;
2701 new_child->font = NULL;
2702 new_child->face->refcount++;
2703 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2704 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2705 list_add_tail(&system_font_link->links, &new_child->entry);
2708 list_add_tail(&system_links, &system_font_link->entry);
2709 return ret;
2712 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2714 DIR *dir;
2715 struct dirent *dent;
2716 char path[MAX_PATH];
2718 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2720 dir = opendir(dirname);
2721 if(!dir) {
2722 WARN("Can't open directory %s\n", debugstr_a(dirname));
2723 return FALSE;
2725 while((dent = readdir(dir)) != NULL) {
2726 struct stat statbuf;
2728 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2729 continue;
2731 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2733 sprintf(path, "%s/%s", dirname, dent->d_name);
2735 if(stat(path, &statbuf) == -1)
2737 WARN("Can't stat %s\n", debugstr_a(path));
2738 continue;
2740 if(S_ISDIR(statbuf.st_mode))
2741 ReadFontDir(path, external_fonts);
2742 else
2744 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2745 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2746 AddFontToList(path, NULL, 0, addfont_flags);
2749 closedir(dir);
2750 return TRUE;
2753 #ifdef SONAME_LIBFONTCONFIG
2755 static BOOL fontconfig_enabled;
2757 static UINT parse_aa_pattern( FcPattern *pattern )
2759 FcBool antialias;
2760 int rgba;
2761 UINT aa_flags = 0;
2763 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2764 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2766 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2768 switch (rgba)
2770 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2771 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2772 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2773 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2774 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2777 return aa_flags;
2780 static void init_fontconfig(void)
2782 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2784 if (!fc_handle)
2786 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2787 return;
2790 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2791 LOAD_FUNCPTR(FcConfigSubstitute);
2792 LOAD_FUNCPTR(FcFontList);
2793 LOAD_FUNCPTR(FcFontSetDestroy);
2794 LOAD_FUNCPTR(FcInit);
2795 LOAD_FUNCPTR(FcObjectSetAdd);
2796 LOAD_FUNCPTR(FcObjectSetCreate);
2797 LOAD_FUNCPTR(FcObjectSetDestroy);
2798 LOAD_FUNCPTR(FcPatternCreate);
2799 LOAD_FUNCPTR(FcPatternDestroy);
2800 LOAD_FUNCPTR(FcPatternGetBool);
2801 LOAD_FUNCPTR(FcPatternGetInteger);
2802 LOAD_FUNCPTR(FcPatternGetString);
2803 #undef LOAD_FUNCPTR
2805 if (pFcInit())
2807 FcPattern *pattern = pFcPatternCreate();
2808 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2809 default_aa_flags = parse_aa_pattern( pattern );
2810 pFcPatternDestroy( pattern );
2811 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2812 fontconfig_enabled = TRUE;
2816 static void load_fontconfig_fonts(void)
2818 FcPattern *pat;
2819 FcObjectSet *os;
2820 FcFontSet *fontset;
2821 int i, len;
2822 char *file;
2823 const char *ext;
2825 if (!fontconfig_enabled) return;
2827 pat = pFcPatternCreate();
2828 os = pFcObjectSetCreate();
2829 pFcObjectSetAdd(os, FC_FILE);
2830 pFcObjectSetAdd(os, FC_SCALABLE);
2831 pFcObjectSetAdd(os, FC_ANTIALIAS);
2832 pFcObjectSetAdd(os, FC_RGBA);
2833 fontset = pFcFontList(NULL, pat, os);
2834 if(!fontset) return;
2835 for(i = 0; i < fontset->nfont; i++) {
2836 FcBool scalable;
2837 DWORD aa_flags;
2839 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2840 continue;
2842 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2844 /* We're just interested in OT/TT fonts for now, so this hack just
2845 picks up the scalable fonts without extensions .pf[ab] to save time
2846 loading every other font */
2848 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2850 TRACE("not scalable\n");
2851 continue;
2854 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2855 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2857 len = strlen( file );
2858 if(len < 4) continue;
2859 ext = &file[ len - 3 ];
2860 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2861 AddFontToList(file, NULL, 0,
2862 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2864 pFcFontSetDestroy(fontset);
2865 pFcObjectSetDestroy(os);
2866 pFcPatternDestroy(pat);
2869 #elif defined(HAVE_CARBON_CARBON_H)
2871 static void load_mac_font_callback(const void *value, void *context)
2873 CFStringRef pathStr = value;
2874 CFIndex len;
2875 char* path;
2877 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2878 path = HeapAlloc(GetProcessHeap(), 0, len);
2879 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2881 TRACE("font file %s\n", path);
2882 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2884 HeapFree(GetProcessHeap(), 0, path);
2887 static void load_mac_fonts(void)
2889 CFStringRef removeDupesKey;
2890 CFBooleanRef removeDupesValue;
2891 CFDictionaryRef options;
2892 CTFontCollectionRef col;
2893 CFArrayRef descs;
2894 CFMutableSetRef paths;
2895 CFIndex i;
2897 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2898 removeDupesValue = kCFBooleanTrue;
2899 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2900 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2901 col = CTFontCollectionCreateFromAvailableFonts(options);
2902 if (options) CFRelease(options);
2903 if (!col)
2905 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2906 return;
2909 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2910 CFRelease(col);
2911 if (!descs)
2913 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2914 return;
2917 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2918 if (!paths)
2920 WARN("CFSetCreateMutable failed\n");
2921 CFRelease(descs);
2922 return;
2925 for (i = 0; i < CFArrayGetCount(descs); i++)
2927 CTFontDescriptorRef desc;
2928 CFURLRef url;
2929 CFStringRef ext;
2930 CFStringRef path;
2932 desc = CFArrayGetValueAtIndex(descs, i);
2934 #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2935 url = CTFontDescriptorCopyAttribute(desc, kCTFontURLAttribute);
2936 #else
2937 /* CTFontDescriptor doesn't support kCTFontURLAttribute prior to 10.6, so
2938 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2940 CTFontRef font;
2941 ATSFontRef atsFont;
2942 OSStatus status;
2943 FSRef fsref;
2945 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2946 if (!font) continue;
2948 atsFont = CTFontGetPlatformFont(font, NULL);
2949 if (!atsFont)
2951 CFRelease(font);
2952 continue;
2955 status = ATSFontGetFileReference(atsFont, &fsref);
2956 CFRelease(font);
2957 if (status != noErr) continue;
2959 url = CFURLCreateFromFSRef(NULL, &fsref);
2961 #endif
2962 if (!url) continue;
2964 ext = CFURLCopyPathExtension(url);
2965 if (ext)
2967 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2968 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2969 CFRelease(ext);
2970 if (skip)
2972 CFRelease(url);
2973 continue;
2977 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2978 CFRelease(url);
2979 if (!path) continue;
2981 CFSetAddValue(paths, path);
2982 CFRelease(path);
2985 CFRelease(descs);
2987 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2988 CFRelease(paths);
2991 #endif
2993 static char *get_font_dir(void)
2995 const char *build_dir, *data_dir;
2996 char *name = NULL;
2998 if ((data_dir = wine_get_data_dir()))
3000 if (!(name = HeapAlloc( GetProcessHeap(), 0, strlen(data_dir) + 1 + sizeof(WINE_FONT_DIR) )))
3001 return NULL;
3002 strcpy( name, data_dir );
3003 strcat( name, "/" );
3004 strcat( name, WINE_FONT_DIR );
3006 else if ((build_dir = wine_get_build_dir()))
3008 if (!(name = HeapAlloc( GetProcessHeap(), 0, strlen(build_dir) + sizeof("/fonts") )))
3009 return NULL;
3010 strcpy( name, build_dir );
3011 strcat( name, "/fonts" );
3013 return name;
3016 static char *get_data_dir_path( LPCWSTR file )
3018 char *unix_name = NULL;
3019 char *font_dir = get_font_dir();
3021 if (font_dir)
3023 INT len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
3025 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(font_dir) + len + 1 );
3026 strcpy(unix_name, font_dir);
3027 strcat(unix_name, "/");
3029 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
3030 HeapFree( GetProcessHeap(), 0, font_dir );
3032 return unix_name;
3035 static BOOL load_font_from_data_dir(LPCWSTR file)
3037 BOOL ret = FALSE;
3038 char *unix_name = get_data_dir_path( file );
3040 if (unix_name)
3042 EnterCriticalSection( &freetype_cs );
3043 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3044 LeaveCriticalSection( &freetype_cs );
3045 HeapFree(GetProcessHeap(), 0, unix_name);
3047 return ret;
3050 static char *get_winfonts_dir_path(LPCWSTR file)
3052 static const WCHAR slashW[] = {'\\','\0'};
3053 WCHAR windowsdir[MAX_PATH];
3055 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3056 strcatW(windowsdir, fontsW);
3057 strcatW(windowsdir, slashW);
3058 strcatW(windowsdir, file);
3059 return wine_get_unix_file_name( windowsdir );
3062 static void load_system_fonts(void)
3064 HKEY hkey;
3065 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
3066 const WCHAR * const *value;
3067 DWORD dlen, type;
3068 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3069 char *unixname;
3071 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
3072 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3073 strcatW(windowsdir, fontsW);
3074 for(value = SystemFontValues; *value; value++) {
3075 dlen = sizeof(data);
3076 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
3077 type == REG_SZ) {
3078 BOOL added = FALSE;
3080 sprintfW(pathW, fmtW, windowsdir, data);
3081 if((unixname = wine_get_unix_file_name(pathW))) {
3082 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3083 HeapFree(GetProcessHeap(), 0, unixname);
3085 if (!added)
3086 load_font_from_data_dir(data);
3089 RegCloseKey(hkey);
3093 /*************************************************************
3095 * This adds registry entries for any externally loaded fonts
3096 * (fonts from fontconfig or FontDirs). It also deletes entries
3097 * of no longer existing fonts.
3100 static void update_reg_entries(void)
3102 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
3103 LPWSTR valueW;
3104 DWORD len;
3105 Family *family;
3106 Face *face;
3107 WCHAR *file, *path;
3108 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
3110 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
3111 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
3112 ERR("Can't create Windows font reg key\n");
3113 goto end;
3116 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
3117 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
3118 ERR("Can't create Windows font reg key\n");
3119 goto end;
3122 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
3123 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
3124 ERR("Can't create external font reg key\n");
3125 goto end;
3128 /* enumerate the fonts and add external ones to the two keys */
3130 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
3131 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
3132 char *buffer;
3133 WCHAR *name;
3135 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
3137 name = face->FullName ? face->FullName : family->FamilyName;
3139 len = strlenW(name) + 1;
3140 if (face->scalable)
3141 len += sizeof(TrueType) / sizeof(WCHAR);
3143 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3144 strcpyW(valueW, name);
3146 if (face->scalable)
3147 strcatW(valueW, TrueType);
3149 buffer = strWtoA( CP_UNIXCP, face->file );
3150 path = wine_get_dos_file_name( buffer );
3151 HeapFree( GetProcessHeap(), 0, buffer );
3153 if (path)
3154 file = path;
3155 else if ((file = strrchrW(face->file, '/')))
3156 file++;
3157 else
3158 file = face->file;
3160 len = strlenW(file) + 1;
3161 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3162 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3163 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3165 HeapFree(GetProcessHeap(), 0, path);
3166 HeapFree(GetProcessHeap(), 0, valueW);
3169 end:
3170 if(external_key) RegCloseKey(external_key);
3171 if(win9x_key) RegCloseKey(win9x_key);
3172 if(winnt_key) RegCloseKey(winnt_key);
3175 static void delete_external_font_keys(void)
3177 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
3178 DWORD dlen, plen, vlen, datalen, valuelen, i, type, path_type;
3179 LPWSTR valueW;
3180 LPVOID data;
3181 BYTE *path;
3183 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
3184 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
3185 ERR("Can't create Windows font reg key\n");
3186 goto end;
3189 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
3190 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
3191 ERR("Can't create Windows font reg key\n");
3192 goto end;
3195 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
3196 ERR("Can't create external font reg key\n");
3197 goto end;
3200 /* Delete all external fonts added last time */
3202 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3203 &valuelen, &datalen, NULL, NULL);
3204 valuelen++; /* returned value doesn't include room for '\0' */
3205 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3206 data = HeapAlloc(GetProcessHeap(), 0, datalen);
3207 path = HeapAlloc(GetProcessHeap(), 0, datalen);
3209 dlen = datalen;
3210 vlen = valuelen;
3211 i = 0;
3212 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
3213 &dlen) == ERROR_SUCCESS) {
3214 plen = dlen;
3215 if (RegQueryValueExW(winnt_key, valueW, 0, &path_type, path, &plen) == ERROR_SUCCESS &&
3216 type == path_type && dlen == plen && !memcmp(data, path, plen))
3217 RegDeleteValueW(winnt_key, valueW);
3219 plen = dlen;
3220 if (RegQueryValueExW(win9x_key, valueW, 0, &path_type, path, &plen) == ERROR_SUCCESS &&
3221 type == path_type && dlen == plen && !memcmp(data, path, plen))
3222 RegDeleteValueW(win9x_key, valueW);
3224 /* reset dlen and vlen */
3225 dlen = datalen;
3226 vlen = valuelen;
3228 HeapFree(GetProcessHeap(), 0, path);
3229 HeapFree(GetProcessHeap(), 0, data);
3230 HeapFree(GetProcessHeap(), 0, valueW);
3232 /* Delete the old external fonts key */
3233 RegCloseKey(external_key);
3234 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
3236 end:
3237 if(win9x_key) RegCloseKey(win9x_key);
3238 if(winnt_key) RegCloseKey(winnt_key);
3241 /*************************************************************
3242 * WineEngAddFontResourceEx
3245 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3247 INT ret = 0;
3249 GDI_CheckNotLock();
3251 if (ft_handle) /* do it only if we have freetype up and running */
3253 char *unixname;
3255 EnterCriticalSection( &freetype_cs );
3257 if((unixname = wine_get_unix_file_name(file)))
3259 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3261 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3262 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
3263 HeapFree(GetProcessHeap(), 0, unixname);
3265 if (!ret && !strchrW(file, '\\')) {
3266 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
3267 if ((unixname = get_winfonts_dir_path( file )))
3269 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3270 HeapFree(GetProcessHeap(), 0, unixname);
3272 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
3273 if (!ret && (unixname = get_data_dir_path( file )))
3275 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3276 HeapFree(GetProcessHeap(), 0, unixname);
3280 LeaveCriticalSection( &freetype_cs );
3282 return ret;
3285 /*************************************************************
3286 * WineEngAddFontMemResourceEx
3289 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3291 GDI_CheckNotLock();
3293 if (ft_handle) /* do it only if we have freetype up and running */
3295 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
3297 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
3298 memcpy(pFontCopy, pbFont, cbFont);
3300 EnterCriticalSection( &freetype_cs );
3301 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3302 LeaveCriticalSection( &freetype_cs );
3304 if (*pcFonts == 0)
3306 TRACE("AddFontToList failed\n");
3307 HeapFree(GetProcessHeap(), 0, pFontCopy);
3308 return 0;
3310 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
3311 * For now return something unique but quite random
3313 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
3314 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
3317 *pcFonts = 0;
3318 return 0;
3321 /*************************************************************
3322 * WineEngRemoveFontResourceEx
3325 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3327 INT ret = 0;
3329 GDI_CheckNotLock();
3331 if (ft_handle) /* do it only if we have freetype up and running */
3333 char *unixname;
3335 EnterCriticalSection( &freetype_cs );
3337 if ((unixname = wine_get_unix_file_name(file)))
3339 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3341 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3342 ret = remove_font_resource( unixname, addfont_flags );
3343 HeapFree(GetProcessHeap(), 0, unixname);
3345 if (!ret && !strchrW(file, '\\'))
3347 if ((unixname = get_winfonts_dir_path( file )))
3349 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3350 HeapFree(GetProcessHeap(), 0, unixname);
3352 if (!ret && (unixname = get_data_dir_path( file )))
3354 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3355 HeapFree(GetProcessHeap(), 0, unixname);
3359 LeaveCriticalSection( &freetype_cs );
3361 return ret;
3364 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
3366 WCHAR *fullname;
3367 char *unix_name;
3368 int file_len;
3370 if (!font_file) return NULL;
3372 file_len = strlenW( font_file );
3374 if (font_path && font_path[0])
3376 int path_len = strlenW( font_path );
3377 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
3378 if (!fullname) return NULL;
3379 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
3380 fullname[path_len] = '\\';
3381 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
3383 else
3385 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
3386 if (!len) return NULL;
3387 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3388 if (!fullname) return NULL;
3389 GetFullPathNameW( font_file, len, fullname, NULL );
3392 unix_name = wine_get_unix_file_name( fullname );
3393 HeapFree( GetProcessHeap(), 0, fullname );
3394 return unix_name;
3397 #include <pshpack1.h>
3398 struct fontdir
3400 WORD num_of_resources;
3401 WORD res_id;
3402 WORD dfVersion;
3403 DWORD dfSize;
3404 CHAR dfCopyright[60];
3405 WORD dfType;
3406 WORD dfPoints;
3407 WORD dfVertRes;
3408 WORD dfHorizRes;
3409 WORD dfAscent;
3410 WORD dfInternalLeading;
3411 WORD dfExternalLeading;
3412 BYTE dfItalic;
3413 BYTE dfUnderline;
3414 BYTE dfStrikeOut;
3415 WORD dfWeight;
3416 BYTE dfCharSet;
3417 WORD dfPixWidth;
3418 WORD dfPixHeight;
3419 BYTE dfPitchAndFamily;
3420 WORD dfAvgWidth;
3421 WORD dfMaxWidth;
3422 BYTE dfFirstChar;
3423 BYTE dfLastChar;
3424 BYTE dfDefaultChar;
3425 BYTE dfBreakChar;
3426 WORD dfWidthBytes;
3427 DWORD dfDevice;
3428 DWORD dfFace;
3429 DWORD dfReserved;
3430 CHAR szFaceName[LF_FACESIZE];
3433 #include <poppack.h>
3435 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
3436 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
3438 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
3440 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3441 Face *face;
3442 WCHAR *name, *english_name;
3443 ENUMLOGFONTEXW elf;
3444 NEWTEXTMETRICEXW ntm;
3445 DWORD type;
3447 if (!ft_face) return FALSE;
3448 face = create_face( ft_face, 0, unix_name, NULL, 0, 0 );
3449 get_family_names( ft_face, &name, &english_name, FALSE );
3450 pFT_Done_Face( ft_face );
3452 GetEnumStructs( face, name, &elf, &ntm, &type );
3453 release_face( face );
3454 HeapFree( GetProcessHeap(), 0, name );
3455 HeapFree( GetProcessHeap(), 0, english_name );
3457 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3459 memset( fd, 0, sizeof(*fd) );
3461 fd->num_of_resources = 1;
3462 fd->res_id = 0;
3463 fd->dfVersion = 0x200;
3464 fd->dfSize = sizeof(*fd);
3465 strcpy( fd->dfCopyright, "Wine fontdir" );
3466 fd->dfType = 0x4003; /* 0x0080 set if private */
3467 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3468 fd->dfVertRes = 72;
3469 fd->dfHorizRes = 72;
3470 fd->dfAscent = ntm.ntmTm.tmAscent;
3471 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3472 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3473 fd->dfItalic = ntm.ntmTm.tmItalic;
3474 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3475 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3476 fd->dfWeight = ntm.ntmTm.tmWeight;
3477 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3478 fd->dfPixWidth = 0;
3479 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3480 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3481 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3482 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3483 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3484 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3485 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3486 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3487 fd->dfWidthBytes = 0;
3488 fd->dfDevice = 0;
3489 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3490 fd->dfReserved = 0;
3491 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3493 return TRUE;
3496 #define NE_FFLAGS_LIBMODULE 0x8000
3497 #define NE_OSFLAGS_WINDOWS 0x02
3499 static const char dos_string[0x40] = "This is a TrueType resource file";
3500 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3502 #include <pshpack2.h>
3504 struct ne_typeinfo
3506 WORD type_id;
3507 WORD count;
3508 DWORD res;
3511 struct ne_nameinfo
3513 WORD off;
3514 WORD len;
3515 WORD flags;
3516 WORD id;
3517 DWORD res;
3520 struct rsrc_tab
3522 WORD align;
3523 struct ne_typeinfo fontdir_type;
3524 struct ne_nameinfo fontdir_name;
3525 struct ne_typeinfo scalable_type;
3526 struct ne_nameinfo scalable_name;
3527 WORD end_of_rsrc;
3528 BYTE fontdir_res_name[8];
3531 #include <poppack.h>
3533 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3535 BOOL ret = FALSE;
3536 HANDLE file;
3537 DWORD size, written;
3538 BYTE *ptr, *start;
3539 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3540 char *font_fileA, *last_part, *ext;
3541 IMAGE_DOS_HEADER dos;
3542 IMAGE_OS2_HEADER ne =
3544 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3545 0, 0, 0, 0, 0, 0,
3546 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3547 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3549 struct rsrc_tab rsrc_tab =
3552 { 0x8007, 1, 0 },
3553 { 0, 0, 0x0c50, 0x2c, 0 },
3554 { 0x80cc, 1, 0 },
3555 { 0, 0, 0x0c50, 0x8001, 0 },
3557 { 7,'F','O','N','T','D','I','R'}
3560 memset( &dos, 0, sizeof(dos) );
3561 dos.e_magic = IMAGE_DOS_SIGNATURE;
3562 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3564 /* import name is last part\0, resident name is last part without extension
3565 non-resident name is "FONTRES:" + lfFaceName */
3567 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3568 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3569 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3571 last_part = strrchr( font_fileA, '\\' );
3572 if (last_part) last_part++;
3573 else last_part = font_fileA;
3574 import_name_len = strlen( last_part ) + 1;
3576 ext = strchr( last_part, '.' );
3577 if (ext) res_name_len = ext - last_part;
3578 else res_name_len = import_name_len - 1;
3580 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3582 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3583 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3584 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3585 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3586 ne.ne_cbenttab = 2;
3587 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3589 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3590 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3591 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3592 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3594 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3595 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3597 if (!ptr)
3599 HeapFree( GetProcessHeap(), 0, font_fileA );
3600 return FALSE;
3603 memcpy( ptr, &dos, sizeof(dos) );
3604 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3605 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3607 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3608 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3610 ptr = start + dos.e_lfanew + ne.ne_restab;
3611 *ptr++ = res_name_len;
3612 memcpy( ptr, last_part, res_name_len );
3614 ptr = start + dos.e_lfanew + ne.ne_imptab;
3615 *ptr++ = import_name_len;
3616 memcpy( ptr, last_part, import_name_len );
3618 ptr = start + ne.ne_nrestab;
3619 *ptr++ = non_res_name_len;
3620 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3621 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3623 ptr = start + (rsrc_tab.scalable_name.off << 4);
3624 memcpy( ptr, font_fileA, font_file_len );
3626 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3627 memcpy( ptr, fontdir, fontdir->dfSize );
3629 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3630 if (file != INVALID_HANDLE_VALUE)
3632 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3633 ret = TRUE;
3634 CloseHandle( file );
3637 HeapFree( GetProcessHeap(), 0, start );
3638 HeapFree( GetProcessHeap(), 0, font_fileA );
3640 return ret;
3643 /*************************************************************
3644 * WineEngCreateScalableFontResource
3647 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3648 LPCWSTR font_file, LPCWSTR font_path )
3650 char *unix_name = get_ttf_file_name( font_file, font_path );
3651 struct fontdir fontdir;
3652 BOOL ret = FALSE;
3654 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3655 SetLastError( ERROR_INVALID_PARAMETER );
3656 else
3658 if (hidden) fontdir.dfType |= 0x80;
3659 ret = create_fot( resource, font_file, &fontdir );
3662 HeapFree( GetProcessHeap(), 0, unix_name );
3663 return ret;
3666 static const struct nls_update_font_list
3668 UINT ansi_cp, oem_cp;
3669 const char *oem, *fixed, *system;
3670 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3671 /* these are for font substitutes */
3672 const char *shelldlg, *tmsrmn;
3673 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3674 *helv_0, *tmsrmn_0;
3675 const struct subst
3677 const char *from, *to;
3678 } arial_0, courier_new_0, times_new_roman_0;
3679 } nls_update_font_list[] =
3681 /* Latin 1 (United States) */
3682 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3683 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3684 "Tahoma","Times New Roman",
3685 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3686 { 0 }, { 0 }, { 0 }
3688 /* Latin 1 (Multilingual) */
3689 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3690 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3691 "Tahoma","Times New Roman", /* FIXME unverified */
3692 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3693 { 0 }, { 0 }, { 0 }
3695 /* Eastern Europe */
3696 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3697 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3698 "Tahoma","Times New Roman", /* FIXME unverified */
3699 "Fixedsys,238", "System,238",
3700 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3701 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3702 { "Arial CE,0", "Arial,238" },
3703 { "Courier New CE,0", "Courier New,238" },
3704 { "Times New Roman CE,0", "Times New Roman,238" }
3706 /* Cyrillic */
3707 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3708 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3709 "Tahoma","Times New Roman", /* FIXME unverified */
3710 "Fixedsys,204", "System,204",
3711 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3712 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3713 { "Arial Cyr,0", "Arial,204" },
3714 { "Courier New Cyr,0", "Courier New,204" },
3715 { "Times New Roman Cyr,0", "Times New Roman,204" }
3717 /* Greek */
3718 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3719 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3720 "Tahoma","Times New Roman", /* FIXME unverified */
3721 "Fixedsys,161", "System,161",
3722 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3723 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3724 { "Arial Greek,0", "Arial,161" },
3725 { "Courier New Greek,0", "Courier New,161" },
3726 { "Times New Roman Greek,0", "Times New Roman,161" }
3728 /* Turkish */
3729 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3730 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3731 "Tahoma","Times New Roman", /* FIXME unverified */
3732 "Fixedsys,162", "System,162",
3733 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3734 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3735 { "Arial Tur,0", "Arial,162" },
3736 { "Courier New Tur,0", "Courier New,162" },
3737 { "Times New Roman Tur,0", "Times New Roman,162" }
3739 /* Hebrew */
3740 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3741 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3742 "Tahoma","Times New Roman", /* FIXME unverified */
3743 "Fixedsys,177", "System,177",
3744 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3745 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3746 { 0 }, { 0 }, { 0 }
3748 /* Arabic */
3749 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3750 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3751 "Microsoft Sans Serif","Times New Roman",
3752 "Fixedsys,178", "System,178",
3753 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3754 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3755 { 0 }, { 0 }, { 0 }
3757 /* Baltic */
3758 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3759 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3760 "Tahoma","Times New Roman", /* FIXME unverified */
3761 "Fixedsys,186", "System,186",
3762 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3763 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3764 { "Arial Baltic,0", "Arial,186" },
3765 { "Courier New Baltic,0", "Courier New,186" },
3766 { "Times New Roman Baltic,0", "Times New Roman,186" }
3768 /* Vietnamese */
3769 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3770 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3771 "Tahoma","Times New Roman", /* FIXME unverified */
3772 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3773 { 0 }, { 0 }, { 0 }
3775 /* Thai */
3776 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3777 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3778 "Tahoma","Times New Roman", /* FIXME unverified */
3779 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3780 { 0 }, { 0 }, { 0 }
3782 /* Japanese */
3783 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3784 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3785 "MS UI Gothic","MS Serif",
3786 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3787 { 0 }, { 0 }, { 0 }
3789 /* Chinese Simplified */
3790 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3791 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3792 "SimSun", "NSimSun",
3793 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3794 { 0 }, { 0 }, { 0 }
3796 /* Korean */
3797 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3798 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3799 "Gulim", "Batang",
3800 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3801 { 0 }, { 0 }, { 0 }
3803 /* Chinese Traditional */
3804 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3805 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3806 "PMingLiU", "MingLiU",
3807 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3808 { 0 }, { 0 }, { 0 }
3812 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3814 return ( ansi_cp == 932 /* CP932 for Japanese */
3815 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3816 || ansi_cp == 949 /* CP949 for Korean */
3817 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3820 static inline HKEY create_fonts_NT_registry_key(void)
3822 HKEY hkey = 0;
3824 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3825 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3826 return hkey;
3829 static inline HKEY create_fonts_9x_registry_key(void)
3831 HKEY hkey = 0;
3833 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3834 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3835 return hkey;
3838 static inline HKEY create_config_fonts_registry_key(void)
3840 HKEY hkey = 0;
3842 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3843 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3844 return hkey;
3847 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3849 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3851 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3852 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3853 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3854 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3857 static void set_value_key(HKEY hkey, const char *name, const char *value)
3859 if (value)
3860 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3861 else if (name)
3862 RegDeleteValueA(hkey, name);
3865 static void update_font_association_info(UINT current_ansi_codepage)
3867 static const char *font_assoc_reg_key = "System\\CurrentControlSet\\Control\\FontAssoc";
3868 static const char *assoc_charset_subkey = "Associated Charset";
3870 if (is_dbcs_ansi_cp(current_ansi_codepage))
3872 HKEY hkey;
3873 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, font_assoc_reg_key, &hkey) == ERROR_SUCCESS)
3875 HKEY hsubkey;
3876 if (RegCreateKeyA(hkey, assoc_charset_subkey, &hsubkey) == ERROR_SUCCESS)
3878 switch (current_ansi_codepage)
3880 case 932:
3881 set_value_key(hsubkey, "ANSI(00)", "NO");
3882 set_value_key(hsubkey, "OEM(FF)", "NO");
3883 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3884 break;
3885 case 936:
3886 case 949:
3887 case 950:
3888 set_value_key(hsubkey, "ANSI(00)", "YES");
3889 set_value_key(hsubkey, "OEM(FF)", "YES");
3890 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3891 break;
3893 RegCloseKey(hsubkey);
3896 /* TODO: Associated DefaultFonts */
3898 RegCloseKey(hkey);
3901 else
3902 RegDeleteTreeA(HKEY_LOCAL_MACHINE, font_assoc_reg_key);
3905 static void set_multi_value_key(HKEY hkey, const WCHAR *name, const WCHAR *value, DWORD len)
3907 if (value)
3908 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (const BYTE *)value, len);
3909 else if (name)
3910 RegDeleteValueW(hkey, name);
3913 static void update_font_system_link_info(UINT current_ansi_codepage)
3915 static const WCHAR system_link_simplified_chinese[] =
3916 {'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3917 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3918 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3919 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3920 '\0'};
3921 static const WCHAR system_link_traditional_chinese[] =
3922 {'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3923 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3924 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3925 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3926 '\0'};
3927 static const WCHAR system_link_japanese[] =
3928 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3929 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3930 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3931 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3932 '\0'};
3933 static const WCHAR system_link_korean[] =
3934 {'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3935 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3936 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3937 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3938 '\0'};
3939 static const WCHAR system_link_non_cjk[] =
3940 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3941 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3942 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3943 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3944 '\0'};
3945 HKEY hkey;
3947 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
3949 const WCHAR *link;
3950 DWORD len;
3952 switch (current_ansi_codepage)
3954 case 932:
3955 link = system_link_japanese;
3956 len = sizeof(system_link_japanese);
3957 break;
3958 case 936:
3959 link = system_link_simplified_chinese;
3960 len = sizeof(system_link_simplified_chinese);
3961 break;
3962 case 949:
3963 link = system_link_korean;
3964 len = sizeof(system_link_korean);
3965 break;
3966 case 950:
3967 link = system_link_traditional_chinese;
3968 len = sizeof(system_link_traditional_chinese);
3969 break;
3970 default:
3971 link = system_link_non_cjk;
3972 len = sizeof(system_link_non_cjk);
3974 set_multi_value_key(hkey, Lucida_Sans_Unicode, link, len);
3975 set_multi_value_key(hkey, Microsoft_Sans_Serif, link, len);
3976 set_multi_value_key(hkey, Tahoma, link, len);
3977 RegCloseKey(hkey);
3981 static void update_font_info(void)
3983 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3984 char buf[40], cpbuf[40];
3985 DWORD len, type;
3986 HKEY hkey = 0;
3987 UINT i, ansi_cp = 0, oem_cp = 0;
3988 DWORD screen_dpi, font_dpi = 0;
3989 BOOL done = FALSE;
3991 screen_dpi = get_dpi();
3992 if (!screen_dpi) screen_dpi = 96;
3994 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3995 return;
3997 reg_load_dword(hkey, logpixels, &font_dpi);
3999 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
4000 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
4001 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
4002 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
4003 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
4005 /* Setup Default_Fallback usage for DBCS ANSI codepages */
4006 if (is_dbcs_ansi_cp(ansi_cp))
4007 use_default_fallback = TRUE;
4009 buf[0] = 0;
4010 len = sizeof(buf);
4011 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
4013 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
4015 RegCloseKey(hkey);
4016 return;
4018 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
4019 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
4021 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
4022 ansi_cp, oem_cp, screen_dpi);
4024 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
4025 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
4026 RegCloseKey(hkey);
4028 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
4030 HKEY hkey;
4032 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
4033 nls_update_font_list[i].oem_cp == oem_cp)
4035 hkey = create_config_fonts_registry_key();
4036 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
4037 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
4038 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
4039 RegCloseKey(hkey);
4041 hkey = create_fonts_NT_registry_key();
4042 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
4043 RegCloseKey(hkey);
4045 hkey = create_fonts_9x_registry_key();
4046 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
4047 RegCloseKey(hkey);
4049 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
4051 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
4052 strlen(nls_update_font_list[i].shelldlg)+1);
4053 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
4054 strlen(nls_update_font_list[i].tmsrmn)+1);
4056 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
4057 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
4058 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
4059 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
4060 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
4061 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
4062 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
4063 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
4065 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
4066 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
4067 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
4069 RegCloseKey(hkey);
4071 done = TRUE;
4073 else
4075 /* Delete the FontSubstitutes from other locales */
4076 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
4078 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
4079 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
4080 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
4081 RegCloseKey(hkey);
4085 if (!done)
4086 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
4088 /* update locale dependent font association info and font system link info in registry.
4089 update only when codepages changed, not logpixels. */
4090 if (strcmp(buf, cpbuf) != 0)
4092 update_font_association_info(ansi_cp);
4093 update_font_system_link_info(ansi_cp);
4097 static BOOL init_freetype(void)
4099 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
4100 if(!ft_handle) {
4101 WINE_MESSAGE(
4102 "Wine cannot find the FreeType font library. To enable Wine to\n"
4103 "use TrueType fonts please install a version of FreeType greater than\n"
4104 "or equal to 2.0.5.\n"
4105 "http://www.freetype.org\n");
4106 return FALSE;
4109 #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;}
4111 LOAD_FUNCPTR(FT_Done_Face)
4112 LOAD_FUNCPTR(FT_Get_Char_Index)
4113 LOAD_FUNCPTR(FT_Get_First_Char)
4114 LOAD_FUNCPTR(FT_Get_Next_Char)
4115 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
4116 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
4117 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
4118 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
4119 LOAD_FUNCPTR(FT_Init_FreeType)
4120 LOAD_FUNCPTR(FT_Library_Version)
4121 LOAD_FUNCPTR(FT_Load_Glyph)
4122 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
4123 LOAD_FUNCPTR(FT_Matrix_Multiply)
4124 #ifndef FT_MULFIX_INLINED
4125 LOAD_FUNCPTR(FT_MulFix)
4126 #endif
4127 LOAD_FUNCPTR(FT_New_Face)
4128 LOAD_FUNCPTR(FT_New_Memory_Face)
4129 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
4130 LOAD_FUNCPTR(FT_Outline_Get_CBox)
4131 LOAD_FUNCPTR(FT_Outline_Transform)
4132 LOAD_FUNCPTR(FT_Outline_Translate)
4133 LOAD_FUNCPTR(FT_Render_Glyph)
4134 LOAD_FUNCPTR(FT_Set_Charmap)
4135 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
4136 LOAD_FUNCPTR(FT_Vector_Length)
4137 LOAD_FUNCPTR(FT_Vector_Transform)
4138 LOAD_FUNCPTR(FT_Vector_Unit)
4139 #undef LOAD_FUNCPTR
4140 /* Don't warn if these ones are missing */
4141 pFT_Outline_Embolden = wine_dlsym(ft_handle, "FT_Outline_Embolden", NULL, 0);
4142 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
4143 #ifdef FT_LCD_FILTER_H
4144 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
4145 #endif
4147 if(pFT_Init_FreeType(&library) != 0) {
4148 ERR("Can't init FreeType library\n");
4149 wine_dlclose(ft_handle, NULL, 0);
4150 ft_handle = NULL;
4151 return FALSE;
4153 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
4155 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
4156 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
4157 ((FT_Version.minor << 8) & 0x00ff00) |
4158 ((FT_Version.patch ) & 0x0000ff);
4160 font_driver = &freetype_funcs;
4161 return TRUE;
4163 sym_not_found:
4164 WINE_MESSAGE(
4165 "Wine cannot find certain functions that it needs inside the FreeType\n"
4166 "font library. To enable Wine to use TrueType fonts please upgrade\n"
4167 "FreeType to at least version 2.1.4.\n"
4168 "http://www.freetype.org\n");
4169 wine_dlclose(ft_handle, NULL, 0);
4170 ft_handle = NULL;
4171 return FALSE;
4174 static void init_font_list(void)
4176 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
4177 static const WCHAR pathW[] = {'P','a','t','h',0};
4178 HKEY hkey;
4179 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
4180 WCHAR windowsdir[MAX_PATH];
4181 char *unixname;
4183 delete_external_font_keys();
4185 /* load the system bitmap fonts */
4186 load_system_fonts();
4188 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
4189 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
4190 strcatW(windowsdir, fontsW);
4191 if((unixname = wine_get_unix_file_name(windowsdir)))
4193 ReadFontDir(unixname, FALSE);
4194 HeapFree(GetProcessHeap(), 0, unixname);
4197 /* load the wine fonts */
4198 if ((unixname = get_font_dir()))
4200 ReadFontDir(unixname, TRUE);
4201 HeapFree(GetProcessHeap(), 0, unixname);
4204 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
4205 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
4206 full path as the entry. Also look for any .fon fonts, since ReadFontDir
4207 will skip these. */
4208 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
4209 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
4210 &hkey) == ERROR_SUCCESS)
4212 LPWSTR data, valueW;
4213 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
4214 &valuelen, &datalen, NULL, NULL);
4216 valuelen++; /* returned value doesn't include room for '\0' */
4217 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
4218 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
4219 if (valueW && data)
4221 dlen = datalen * sizeof(WCHAR);
4222 vlen = valuelen;
4223 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
4224 &dlen) == ERROR_SUCCESS)
4226 if(data[0] && (data[1] == ':'))
4228 if((unixname = wine_get_unix_file_name(data)))
4230 AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
4231 HeapFree(GetProcessHeap(), 0, unixname);
4234 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
4236 WCHAR pathW[MAX_PATH];
4237 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
4238 BOOL added = FALSE;
4240 sprintfW(pathW, fmtW, windowsdir, data);
4241 if((unixname = wine_get_unix_file_name(pathW)))
4243 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
4244 HeapFree(GetProcessHeap(), 0, unixname);
4246 if (!added)
4247 load_font_from_data_dir(data);
4249 /* reset dlen and vlen */
4250 dlen = datalen;
4251 vlen = valuelen;
4254 HeapFree(GetProcessHeap(), 0, data);
4255 HeapFree(GetProcessHeap(), 0, valueW);
4256 RegCloseKey(hkey);
4259 #ifdef SONAME_LIBFONTCONFIG
4260 load_fontconfig_fonts();
4261 #elif defined(HAVE_CARBON_CARBON_H)
4262 load_mac_fonts();
4263 #elif defined(__ANDROID__)
4264 ReadFontDir("/system/fonts", TRUE);
4265 #endif
4267 /* then look in any directories that we've specified in the config file */
4268 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
4269 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
4271 DWORD len;
4272 LPWSTR valueW;
4273 LPSTR valueA, ptr;
4275 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
4277 len += sizeof(WCHAR);
4278 valueW = HeapAlloc( GetProcessHeap(), 0, len );
4279 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
4281 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
4282 valueA = HeapAlloc( GetProcessHeap(), 0, len );
4283 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
4284 TRACE( "got font path %s\n", debugstr_a(valueA) );
4285 ptr = valueA;
4286 while (ptr)
4288 const char* home;
4289 LPSTR next = strchr( ptr, ':' );
4290 if (next) *next++ = 0;
4291 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
4292 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
4294 strcpy( unixname, home );
4295 strcat( unixname, ptr + 1 );
4296 ReadFontDir( unixname, TRUE );
4297 HeapFree( GetProcessHeap(), 0, unixname );
4299 else
4300 ReadFontDir( ptr, TRUE );
4301 ptr = next;
4303 HeapFree( GetProcessHeap(), 0, valueA );
4305 HeapFree( GetProcessHeap(), 0, valueW );
4307 RegCloseKey(hkey);
4311 static BOOL move_to_front(const WCHAR *name)
4313 Family *family, *cursor2;
4314 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
4316 if(!strncmpiW(family->FamilyName, name, LF_FACESIZE - 1))
4318 list_remove(&family->entry);
4319 list_add_head(&font_list, &family->entry);
4320 return TRUE;
4323 return FALSE;
4326 static BOOL set_default(const WCHAR **name_list)
4328 while (*name_list)
4330 if (move_to_front(*name_list)) return TRUE;
4331 name_list++;
4334 return FALSE;
4337 static void reorder_font_list(void)
4339 set_default( default_serif_list );
4340 set_default( default_fixed_list );
4341 set_default( default_sans_list );
4344 /*************************************************************
4345 * WineEngInit
4347 * Initialize FreeType library and create a list of available faces
4349 BOOL WineEngInit(void)
4351 HKEY hkey;
4352 DWORD disposition;
4353 HANDLE font_mutex;
4355 /* update locale dependent font info in registry */
4356 update_font_info();
4358 if(!init_freetype()) return FALSE;
4360 #ifdef SONAME_LIBFONTCONFIG
4361 init_fontconfig();
4362 #endif
4364 if (!RegOpenKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, KEY_READ, &hkey))
4366 static const WCHAR antialias_fake_bold_or_italic[] = { 'A','n','t','i','a','l','i','a','s','F','a','k','e',
4367 'B','o','l','d','O','r','I','t','a','l','i','c',0 };
4368 static const WCHAR true_options[] = { 'y','Y','t','T','1',0 };
4369 DWORD type, size;
4370 WCHAR buffer[20];
4372 size = sizeof(buffer);
4373 if (!RegQueryValueExW(hkey, antialias_fake_bold_or_italic, NULL, &type, (BYTE*)buffer, &size) &&
4374 type == REG_SZ && size >= 1)
4376 antialias_fakes = (strchrW(true_options, buffer[0]) != NULL);
4378 RegCloseKey(hkey);
4381 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
4383 ERR("Failed to create font mutex\n");
4384 return FALSE;
4386 WaitForSingleObject(font_mutex, INFINITE);
4388 create_font_cache_key(&hkey_font_cache, &disposition);
4390 if(disposition == REG_CREATED_NEW_KEY)
4391 init_font_list();
4392 else
4393 load_font_list_from_cache(hkey_font_cache);
4395 reorder_font_list();
4397 DumpFontList();
4398 LoadSubstList();
4399 DumpSubstList();
4400 LoadReplaceList();
4402 if(disposition == REG_CREATED_NEW_KEY)
4403 update_reg_entries();
4405 init_system_links();
4407 ReleaseMutex(font_mutex);
4408 return TRUE;
4411 /* Some fonts have large usWinDescent values, as a result of storing signed short
4412 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
4413 some font generation tools. */
4414 static inline USHORT get_fixed_windescent(USHORT windescent)
4416 return abs((SHORT)windescent);
4419 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
4421 TT_OS2 *pOS2;
4422 TT_HoriHeader *pHori;
4424 LONG ppem;
4425 const LONG MAX_PPEM = (1 << 16) - 1;
4427 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4428 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4430 if(height == 0) height = 16;
4432 /* Calc. height of EM square:
4434 * For +ve lfHeight we have
4435 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
4436 * Re-arranging gives:
4437 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4439 * For -ve lfHeight we have
4440 * |lfHeight| = ppem
4441 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4442 * with il = winAscent + winDescent - units_per_em]
4446 if(height > 0) {
4447 USHORT windescent = get_fixed_windescent(pOS2->usWinDescent);
4448 if(pOS2->usWinAscent + windescent == 0)
4449 ppem = MulDiv(ft_face->units_per_EM, height,
4450 pHori->Ascender - pHori->Descender);
4451 else
4452 ppem = MulDiv(ft_face->units_per_EM, height,
4453 pOS2->usWinAscent + windescent);
4454 if(ppem > MAX_PPEM) {
4455 WARN("Ignoring too large height %d, ppem %d\n", height, ppem);
4456 ppem = 1;
4459 else if(height >= -MAX_PPEM)
4460 ppem = -height;
4461 else {
4462 WARN("Ignoring too large height %d\n", height);
4463 ppem = 1;
4466 return ppem;
4469 static struct font_mapping *map_font_file( const char *name )
4471 struct font_mapping *mapping;
4472 struct stat st;
4473 int fd;
4475 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
4476 if (fstat( fd, &st ) == -1) goto error;
4478 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
4480 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
4482 mapping->refcount++;
4483 close( fd );
4484 return mapping;
4487 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
4488 goto error;
4490 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
4491 close( fd );
4493 if (mapping->data == MAP_FAILED)
4495 HeapFree( GetProcessHeap(), 0, mapping );
4496 return NULL;
4498 mapping->refcount = 1;
4499 mapping->dev = st.st_dev;
4500 mapping->ino = st.st_ino;
4501 mapping->size = st.st_size;
4502 list_add_tail( &mappings_list, &mapping->entry );
4503 return mapping;
4505 error:
4506 close( fd );
4507 return NULL;
4510 static void unmap_font_file( struct font_mapping *mapping )
4512 if (!--mapping->refcount)
4514 list_remove( &mapping->entry );
4515 munmap( mapping->data, mapping->size );
4516 HeapFree( GetProcessHeap(), 0, mapping );
4520 static LONG load_VDMX(GdiFont*, LONG);
4522 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
4524 FT_Error err;
4525 FT_Face ft_face;
4526 void *data_ptr;
4527 DWORD data_size;
4529 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
4531 if (face->file)
4533 char *filename = strWtoA( CP_UNIXCP, face->file );
4534 font->mapping = map_font_file( filename );
4535 HeapFree( GetProcessHeap(), 0, filename );
4536 if (!font->mapping)
4538 WARN("failed to map %s\n", debugstr_w(face->file));
4539 return 0;
4541 data_ptr = font->mapping->data;
4542 data_size = font->mapping->size;
4544 else
4546 data_ptr = face->font_data_ptr;
4547 data_size = face->font_data_size;
4550 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
4551 if(err) {
4552 ERR("FT_New_Face rets %d\n", err);
4553 return 0;
4556 /* set it here, as load_VDMX needs it */
4557 font->ft_face = ft_face;
4559 if(FT_IS_SCALABLE(ft_face)) {
4560 FT_ULong len;
4561 DWORD header;
4563 /* load the VDMX table if we have one */
4564 font->ppem = load_VDMX(font, height);
4565 if(font->ppem == 0)
4566 font->ppem = calc_ppem_for_height(ft_face, height);
4567 TRACE("height %d => ppem %d\n", height, font->ppem);
4569 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
4570 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
4572 /* see if it's a TTC */
4573 len = sizeof(header);
4574 if (!pFT_Load_Sfnt_Table(ft_face, 0, 0, (void*)&header, &len)) {
4575 if (header == MS_TTCF_TAG)
4577 len = sizeof(font->ttc_item_offset);
4578 if (pFT_Load_Sfnt_Table(ft_face, 0, (3 + face->face_index) * sizeof(DWORD),
4579 (void*)&font->ttc_item_offset, &len))
4580 font->ttc_item_offset = 0;
4581 else
4582 font->ttc_item_offset = GET_BE_DWORD(font->ttc_item_offset);
4585 } else {
4586 font->ppem = height;
4587 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
4588 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
4590 return ft_face;
4594 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
4596 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4597 a single face with the requested charset. The idea is to check if
4598 the selected font supports the current ANSI codepage, if it does
4599 return the corresponding charset, else return the first charset */
4601 CHARSETINFO csi;
4602 int acp = GetACP(), i;
4603 DWORD fs0;
4605 *cp = acp;
4606 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
4608 const SYSTEM_LINKS *font_link;
4610 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4611 return csi.ciCharset;
4613 font_link = find_font_link(family_name);
4614 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4615 return csi.ciCharset;
4618 for(i = 0; i < 32; i++) {
4619 fs0 = 1L << i;
4620 if(face->fs.fsCsb[0] & fs0) {
4621 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4622 *cp = csi.ciACP;
4623 return csi.ciCharset;
4625 else
4626 FIXME("TCI failing on %x\n", fs0);
4630 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4631 face->fs.fsCsb[0], debugstr_w(face->file));
4632 *cp = acp;
4633 return DEFAULT_CHARSET;
4636 static GdiFont *alloc_font(void)
4638 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4639 ret->refcount = 1;
4640 ret->gmsize = 1;
4641 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4642 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4643 ret->potm = NULL;
4644 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4645 ret->total_kern_pairs = (DWORD)-1;
4646 ret->kern_pairs = NULL;
4647 ret->instance_id = alloc_font_handle(ret);
4648 list_init(&ret->child_fonts);
4649 return ret;
4652 static void free_font(GdiFont *font)
4654 CHILD_FONT *child, *child_next;
4655 DWORD i;
4657 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
4659 list_remove(&child->entry);
4660 if(child->font)
4661 free_font(child->font);
4662 release_face( child->face );
4663 HeapFree(GetProcessHeap(), 0, child);
4666 HeapFree(GetProcessHeap(), 0, font->fileinfo);
4667 free_font_handle(font->instance_id);
4668 if (font->ft_face) pFT_Done_Face(font->ft_face);
4669 if (font->mapping) unmap_font_file( font->mapping );
4670 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4671 HeapFree(GetProcessHeap(), 0, font->potm);
4672 HeapFree(GetProcessHeap(), 0, font->name);
4673 for (i = 0; i < font->gmsize; i++)
4674 HeapFree(GetProcessHeap(),0,font->gm[i]);
4675 HeapFree(GetProcessHeap(), 0, font->gm);
4676 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4677 HeapFree(GetProcessHeap(), 0, font);
4681 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4683 FT_Face ft_face = font->ft_face;
4684 FT_ULong len;
4685 FT_Error err;
4687 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4689 if(!buf)
4690 len = 0;
4691 else
4692 len = cbData;
4694 /* if font is a member of TTC, 'ttcf' tag allows reading from beginning of TTC file,
4695 0 tag means to read from start of collection member data. */
4696 if (font->ttc_item_offset)
4698 if (table == MS_TTCF_TAG)
4699 table = 0;
4700 else if (table == 0)
4701 offset += font->ttc_item_offset;
4704 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4706 /* make sure value of len is the value freetype says it needs */
4707 if (buf && len)
4709 FT_ULong needed = 0;
4710 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4711 if( !err && needed < len) len = needed;
4713 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4714 if (err)
4716 table = RtlUlongByteSwap( table );
4717 TRACE("Can't find table %s\n", debugstr_an((char*)&table, 4));
4718 return GDI_ERROR;
4720 return len;
4723 /*************************************************************
4724 * load_VDMX
4726 * load the vdmx entry for the specified height
4731 typedef struct {
4732 WORD version;
4733 WORD numRecs;
4734 WORD numRatios;
4735 } VDMX_Header;
4737 typedef struct {
4738 BYTE bCharSet;
4739 BYTE xRatio;
4740 BYTE yStartRatio;
4741 BYTE yEndRatio;
4742 } Ratios;
4744 typedef struct {
4745 WORD recs;
4746 BYTE startsz;
4747 BYTE endsz;
4748 } VDMX_group;
4750 typedef struct {
4751 WORD yPelHeight;
4752 WORD yMax;
4753 WORD yMin;
4754 } VDMX_vTable;
4756 static LONG load_VDMX(GdiFont *font, LONG height)
4758 VDMX_Header hdr;
4759 VDMX_group group;
4760 BYTE devXRatio, devYRatio;
4761 USHORT numRecs, numRatios;
4762 DWORD result, offset = -1;
4763 LONG ppem = 0;
4764 int i;
4766 result = get_font_data(font, MS_VDMX_TAG, 0, &hdr, sizeof(hdr));
4768 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4769 return ppem;
4771 /* FIXME: need the real device aspect ratio */
4772 devXRatio = 1;
4773 devYRatio = 1;
4775 numRecs = GET_BE_WORD(hdr.numRecs);
4776 numRatios = GET_BE_WORD(hdr.numRatios);
4778 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr.version), numRecs, numRatios);
4779 for(i = 0; i < numRatios; i++) {
4780 Ratios ratio;
4782 offset = sizeof(hdr) + (i * sizeof(Ratios));
4783 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4784 offset = -1;
4786 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4788 if (!ratio.bCharSet) continue;
4790 if((ratio.xRatio == 0 &&
4791 ratio.yStartRatio == 0 &&
4792 ratio.yEndRatio == 0) ||
4793 (devXRatio == ratio.xRatio &&
4794 devYRatio >= ratio.yStartRatio &&
4795 devYRatio <= ratio.yEndRatio))
4797 WORD group_offset;
4799 offset = sizeof(hdr) + numRatios * sizeof(ratio) + i * sizeof(group_offset);
4800 get_font_data(font, MS_VDMX_TAG, offset, &group_offset, sizeof(group_offset));
4801 offset = GET_BE_WORD(group_offset);
4802 break;
4806 if(offset == -1) return 0;
4808 if(get_font_data(font, MS_VDMX_TAG, offset, &group, sizeof(group)) != GDI_ERROR) {
4809 USHORT recs;
4810 BYTE startsz, endsz;
4811 WORD *vTable;
4813 recs = GET_BE_WORD(group.recs);
4814 startsz = group.startsz;
4815 endsz = group.endsz;
4817 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4819 vTable = HeapAlloc(GetProcessHeap(), 0, recs * sizeof(VDMX_vTable));
4820 result = get_font_data(font, MS_VDMX_TAG, offset + sizeof(group), vTable, recs * sizeof(VDMX_vTable));
4821 if(result == GDI_ERROR) {
4822 FIXME("Failed to retrieve vTable\n");
4823 goto end;
4826 if(height > 0) {
4827 for(i = 0; i < recs; i++) {
4828 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4829 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4830 ppem = GET_BE_WORD(vTable[i * 3]);
4832 if(yMax + -yMin == height) {
4833 font->yMax = yMax;
4834 font->yMin = yMin;
4835 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4836 break;
4838 if(yMax + -yMin > height) {
4839 if(--i < 0) {
4840 ppem = 0;
4841 goto end; /* failed */
4843 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4844 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4845 ppem = GET_BE_WORD(vTable[i * 3]);
4846 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4847 break;
4850 if(!font->yMax) {
4851 ppem = 0;
4852 TRACE("ppem not found for height %d\n", height);
4854 } else {
4855 ppem = -height;
4856 if(ppem < startsz || ppem > endsz)
4858 ppem = 0;
4859 goto end;
4862 for(i = 0; i < recs; i++) {
4863 USHORT yPelHeight;
4864 yPelHeight = GET_BE_WORD(vTable[i * 3]);
4866 if(yPelHeight > ppem)
4868 ppem = 0;
4869 break; /* failed */
4872 if(yPelHeight == ppem) {
4873 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4874 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4875 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
4876 break;
4880 end:
4881 HeapFree(GetProcessHeap(), 0, vTable);
4884 return ppem;
4887 static void dump_gdi_font_list(void)
4889 GdiFont *font;
4891 TRACE("---------- Font Cache ----------\n");
4892 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct tagGdiFont, entry )
4893 TRACE("font=%p ref=%u %s %d\n", font, font->refcount,
4894 debugstr_w(font->font_desc.lf.lfFaceName), font->font_desc.lf.lfHeight);
4897 static void grab_font( GdiFont *font )
4899 if (!font->refcount++)
4901 list_remove( &font->unused_entry );
4902 unused_font_count--;
4906 static void release_font( GdiFont *font )
4908 if (!font) return;
4909 if (!--font->refcount)
4911 TRACE( "font %p\n", font );
4913 /* add it to the unused list */
4914 list_add_head( &unused_gdi_font_list, &font->unused_entry );
4915 if (unused_font_count > UNUSED_CACHE_SIZE)
4917 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct tagGdiFont, unused_entry );
4918 TRACE( "freeing %p\n", font );
4919 list_remove( &font->entry );
4920 list_remove( &font->unused_entry );
4921 free_font( font );
4923 else unused_font_count++;
4925 if (TRACE_ON(font)) dump_gdi_font_list();
4929 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4931 if(font->font_desc.hash != fd->hash) return TRUE;
4932 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4933 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4934 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4935 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4938 static void calc_hash(FONT_DESC *pfd)
4940 DWORD hash = 0, *ptr, two_chars;
4941 WORD *pwc;
4942 unsigned int i;
4944 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4945 hash ^= *ptr;
4946 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4947 hash ^= *ptr;
4948 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4949 two_chars = *ptr;
4950 pwc = (WCHAR *)&two_chars;
4951 if(!*pwc) break;
4952 *pwc = toupperW(*pwc);
4953 pwc++;
4954 *pwc = toupperW(*pwc);
4955 hash ^= two_chars;
4956 if(!*pwc) break;
4958 hash ^= !pfd->can_use_bitmap;
4959 pfd->hash = hash;
4962 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4964 GdiFont *ret;
4965 FONT_DESC fd;
4967 fd.lf = *plf;
4968 fd.matrix = *pmat;
4969 fd.can_use_bitmap = can_use_bitmap;
4970 calc_hash(&fd);
4972 /* try the in-use list */
4973 LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
4975 if(fontcmp(ret, &fd)) continue;
4976 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4977 list_remove( &ret->entry );
4978 list_add_head( &gdi_font_list, &ret->entry );
4979 grab_font( ret );
4980 return ret;
4982 return NULL;
4985 static void add_to_cache(GdiFont *font)
4987 static DWORD cache_num = 1;
4989 font->cache_num = cache_num++;
4990 list_add_head(&gdi_font_list, &font->entry);
4991 TRACE( "font %p\n", font );
4994 /*************************************************************
4995 * create_child_font_list
4997 static BOOL create_child_font_list(GdiFont *font)
4999 BOOL ret = FALSE;
5000 SYSTEM_LINKS *font_link;
5001 CHILD_FONT *font_link_entry, *new_child;
5002 FontSubst *psub;
5003 WCHAR* font_name;
5005 psub = get_font_subst(&font_subst_list, font->name, -1);
5006 font_name = psub ? psub->to.name : font->name;
5007 font_link = find_font_link(font_name);
5008 if (font_link != NULL)
5010 TRACE("found entry in system list\n");
5011 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5013 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
5014 new_child->face = font_link_entry->face;
5015 new_child->font = NULL;
5016 new_child->face->refcount++;
5017 list_add_tail(&font->child_fonts, &new_child->entry);
5018 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
5020 ret = TRUE;
5023 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
5024 * Sans Serif. This is how asian windows get default fallbacks for fonts
5026 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
5027 font->charset != OEM_CHARSET &&
5028 strcmpiW(font_name,szDefaultFallbackLink) != 0)
5030 font_link = find_font_link(szDefaultFallbackLink);
5031 if (font_link != NULL)
5033 TRACE("found entry in default fallback list\n");
5034 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5036 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
5037 new_child->face = font_link_entry->face;
5038 new_child->font = NULL;
5039 new_child->face->refcount++;
5040 list_add_tail(&font->child_fonts, &new_child->entry);
5041 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
5043 ret = TRUE;
5047 return ret;
5050 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
5052 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
5053 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
5054 FT_Int i;
5056 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
5058 for (i = 0; i < ft_face->num_charmaps; i++)
5060 if (ft_face->charmaps[i]->encoding == encoding)
5062 TRACE("found cmap with platform_id %u, encoding_id %u\n",
5063 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
5065 switch (ft_face->charmaps[i]->platform_id)
5067 default:
5068 cmap_def = ft_face->charmaps[i];
5069 break;
5070 case 0: /* Apple Unicode */
5071 cmap0 = ft_face->charmaps[i];
5072 break;
5073 case 1: /* Macintosh */
5074 cmap1 = ft_face->charmaps[i];
5075 break;
5076 case 2: /* ISO */
5077 cmap2 = ft_face->charmaps[i];
5078 break;
5079 case 3: /* Microsoft */
5080 cmap3 = ft_face->charmaps[i];
5081 break;
5085 if (cmap3) /* prefer Microsoft cmap table */
5086 ft_err = pFT_Set_Charmap(ft_face, cmap3);
5087 else if (cmap1)
5088 ft_err = pFT_Set_Charmap(ft_face, cmap1);
5089 else if (cmap2)
5090 ft_err = pFT_Set_Charmap(ft_face, cmap2);
5091 else if (cmap0)
5092 ft_err = pFT_Set_Charmap(ft_face, cmap0);
5093 else if (cmap_def)
5094 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
5097 return ft_err == FT_Err_Ok;
5101 /*************************************************************
5102 * freetype_CreateDC
5104 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
5105 LPCWSTR output, const DEVMODEW *devmode )
5107 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
5109 if (!physdev) return FALSE;
5110 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
5111 return TRUE;
5115 /*************************************************************
5116 * freetype_DeleteDC
5118 static BOOL freetype_DeleteDC( PHYSDEV dev )
5120 struct freetype_physdev *physdev = get_freetype_dev( dev );
5121 release_font( physdev->font );
5122 HeapFree( GetProcessHeap(), 0, physdev );
5123 return TRUE;
5126 static FT_Encoding pick_charmap( FT_Face face, int charset )
5128 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
5129 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
5130 const FT_Encoding *encs = regular_order;
5132 if (charset == SYMBOL_CHARSET) encs = symbol_order;
5134 while (*encs != 0)
5136 if (select_charmap( face, *encs )) break;
5137 encs++;
5140 if (!face->charmap && face->num_charmaps)
5142 if (!pFT_Set_Charmap(face, face->charmaps[0]))
5143 return face->charmap->encoding;
5146 return *encs;
5149 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
5151 DWORD size;
5152 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
5153 WORD *alloced = NULL, *ptr = buf;
5154 WORD num_recs, version;
5155 BOOL ret = FALSE;
5157 *flags = 0;
5158 size = get_font_data( font, MS_GASP_TAG, 0, NULL, 0 );
5159 if (size == GDI_ERROR) return FALSE;
5160 if (size < 4 * sizeof(WORD)) return FALSE;
5161 if (size > sizeof(buf))
5163 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
5164 if (!ptr) return FALSE;
5167 get_font_data( font, MS_GASP_TAG, 0, ptr, size );
5169 version = GET_BE_WORD( *ptr++ );
5170 num_recs = GET_BE_WORD( *ptr++ );
5172 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
5174 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
5175 goto done;
5178 while (num_recs--)
5180 *flags = GET_BE_WORD( *(ptr + 1) );
5181 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
5182 ptr += 2;
5184 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
5185 ret = TRUE;
5187 done:
5188 HeapFree( GetProcessHeap(), 0, alloced );
5189 return ret;
5192 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5194 const GSUB_ScriptList *script;
5195 const GSUB_Script *deflt = NULL;
5196 int i;
5197 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5199 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5200 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5202 const GSUB_Script *scr;
5203 int offset;
5205 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5206 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5208 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5209 return scr;
5210 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5211 deflt = scr;
5213 return deflt;
5216 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5218 int i;
5219 int offset;
5220 const GSUB_LangSys *Lang;
5222 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5224 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5226 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5227 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5229 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5230 return Lang;
5232 offset = GET_BE_WORD(script->DefaultLangSys);
5233 if (offset)
5235 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5236 return Lang;
5238 return NULL;
5241 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5243 int i;
5244 const GSUB_FeatureList *feature;
5245 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5247 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5248 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5250 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5251 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5253 const GSUB_Feature *feat;
5254 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5255 return feat;
5258 return NULL;
5261 static const char* get_opentype_script(const GdiFont *font)
5264 * I am not sure if this is the correct way to generate our script tag
5267 switch (font->charset)
5269 case ANSI_CHARSET: return "latn";
5270 case BALTIC_CHARSET: return "latn"; /* ?? */
5271 case CHINESEBIG5_CHARSET: return "hani";
5272 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5273 case GB2312_CHARSET: return "hani";
5274 case GREEK_CHARSET: return "grek";
5275 case HANGUL_CHARSET: return "hang";
5276 case RUSSIAN_CHARSET: return "cyrl";
5277 case SHIFTJIS_CHARSET: return "kana";
5278 case TURKISH_CHARSET: return "latn"; /* ?? */
5279 case VIETNAMESE_CHARSET: return "latn";
5280 case JOHAB_CHARSET: return "latn"; /* ?? */
5281 case ARABIC_CHARSET: return "arab";
5282 case HEBREW_CHARSET: return "hebr";
5283 case THAI_CHARSET: return "thai";
5284 default: return "latn";
5288 static const VOID * get_GSUB_vert_feature(const GdiFont *font)
5290 const GSUB_Header *header;
5291 const GSUB_Script *script;
5292 const GSUB_LangSys *language;
5293 const GSUB_Feature *feature;
5295 if (!font->GSUB_Table)
5296 return NULL;
5298 header = font->GSUB_Table;
5300 script = GSUB_get_script_table(header, get_opentype_script(font));
5301 if (!script)
5303 TRACE("Script not found\n");
5304 return NULL;
5306 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5307 if (!language)
5309 TRACE("Language not found\n");
5310 return NULL;
5312 feature = GSUB_get_feature(header, language, "vrt2");
5313 if (!feature)
5314 feature = GSUB_get_feature(header, language, "vert");
5315 if (!feature)
5317 TRACE("vrt2/vert feature not found\n");
5318 return NULL;
5320 return feature;
5323 static void fill_fileinfo_from_face( GdiFont *font, Face *face )
5325 WIN32_FILE_ATTRIBUTE_DATA info;
5326 int len;
5328 if (!face->file)
5330 font->fileinfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*font->fileinfo));
5331 return;
5334 len = strlenW(face->file);
5335 font->fileinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*font->fileinfo) + len * sizeof(WCHAR));
5336 if (GetFileAttributesExW(face->file, GetFileExInfoStandard, &info))
5338 font->fileinfo->writetime = info.ftLastWriteTime;
5339 font->fileinfo->size.QuadPart = (LONGLONG)info.nFileSizeHigh << 32 | info.nFileSizeLow;
5340 strcpyW(font->fileinfo->path, face->file);
5342 else
5343 memset(font->fileinfo, 0, sizeof(*font->fileinfo) + len * sizeof(WCHAR));
5346 /*************************************************************
5347 * freetype_SelectFont
5349 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
5351 struct freetype_physdev *physdev = get_freetype_dev( dev );
5352 GdiFont *ret;
5353 Face *face, *best, *best_bitmap;
5354 Family *family, *last_resort_family;
5355 const struct list *face_list;
5356 INT height, width = 0;
5357 unsigned int score = 0, new_score;
5358 signed int diff = 0, newdiff;
5359 BOOL bd, it, can_use_bitmap, want_vertical;
5360 LOGFONTW lf;
5361 CHARSETINFO csi;
5362 FMAT2 dcmat;
5363 FontSubst *psub = NULL;
5364 DC *dc = get_physdev_dc( dev );
5365 const SYSTEM_LINKS *font_link;
5367 if (!hfont) /* notification that the font has been changed by another driver */
5369 release_font( physdev->font );
5370 physdev->font = NULL;
5371 return 0;
5374 GetObjectW( hfont, sizeof(lf), &lf );
5375 lf.lfWidth = abs(lf.lfWidth);
5377 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
5379 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
5380 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
5381 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
5382 lf.lfEscapement);
5384 if(dc->GraphicsMode == GM_ADVANCED)
5386 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
5387 /* Try to avoid not necessary glyph transformations */
5388 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
5390 lf.lfHeight *= fabs(dcmat.eM11);
5391 lf.lfWidth *= fabs(dcmat.eM11);
5392 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
5395 else
5397 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
5398 font scaling abilities. */
5399 dcmat.eM11 = dcmat.eM22 = 1.0;
5400 dcmat.eM21 = dcmat.eM12 = 0;
5401 lf.lfOrientation = lf.lfEscapement;
5402 if (dc->vport2WorldValid)
5404 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
5405 lf.lfOrientation = -lf.lfOrientation;
5406 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
5407 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
5411 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
5412 dcmat.eM21, dcmat.eM22);
5414 GDI_CheckNotLock();
5415 EnterCriticalSection( &freetype_cs );
5417 /* check the cache first */
5418 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5419 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
5420 goto done;
5423 TRACE("not in cache\n");
5424 ret = alloc_font();
5426 ret->font_desc.matrix = dcmat;
5427 ret->font_desc.lf = lf;
5428 ret->font_desc.can_use_bitmap = can_use_bitmap;
5429 calc_hash(&ret->font_desc);
5431 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
5432 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
5433 original value lfCharSet. Note this is a special case for
5434 Symbol and doesn't happen at least for "Wingdings*" */
5436 if(!strcmpiW(lf.lfFaceName, SymbolW))
5437 lf.lfCharSet = SYMBOL_CHARSET;
5439 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
5440 switch(lf.lfCharSet) {
5441 case DEFAULT_CHARSET:
5442 csi.fs.fsCsb[0] = 0;
5443 break;
5444 default:
5445 FIXME("Untranslated charset %d\n", lf.lfCharSet);
5446 csi.fs.fsCsb[0] = 0;
5447 break;
5451 family = NULL;
5452 if(lf.lfFaceName[0] != '\0') {
5453 CHILD_FONT *font_link_entry;
5454 LPWSTR FaceName = lf.lfFaceName;
5456 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
5458 if(psub) {
5459 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
5460 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
5461 if (psub->to.charset != -1)
5462 lf.lfCharSet = psub->to.charset;
5465 /* We want a match on name and charset or just name if
5466 charset was DEFAULT_CHARSET. If the latter then
5467 we fixup the returned charset later in get_nearest_charset
5468 where we'll either use the charset of the current ansi codepage
5469 or if that's unavailable the first charset that the font supports.
5471 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5472 if (!strncmpiW(family->FamilyName, FaceName, LF_FACESIZE - 1) ||
5473 (psub && !strncmpiW(family->FamilyName, psub->to.name, LF_FACESIZE - 1)))
5475 font_link = find_font_link(family->FamilyName);
5476 face_list = get_face_list_from_family(family);
5477 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5478 if (!(face->scalable || can_use_bitmap))
5479 continue;
5480 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5481 goto found;
5482 if (font_link != NULL &&
5483 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5484 goto found;
5485 if (!csi.fs.fsCsb[0])
5486 goto found;
5491 /* Search by full face name. */
5492 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5493 face_list = get_face_list_from_family(family);
5494 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5495 if(face->FullName && !strncmpiW(face->FullName, FaceName, LF_FACESIZE - 1) &&
5496 (face->scalable || can_use_bitmap))
5498 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5499 goto found_face;
5500 font_link = find_font_link(family->FamilyName);
5501 if (font_link != NULL &&
5502 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5503 goto found_face;
5509 * Try check the SystemLink list first for a replacement font.
5510 * We may find good replacements there.
5512 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
5514 if(!strncmpiW(font_link->font_name, FaceName, LF_FACESIZE - 1) ||
5515 (psub && !strncmpiW(font_link->font_name,psub->to.name, LF_FACESIZE - 1)))
5517 TRACE("found entry in system list\n");
5518 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5520 const SYSTEM_LINKS *links;
5522 face = font_link_entry->face;
5523 if (!(face->scalable || can_use_bitmap))
5524 continue;
5525 family = face->family;
5526 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5527 goto found;
5528 links = find_font_link(family->FamilyName);
5529 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
5530 goto found;
5536 psub = NULL; /* substitution is no more relevant */
5538 /* If requested charset was DEFAULT_CHARSET then try using charset
5539 corresponding to the current ansi codepage */
5540 if (!csi.fs.fsCsb[0])
5542 INT acp = GetACP();
5543 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
5544 FIXME("TCI failed on codepage %d\n", acp);
5545 csi.fs.fsCsb[0] = 0;
5546 } else
5547 lf.lfCharSet = csi.ciCharset;
5550 want_vertical = (lf.lfFaceName[0] == '@');
5552 /* Face families are in the top 4 bits of lfPitchAndFamily,
5553 so mask with 0xF0 before testing */
5555 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
5556 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
5557 strcpyW(lf.lfFaceName, defFixed);
5558 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
5559 strcpyW(lf.lfFaceName, defSerif);
5560 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
5561 strcpyW(lf.lfFaceName, defSans);
5562 else
5563 strcpyW(lf.lfFaceName, defSans);
5564 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5565 if(!strncmpiW(family->FamilyName, lf.lfFaceName, LF_FACESIZE - 1)) {
5566 font_link = find_font_link(family->FamilyName);
5567 face_list = get_face_list_from_family(family);
5568 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5569 if (!(face->scalable || can_use_bitmap))
5570 continue;
5571 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5572 goto found;
5573 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5574 goto found;
5579 last_resort_family = NULL;
5580 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5581 font_link = find_font_link(family->FamilyName);
5582 face_list = get_face_list_from_family(family);
5583 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5584 if(!(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical &&
5585 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5586 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
5587 if(face->scalable)
5588 goto found;
5589 if(can_use_bitmap && !last_resort_family)
5590 last_resort_family = family;
5595 if(last_resort_family) {
5596 family = last_resort_family;
5597 csi.fs.fsCsb[0] = 0;
5598 goto found;
5601 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5602 face_list = get_face_list_from_family(family);
5603 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5604 if(face->scalable && !(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical) {
5605 csi.fs.fsCsb[0] = 0;
5606 WARN("just using first face for now\n");
5607 goto found;
5609 if(can_use_bitmap && !last_resort_family)
5610 last_resort_family = family;
5613 if(!last_resort_family) {
5614 FIXME("can't find a single appropriate font - bailing\n");
5615 free_font(ret);
5616 ret = NULL;
5617 goto done;
5620 WARN("could only find a bitmap font - this will probably look awful!\n");
5621 family = last_resort_family;
5622 csi.fs.fsCsb[0] = 0;
5624 found:
5625 it = lf.lfItalic ? 1 : 0;
5626 bd = lf.lfWeight > 550 ? 1 : 0;
5628 height = lf.lfHeight;
5630 face = best = best_bitmap = NULL;
5631 font_link = find_font_link(family->FamilyName);
5632 face_list = get_face_list_from_family(family);
5633 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5635 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5636 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
5637 !csi.fs.fsCsb[0])
5639 BOOL italic, bold;
5641 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
5642 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
5643 new_score = (italic ^ it) + (bold ^ bd);
5644 if(!best || new_score <= score)
5646 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5647 italic, bold, it, bd);
5648 score = new_score;
5649 best = face;
5650 if(best->scalable && score == 0) break;
5651 if(!best->scalable)
5653 if(height > 0)
5654 newdiff = height - (signed int)(best->size.height);
5655 else
5656 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
5657 if(!best_bitmap || new_score < score ||
5658 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
5660 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
5661 diff = newdiff;
5662 best_bitmap = best;
5663 if(score == 0 && diff == 0) break;
5669 if(best)
5670 face = best->scalable ? best : best_bitmap;
5671 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
5672 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
5674 found_face:
5675 height = lf.lfHeight;
5677 ret->fs = face->fs;
5679 if(csi.fs.fsCsb[0]) {
5680 ret->charset = lf.lfCharSet;
5681 ret->codepage = csi.ciACP;
5683 else
5684 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
5686 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
5687 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
5689 ret->aveWidth = height ? lf.lfWidth : 0;
5691 if(!face->scalable) {
5692 /* Windows uses integer scaling factors for bitmap fonts */
5693 INT scale, scaled_height;
5694 GdiFont *cachedfont;
5696 /* FIXME: rotation of bitmap fonts is ignored */
5697 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
5698 if (ret->aveWidth)
5699 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
5700 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
5701 dcmat.eM11 = dcmat.eM22 = 1.0;
5702 /* As we changed the matrix, we need to search the cache for the font again,
5703 * otherwise we might explode the cache. */
5704 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5705 TRACE("Found cached font after non-scalable matrix rescale!\n");
5706 free_font( ret );
5707 ret = cachedfont;
5708 goto done;
5710 calc_hash(&ret->font_desc);
5712 if (height != 0) height = diff;
5713 height += face->size.height;
5715 scale = (height + face->size.height - 1) / face->size.height;
5716 scaled_height = scale * face->size.height;
5717 /* Only jump to the next height if the difference <= 25% original height */
5718 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
5719 /* The jump between unscaled and doubled is delayed by 1 */
5720 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
5721 ret->scale_y = scale;
5723 width = face->size.x_ppem >> 6;
5724 height = face->size.y_ppem >> 6;
5726 else
5727 ret->scale_y = 1.0;
5728 TRACE("font scale y: %f\n", ret->scale_y);
5730 ret->ft_face = OpenFontFace(ret, face, width, height);
5732 if (!ret->ft_face)
5734 free_font( ret );
5735 ret = NULL;
5736 goto done;
5739 fill_fileinfo_from_face( ret, face );
5740 ret->ntmFlags = face->ntmFlags;
5742 pick_charmap( ret->ft_face, ret->charset );
5744 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
5745 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
5746 ret->underline = lf.lfUnderline ? 0xff : 0;
5747 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
5748 create_child_font_list(ret);
5750 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
5752 int length = get_font_data(ret, MS_GSUB_TAG , 0, NULL, 0);
5753 if (length != GDI_ERROR)
5755 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
5756 get_font_data(ret, MS_GSUB_TAG , 0, ret->GSUB_Table, length);
5757 TRACE("Loaded GSUB table of %i bytes\n",length);
5758 ret->vert_feature = get_GSUB_vert_feature(ret);
5759 if (!ret->vert_feature)
5761 TRACE("Vertical feature not found\n");
5762 HeapFree(GetProcessHeap(), 0, ret->GSUB_Table);
5763 ret->GSUB_Table = NULL;
5767 ret->aa_flags = HIWORD( face->flags );
5769 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
5771 add_to_cache(ret);
5772 done:
5773 if (ret)
5775 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
5777 switch (lf.lfQuality)
5779 case NONANTIALIASED_QUALITY:
5780 case ANTIALIASED_QUALITY:
5781 next->funcs->pSelectFont( dev, hfont, aa_flags );
5782 break;
5783 case CLEARTYPE_QUALITY:
5784 case CLEARTYPE_NATURAL_QUALITY:
5785 default:
5786 if (!*aa_flags) *aa_flags = ret->aa_flags;
5787 next->funcs->pSelectFont( dev, hfont, aa_flags );
5789 /* fixup the antialiasing flags for that font */
5790 switch (*aa_flags)
5792 case WINE_GGO_HRGB_BITMAP:
5793 case WINE_GGO_HBGR_BITMAP:
5794 case WINE_GGO_VRGB_BITMAP:
5795 case WINE_GGO_VBGR_BITMAP:
5796 if (is_subpixel_rendering_enabled()) break;
5797 *aa_flags = GGO_GRAY4_BITMAP;
5798 /* fall through */
5799 case GGO_GRAY2_BITMAP:
5800 case GGO_GRAY4_BITMAP:
5801 case GGO_GRAY8_BITMAP:
5802 case WINE_GGO_GRAY16_BITMAP:
5803 if ((!antialias_fakes || (!ret->fake_bold && !ret->fake_italic)) && is_hinting_enabled())
5805 WORD gasp_flags;
5806 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
5808 TRACE( "font %s %d aa disabled by GASP\n",
5809 debugstr_w(lf.lfFaceName), lf.lfHeight );
5810 *aa_flags = GGO_BITMAP;
5815 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5816 release_font( physdev->font );
5817 physdev->font = ret;
5819 LeaveCriticalSection( &freetype_cs );
5820 return ret ? hfont : 0;
5823 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5825 HRSRC rsrc;
5826 HGLOBAL hMem;
5827 WCHAR *p;
5828 int i;
5830 id += IDS_FIRST_SCRIPT;
5831 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5832 if (!rsrc) return 0;
5833 hMem = LoadResource( gdi32_module, rsrc );
5834 if (!hMem) return 0;
5836 p = LockResource( hMem );
5837 id &= 0x000f;
5838 while (id--) p += *p + 1;
5840 i = min(LF_FACESIZE - 1, *p);
5841 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5842 buffer[i] = 0;
5843 return i;
5846 static inline BOOL is_complex_script_ansi_cp(UINT ansi_cp)
5848 return (ansi_cp == 874 /* Thai */
5849 || ansi_cp == 1255 /* Hebrew */
5850 || ansi_cp == 1256 /* Arabic */
5854 /***************************************************
5855 * create_enum_charset_list
5857 * This function creates charset enumeration list because in DEFAULT_CHARSET
5858 * case, the ANSI codepage's charset takes precedence over other charsets.
5859 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
5860 * This function works as a filter other than DEFAULT_CHARSET case.
5862 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5864 CHARSETINFO csi;
5865 DWORD n = 0;
5867 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5868 csi.fs.fsCsb[0] != 0) {
5869 list->element[n].mask = csi.fs.fsCsb[0];
5870 list->element[n].charset = csi.ciCharset;
5871 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5872 n++;
5874 else { /* charset is DEFAULT_CHARSET or invalid. */
5875 INT acp, i;
5876 DWORD mask = 0;
5878 /* Set the current codepage's charset as the first element. */
5879 acp = GetACP();
5880 if (!is_complex_script_ansi_cp(acp) &&
5881 TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5882 csi.fs.fsCsb[0] != 0) {
5883 list->element[n].mask = csi.fs.fsCsb[0];
5884 list->element[n].charset = csi.ciCharset;
5885 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5886 mask |= csi.fs.fsCsb[0];
5887 n++;
5890 /* Fill out left elements. */
5891 for (i = 0; i < 32; i++) {
5892 FONTSIGNATURE fs;
5893 fs.fsCsb[0] = 1L << i;
5894 fs.fsCsb[1] = 0;
5895 if (fs.fsCsb[0] & mask)
5896 continue; /* skip, already added. */
5897 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5898 continue; /* skip, this is an invalid fsCsb bit. */
5900 list->element[n].mask = fs.fsCsb[0];
5901 list->element[n].charset = csi.ciCharset;
5902 load_script_name( i, list->element[n].name );
5903 mask |= fs.fsCsb[0];
5904 n++;
5907 /* add catch all mask for remaining bits */
5908 if (~mask)
5910 list->element[n].mask = ~mask;
5911 list->element[n].charset = DEFAULT_CHARSET;
5912 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5913 n++;
5916 list->total = n;
5918 return n;
5921 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
5922 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5924 GdiFont *font;
5925 LONG width, height;
5927 if (face->cached_enum_data)
5929 TRACE("Cached\n");
5930 *pelf = face->cached_enum_data->elf;
5931 *pntm = face->cached_enum_data->ntm;
5932 *ptype = face->cached_enum_data->type;
5933 return;
5936 font = alloc_font();
5938 if(face->scalable) {
5939 height = 100;
5940 width = 0;
5941 } else {
5942 height = face->size.y_ppem >> 6;
5943 width = face->size.x_ppem >> 6;
5945 font->scale_y = 1.0;
5947 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5949 free_font(font);
5950 return;
5953 font->name = strdupW( family_name );
5954 font->ntmFlags = face->ntmFlags;
5956 if (get_outline_text_metrics(font))
5958 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5960 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5961 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5962 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5964 lstrcpynW(pelf->elfLogFont.lfFaceName,
5965 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5966 LF_FACESIZE);
5967 lstrcpynW(pelf->elfFullName,
5968 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5969 LF_FULLFACESIZE);
5970 lstrcpynW(pelf->elfStyle,
5971 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5972 LF_FACESIZE);
5974 else
5976 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5978 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5979 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5980 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5982 lstrcpynW(pelf->elfLogFont.lfFaceName, family_name, LF_FACESIZE);
5983 if (face->FullName)
5984 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5985 else
5986 lstrcpynW(pelf->elfFullName, family_name, LF_FULLFACESIZE);
5987 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5990 pntm->ntmTm.ntmFlags = face->ntmFlags;
5991 pntm->ntmFontSig = face->fs;
5993 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5995 pelf->elfLogFont.lfEscapement = 0;
5996 pelf->elfLogFont.lfOrientation = 0;
5997 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5998 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5999 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
6000 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
6001 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
6002 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
6003 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
6004 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
6005 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
6006 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
6007 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
6009 *ptype = 0;
6010 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
6011 *ptype |= TRUETYPE_FONTTYPE;
6012 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
6013 *ptype |= DEVICE_FONTTYPE;
6014 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
6015 *ptype |= RASTER_FONTTYPE;
6017 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
6018 if (face->cached_enum_data)
6020 face->cached_enum_data->elf = *pelf;
6021 face->cached_enum_data->ntm = *pntm;
6022 face->cached_enum_data->type = *ptype;
6025 free_font(font);
6028 static BOOL family_matches(Family *family, const WCHAR *face_name)
6030 Face *face;
6031 const struct list *face_list;
6033 if (!strncmpiW(face_name, family->FamilyName, LF_FACESIZE - 1)) return TRUE;
6035 face_list = get_face_list_from_family(family);
6036 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
6037 if (face->FullName && !strncmpiW(face_name, face->FullName, LF_FACESIZE - 1)) return TRUE;
6039 return FALSE;
6042 static BOOL face_matches(const WCHAR *family_name, Face *face, const WCHAR *face_name)
6044 if (!strncmpiW(face_name, family_name, LF_FACESIZE - 1)) return TRUE;
6046 return (face->FullName && !strncmpiW(face_name, face->FullName, LF_FACESIZE - 1));
6049 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
6050 FONTENUMPROCW proc, LPARAM lparam, const WCHAR *subst)
6052 ENUMLOGFONTEXW elf;
6053 NEWTEXTMETRICEXW ntm;
6054 DWORD type = 0;
6055 DWORD i;
6057 GetEnumStructs(face, face->family->FamilyName, &elf, &ntm, &type);
6058 for(i = 0; i < list->total; i++) {
6059 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
6060 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
6061 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
6062 i = list->total; /* break out of loop after enumeration */
6064 else
6066 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
6067 /* use the DEFAULT_CHARSET case only if no other charset is present */
6068 if (list->element[i].charset == DEFAULT_CHARSET &&
6069 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
6070 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
6071 strcpyW(elf.elfScript, list->element[i].name);
6072 if (!elf.elfScript[0])
6073 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
6075 /* Font Replacement */
6076 if (family != face->family)
6078 lstrcpynW(elf.elfLogFont.lfFaceName, family->FamilyName, LF_FACESIZE);
6079 if (face->FullName)
6080 lstrcpynW(elf.elfFullName, face->FullName, LF_FULLFACESIZE);
6081 else
6082 lstrcpynW(elf.elfFullName, family->FamilyName, LF_FULLFACESIZE);
6084 if (subst)
6085 strcpyW(elf.elfLogFont.lfFaceName, subst);
6086 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
6087 debugstr_w(elf.elfLogFont.lfFaceName),
6088 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
6089 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
6090 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
6091 ntm.ntmTm.ntmFlags);
6092 /* release section before callback (FIXME) */
6093 LeaveCriticalSection( &freetype_cs );
6094 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
6095 EnterCriticalSection( &freetype_cs );
6097 return TRUE;
6100 /*************************************************************
6101 * freetype_EnumFonts
6103 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
6105 Family *family;
6106 Face *face;
6107 const struct list *face_list;
6108 LOGFONTW lf;
6109 struct enum_charset_list enum_charsets;
6111 if (!plf)
6113 lf.lfCharSet = DEFAULT_CHARSET;
6114 lf.lfPitchAndFamily = 0;
6115 lf.lfFaceName[0] = 0;
6116 plf = &lf;
6119 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
6121 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
6123 GDI_CheckNotLock();
6124 EnterCriticalSection( &freetype_cs );
6125 if(plf->lfFaceName[0]) {
6126 WCHAR *face_name = plf->lfFaceName;
6127 FontSubst *psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
6129 if(psub) {
6130 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
6131 debugstr_w(psub->to.name));
6132 face_name = psub->to.name;
6135 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
6136 if (!family_matches(family, face_name)) continue;
6137 face_list = get_face_list_from_family(family);
6138 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
6139 if (!face_matches(family->FamilyName, face, face_name)) continue;
6140 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam, psub ? psub->from.name : NULL)) return FALSE;
6143 } else {
6144 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
6145 face_list = get_face_list_from_family(family);
6146 face = LIST_ENTRY(list_head(face_list), Face, entry);
6147 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam, NULL)) return FALSE;
6150 LeaveCriticalSection( &freetype_cs );
6151 return TRUE;
6154 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
6156 pt->x.value = vec->x >> 6;
6157 pt->x.fract = (vec->x & 0x3f) << 10;
6158 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
6159 pt->y.value = vec->y >> 6;
6160 pt->y.fract = (vec->y & 0x3f) << 10;
6161 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
6164 /***************************************************
6165 * According to the MSDN documentation on WideCharToMultiByte,
6166 * certain codepages cannot set the default_used parameter.
6167 * This returns TRUE if the codepage can set that parameter, false else
6168 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
6170 static BOOL codepage_sets_default_used(UINT codepage)
6172 switch (codepage)
6174 case CP_UTF7:
6175 case CP_UTF8:
6176 case CP_SYMBOL:
6177 return FALSE;
6178 default:
6179 return TRUE;
6184 * GSUB Table handling functions
6187 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
6189 const GSUB_CoverageFormat1* cf1;
6191 cf1 = table;
6193 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
6195 int count = GET_BE_WORD(cf1->GlyphCount);
6196 int i;
6197 TRACE("Coverage Format 1, %i glyphs\n",count);
6198 for (i = 0; i < count; i++)
6199 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
6200 return i;
6201 return -1;
6203 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
6205 const GSUB_CoverageFormat2* cf2;
6206 int i;
6207 int count;
6208 cf2 = (const GSUB_CoverageFormat2*)cf1;
6210 count = GET_BE_WORD(cf2->RangeCount);
6211 TRACE("Coverage Format 2, %i ranges\n",count);
6212 for (i = 0; i < count; i++)
6214 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
6215 return -1;
6216 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
6217 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
6219 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
6220 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
6223 return -1;
6225 else
6226 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
6228 return -1;
6231 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
6233 int i;
6234 int offset;
6235 const GSUB_LookupList *lookup;
6236 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
6238 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
6239 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
6241 const GSUB_LookupTable *look;
6242 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
6243 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
6244 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
6245 if (GET_BE_WORD(look->LookupType) != 1)
6246 FIXME("We only handle SubType 1\n");
6247 else
6249 int j;
6251 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
6253 const GSUB_SingleSubstFormat1 *ssf1;
6254 offset = GET_BE_WORD(look->SubTable[j]);
6255 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
6256 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
6258 int offset = GET_BE_WORD(ssf1->Coverage);
6259 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
6260 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
6262 TRACE(" Glyph 0x%x ->",glyph);
6263 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
6264 TRACE(" 0x%x\n",glyph);
6267 else
6269 const GSUB_SingleSubstFormat2 *ssf2;
6270 INT index;
6271 INT offset;
6273 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
6274 offset = GET_BE_WORD(ssf1->Coverage);
6275 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
6276 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
6277 TRACE(" Coverage index %i\n",index);
6278 if (index != -1)
6280 TRACE(" Glyph is 0x%x ->",glyph);
6281 glyph = GET_BE_WORD(ssf2->Substitute[index]);
6282 TRACE("0x%x\n",glyph);
6288 return glyph;
6292 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
6294 const GSUB_Header *header;
6295 const GSUB_Feature *feature;
6297 if (!font->GSUB_Table)
6298 return glyph;
6300 header = font->GSUB_Table;
6301 feature = font->vert_feature;
6303 return GSUB_apply_feature(header, feature, glyph);
6306 static FT_UInt get_glyph_index_symbol(const GdiFont *font, UINT glyph)
6308 FT_UInt ret;
6310 if (glyph < 0x100) glyph += 0xf000;
6311 /* there are a number of old pre-Unicode "broken" TTFs, which
6312 do have symbols at U+00XX instead of U+f0XX */
6313 if (!(ret = pFT_Get_Char_Index(font->ft_face, glyph)))
6314 ret = pFT_Get_Char_Index(font->ft_face, glyph - 0xf000);
6316 return ret;
6319 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
6321 FT_UInt ret;
6322 WCHAR wc;
6323 char buf;
6325 if (font->ft_face->charmap->encoding == FT_ENCODING_NONE)
6327 BOOL default_used;
6328 BOOL *default_used_pointer;
6330 default_used_pointer = NULL;
6331 default_used = FALSE;
6332 if (codepage_sets_default_used(font->codepage))
6333 default_used_pointer = &default_used;
6334 wc = (WCHAR)glyph;
6335 if (!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) ||
6336 default_used)
6338 if (font->codepage == CP_SYMBOL)
6340 ret = get_glyph_index_symbol(font, glyph);
6341 if (!ret)
6343 if (WideCharToMultiByte(CP_ACP, 0, &wc, 1, &buf, 1, NULL, NULL))
6344 ret = get_glyph_index_symbol(font, buf);
6347 else
6348 ret = 0;
6350 else
6351 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
6352 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6353 return ret;
6356 if (font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
6358 ret = get_glyph_index_symbol(font, glyph);
6359 if (!ret)
6361 wc = (WCHAR)glyph;
6362 if (WideCharToMultiByte(CP_ACP, 0, &wc, 1, &buf, 1, NULL, NULL))
6363 ret = get_glyph_index_symbol(font, (unsigned char)buf);
6365 return ret;
6368 return pFT_Get_Char_Index(font->ft_face, glyph);
6371 /* helper for freetype_GetGlyphIndices */
6372 static FT_UInt get_gdi_glyph_index(const GdiFont *font, UINT glyph)
6374 WCHAR wc = (WCHAR)glyph;
6375 BOOL default_used = FALSE;
6376 BOOL *default_used_pointer = NULL;
6377 FT_UInt ret;
6378 char buf;
6380 if(font->ft_face->charmap->encoding != FT_ENCODING_NONE)
6381 return get_glyph_index(font, glyph);
6383 if (codepage_sets_default_used(font->codepage))
6384 default_used_pointer = &default_used;
6385 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer)
6386 || default_used)
6388 if (font->codepage == CP_SYMBOL && wc < 0x100)
6389 ret = (unsigned char)wc;
6390 else
6391 ret = 0;
6393 else
6394 ret = (unsigned char)buf;
6395 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6396 return ret;
6399 static FT_UInt get_default_char_index(GdiFont *font)
6401 FT_UInt default_char;
6403 if (FT_IS_SFNT(font->ft_face))
6405 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
6406 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
6408 else
6410 TEXTMETRICW textm;
6411 get_text_metrics(font, &textm);
6412 default_char = textm.tmDefaultChar;
6415 return default_char;
6418 /*************************************************************
6419 * freetype_GetGlyphIndices
6421 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
6423 struct freetype_physdev *physdev = get_freetype_dev( dev );
6424 int i;
6425 WORD default_char;
6426 BOOL got_default = FALSE;
6428 if (!physdev->font)
6430 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
6431 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
6434 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
6436 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
6437 got_default = TRUE;
6440 GDI_CheckNotLock();
6441 EnterCriticalSection( &freetype_cs );
6443 for(i = 0; i < count; i++)
6445 pgi[i] = get_gdi_glyph_index(physdev->font, lpstr[i]);
6446 if (pgi[i] == 0)
6448 if (!got_default)
6450 default_char = get_default_char_index(physdev->font);
6451 got_default = TRUE;
6453 pgi[i] = default_char;
6455 else
6456 pgi[i] = get_GSUB_vert_glyph(physdev->font, pgi[i]);
6458 LeaveCriticalSection( &freetype_cs );
6459 return count;
6462 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
6464 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
6465 return !memcmp(matrix, &identity, sizeof(FMAT2));
6468 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
6470 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
6471 return !memcmp(matrix, &identity, sizeof(MAT2));
6474 static inline FT_Vector normalize_vector(FT_Vector *vec)
6476 FT_Vector out;
6477 FT_Fixed len;
6478 len = pFT_Vector_Length(vec);
6479 if (len) {
6480 out.x = (vec->x << 6) / len;
6481 out.y = (vec->y << 6) / len;
6483 else
6484 out.x = out.y = 0;
6485 return out;
6488 static BOOL get_bold_glyph_outline(FT_GlyphSlot glyph, LONG ppem, FT_Glyph_Metrics *metrics)
6490 FT_Error err;
6491 FT_Pos strength;
6492 FT_BBox bbox;
6494 if(glyph->format != FT_GLYPH_FORMAT_OUTLINE)
6495 return FALSE;
6496 if(!pFT_Outline_Embolden)
6497 return FALSE;
6499 strength = MulDiv(ppem, 1 << 6, 24);
6500 err = pFT_Outline_Embolden(&glyph->outline, strength);
6501 if(err) {
6502 TRACE("FT_Ouline_Embolden returns %d\n", err);
6503 return FALSE;
6506 pFT_Outline_Get_CBox(&glyph->outline, &bbox);
6507 metrics->width = bbox.xMax - bbox.xMin;
6508 metrics->height = bbox.yMax - bbox.yMin;
6509 metrics->horiBearingX = bbox.xMin;
6510 metrics->horiBearingY = bbox.yMax;
6511 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
6512 metrics->vertBearingY = (metrics->vertAdvance - metrics->height) / 2;
6513 return TRUE;
6516 static inline BYTE get_max_level( UINT format )
6518 switch( format )
6520 case GGO_GRAY2_BITMAP: return 4;
6521 case GGO_GRAY4_BITMAP: return 16;
6522 case GGO_GRAY8_BITMAP: return 64;
6524 return 255;
6527 extern const unsigned short vertical_orientation_table[] DECLSPEC_HIDDEN;
6529 static BOOL check_unicode_tategaki(WCHAR uchar)
6531 unsigned short orientation = vertical_orientation_table[vertical_orientation_table[vertical_orientation_table[uchar >> 8]+((uchar >> 4) & 0x0f)]+ (uchar & 0xf)];
6533 /* We only reach this code if typographical substitution did not occur */
6534 /* Type: U or Type: Tu */
6535 return (orientation == 1 || orientation == 3);
6538 static FT_Vector get_advance_metric(GdiFont *incoming_font, GdiFont *font,
6539 const FT_Glyph_Metrics *metrics,
6540 const FT_Matrix *transMat, BOOL vertical_metrics)
6542 FT_Vector adv;
6543 FT_Fixed base_advance, em_scale = 0;
6544 BOOL fixed_pitch_full = FALSE;
6546 if (vertical_metrics)
6547 base_advance = metrics->vertAdvance;
6548 else
6549 base_advance = metrics->horiAdvance;
6551 adv.x = base_advance;
6552 adv.y = 0;
6554 /* In fixed-pitch font, we adjust the fullwidth character advance so that
6555 they have double halfwidth character width. E.g. if the font is 19 ppem,
6556 we return 20 (not 19) for fullwidth characters as we return 10 for
6557 halfwidth characters. */
6558 if(FT_IS_SCALABLE(incoming_font->ft_face) &&
6559 (incoming_font->potm || get_outline_text_metrics(incoming_font)) &&
6560 !(incoming_font->potm->otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
6561 UINT avg_advance;
6562 em_scale = MulDiv(incoming_font->ppem, 1 << 16,
6563 incoming_font->ft_face->units_per_EM);
6564 avg_advance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
6565 fixed_pitch_full = (avg_advance > 0 &&
6566 (base_advance + 63) >> 6 ==
6567 pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale));
6568 if (fixed_pitch_full && !transMat)
6569 adv.x = (avg_advance * 2) << 6;
6572 if (transMat) {
6573 pFT_Vector_Transform(&adv, transMat);
6574 if (fixed_pitch_full && adv.y == 0) {
6575 FT_Vector vec;
6576 vec.x = incoming_font->ntmAvgWidth;
6577 vec.y = 0;
6578 pFT_Vector_Transform(&vec, transMat);
6579 adv.x = (pFT_MulFix(vec.x, em_scale) * 2) << 6;
6583 if (font->fake_bold) {
6584 if (!transMat)
6585 adv.x += 1 << 6;
6586 else {
6587 FT_Vector fake_bold_adv, vec = { 1 << 6, 0 };
6588 pFT_Vector_Transform(&vec, transMat);
6589 fake_bold_adv = normalize_vector(&vec);
6590 adv.x += fake_bold_adv.x;
6591 adv.y += fake_bold_adv.y;
6595 adv.x = (adv.x + 63) & -64;
6596 adv.y = -((adv.y + 63) & -64);
6597 return adv;
6600 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
6602 TTPOLYGONHEADER *pph;
6603 TTPOLYCURVE *ppc;
6604 unsigned int needed = 0, point = 0, contour, first_pt;
6605 unsigned int pph_start, cpfx;
6606 DWORD type;
6608 for (contour = 0; contour < outline->n_contours; contour++)
6610 /* Ignore contours containing one point */
6611 if (point == outline->contours[contour])
6613 point++;
6614 continue;
6617 pph_start = needed;
6618 pph = (TTPOLYGONHEADER *)(buf + needed);
6619 first_pt = point;
6620 if (buf)
6622 pph->dwType = TT_POLYGON_TYPE;
6623 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6625 needed += sizeof(*pph);
6626 point++;
6627 while (point <= outline->contours[contour])
6629 ppc = (TTPOLYCURVE *)(buf + needed);
6630 type = outline->tags[point] & FT_Curve_Tag_On ?
6631 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6632 cpfx = 0;
6635 if (buf)
6636 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6637 cpfx++;
6638 point++;
6639 } while (point <= outline->contours[contour] &&
6640 (outline->tags[point] & FT_Curve_Tag_On) ==
6641 (outline->tags[point-1] & FT_Curve_Tag_On));
6642 /* At the end of a contour Windows adds the start point, but
6643 only for Beziers */
6644 if (point > outline->contours[contour] &&
6645 !(outline->tags[point-1] & FT_Curve_Tag_On))
6647 if (buf)
6648 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6649 cpfx++;
6651 else if (point <= outline->contours[contour] &&
6652 outline->tags[point] & FT_Curve_Tag_On)
6654 /* add closing pt for bezier */
6655 if (buf)
6656 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6657 cpfx++;
6658 point++;
6660 if (buf)
6662 ppc->wType = type;
6663 ppc->cpfx = cpfx;
6665 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6667 if (buf)
6668 pph->cb = needed - pph_start;
6670 return needed;
6673 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
6675 /* Convert the quadratic Beziers to cubic Beziers.
6676 The parametric eqn for a cubic Bezier is, from PLRM:
6677 r(t) = at^3 + bt^2 + ct + r0
6678 with the control points:
6679 r1 = r0 + c/3
6680 r2 = r1 + (c + b)/3
6681 r3 = r0 + c + b + a
6683 A quadratic Bezier has the form:
6684 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6686 So equating powers of t leads to:
6687 r1 = 2/3 p1 + 1/3 p0
6688 r2 = 2/3 p1 + 1/3 p2
6689 and of course r0 = p0, r3 = p2
6691 int contour, point = 0, first_pt;
6692 TTPOLYGONHEADER *pph;
6693 TTPOLYCURVE *ppc;
6694 DWORD pph_start, cpfx, type;
6695 FT_Vector cubic_control[4];
6696 unsigned int needed = 0;
6698 for (contour = 0; contour < outline->n_contours; contour++)
6700 pph_start = needed;
6701 pph = (TTPOLYGONHEADER *)(buf + needed);
6702 first_pt = point;
6703 if (buf)
6705 pph->dwType = TT_POLYGON_TYPE;
6706 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6708 needed += sizeof(*pph);
6709 point++;
6710 while (point <= outline->contours[contour])
6712 ppc = (TTPOLYCURVE *)(buf + needed);
6713 type = outline->tags[point] & FT_Curve_Tag_On ?
6714 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6715 cpfx = 0;
6718 if (type == TT_PRIM_LINE)
6720 if (buf)
6721 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6722 cpfx++;
6723 point++;
6725 else
6727 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6728 so cpfx = 3n */
6730 /* FIXME: Possible optimization in endpoint calculation
6731 if there are two consecutive curves */
6732 cubic_control[0] = outline->points[point-1];
6733 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
6735 cubic_control[0].x += outline->points[point].x + 1;
6736 cubic_control[0].y += outline->points[point].y + 1;
6737 cubic_control[0].x >>= 1;
6738 cubic_control[0].y >>= 1;
6740 if (point+1 > outline->contours[contour])
6741 cubic_control[3] = outline->points[first_pt];
6742 else
6744 cubic_control[3] = outline->points[point+1];
6745 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
6747 cubic_control[3].x += outline->points[point].x + 1;
6748 cubic_control[3].y += outline->points[point].y + 1;
6749 cubic_control[3].x >>= 1;
6750 cubic_control[3].y >>= 1;
6753 /* r1 = 1/3 p0 + 2/3 p1
6754 r2 = 1/3 p2 + 2/3 p1 */
6755 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6756 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6757 cubic_control[2] = cubic_control[1];
6758 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6759 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6760 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6761 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6762 if (buf)
6764 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6765 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6766 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6768 cpfx += 3;
6769 point++;
6771 } while (point <= outline->contours[contour] &&
6772 (outline->tags[point] & FT_Curve_Tag_On) ==
6773 (outline->tags[point-1] & FT_Curve_Tag_On));
6774 /* At the end of a contour Windows adds the start point,
6775 but only for Beziers and we've already done that.
6777 if (point <= outline->contours[contour] &&
6778 outline->tags[point] & FT_Curve_Tag_On)
6780 /* This is the closing pt of a bezier, but we've already
6781 added it, so just inc point and carry on */
6782 point++;
6784 if (buf)
6786 ppc->wType = type;
6787 ppc->cpfx = cpfx;
6789 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6791 if (buf)
6792 pph->cb = needed - pph_start;
6794 return needed;
6797 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6799 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
6800 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
6801 const MAT2* lpmat)
6803 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
6804 GLYPHMETRICS gm;
6805 FT_Face ft_face = incoming_font->ft_face;
6806 GdiFont *font = incoming_font;
6807 FT_Glyph_Metrics metrics;
6808 FT_UInt glyph_index;
6809 DWORD width, height, pitch, needed = 0;
6810 FT_Bitmap ft_bitmap;
6811 FT_Error err;
6812 INT left, right, top = 0, bottom = 0;
6813 FT_Vector adv;
6814 INT origin_x = 0, origin_y = 0;
6815 FT_Angle angle = 0;
6816 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
6817 double widthRatio = 1.0;
6818 FT_Matrix transMat = identityMat;
6819 FT_Matrix transMatUnrotated;
6820 FT_Matrix transMatTategaki;
6821 BOOL needsTransform = FALSE;
6822 BOOL tategaki = (font->name[0] == '@');
6823 BOOL vertical_metrics;
6824 UINT original_index;
6826 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
6827 buflen, buf, lpmat);
6829 TRACE("font transform %f %f %f %f\n",
6830 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
6831 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
6833 if(format & GGO_GLYPH_INDEX) {
6834 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
6835 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
6836 as glyph index. "Treasure Adventure Game" depends on this. */
6837 glyph_index = pFT_Get_Char_Index(font->ft_face, glyph);
6838 TRACE("translate glyph index %04x -> %04x\n", glyph, glyph_index);
6839 } else
6840 glyph_index = glyph;
6841 original_index = glyph_index;
6842 format &= ~GGO_GLYPH_INDEX;
6843 /* TODO: Window also turns off tategaki for glyphs passed in by index
6844 if their unicode code points fall outside of the range that is
6845 rotated. */
6846 } else {
6847 BOOL vert;
6848 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index, &vert);
6849 ft_face = font->ft_face;
6850 original_index = glyph_index;
6851 if (!vert && tategaki)
6852 tategaki = check_unicode_tategaki(glyph);
6855 if(format & GGO_UNHINTED) {
6856 load_flags |= FT_LOAD_NO_HINTING;
6857 format &= ~GGO_UNHINTED;
6860 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
6861 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
6862 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
6863 font->gmsize * sizeof(GM*));
6864 } else {
6865 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
6866 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
6868 *lpgm = FONT_GM(font,original_index)->gm;
6869 *abc = FONT_GM(font,original_index)->abc;
6870 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6871 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6872 lpgm->gmCellIncX, lpgm->gmCellIncY);
6873 return 1; /* FIXME */
6877 if (!font->gm[original_index / GM_BLOCK_SIZE])
6878 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
6880 /* Scaling factor */
6881 if (font->aveWidth)
6883 TEXTMETRICW tm;
6885 get_text_metrics(font, &tm);
6887 widthRatio = (double)font->aveWidth;
6888 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6890 else
6891 widthRatio = font->scale_y;
6893 /* Scaling transform */
6894 if (widthRatio != 1.0 || font->scale_y != 1.0)
6896 FT_Matrix scaleMat;
6897 scaleMat.xx = FT_FixedFromFloat(widthRatio);
6898 scaleMat.xy = 0;
6899 scaleMat.yx = 0;
6900 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
6902 pFT_Matrix_Multiply(&scaleMat, &transMat);
6903 needsTransform = TRUE;
6906 /* Slant transform */
6907 if (font->fake_italic) {
6908 FT_Matrix slantMat;
6910 slantMat.xx = (1 << 16);
6911 slantMat.xy = ((1 << 16) >> 2);
6912 slantMat.yx = 0;
6913 slantMat.yy = (1 << 16);
6914 pFT_Matrix_Multiply(&slantMat, &transMat);
6915 needsTransform = TRUE;
6918 /* Rotation transform */
6919 transMatUnrotated = transMat;
6920 transMatTategaki = transMat;
6921 if(font->orientation || tategaki) {
6922 FT_Matrix rotationMat;
6923 FT_Matrix taterotationMat;
6924 FT_Vector vecAngle;
6926 double orient = font->orientation / 10.0;
6927 double tate_orient = 0.f;
6929 if (tategaki)
6930 tate_orient = ((font->orientation+900)%3600)/10.0;
6931 else
6932 tate_orient = font->orientation/10.0;
6934 if (orient)
6936 angle = FT_FixedFromFloat(orient);
6937 pFT_Vector_Unit(&vecAngle, angle);
6938 rotationMat.xx = vecAngle.x;
6939 rotationMat.xy = -vecAngle.y;
6940 rotationMat.yx = -rotationMat.xy;
6941 rotationMat.yy = rotationMat.xx;
6943 pFT_Matrix_Multiply(&rotationMat, &transMat);
6946 if (tate_orient)
6948 angle = FT_FixedFromFloat(tate_orient);
6949 pFT_Vector_Unit(&vecAngle, angle);
6950 taterotationMat.xx = vecAngle.x;
6951 taterotationMat.xy = -vecAngle.y;
6952 taterotationMat.yx = -taterotationMat.xy;
6953 taterotationMat.yy = taterotationMat.xx;
6954 pFT_Matrix_Multiply(&taterotationMat, &transMatTategaki);
6957 needsTransform = TRUE;
6960 /* World transform */
6961 if (!is_identity_FMAT2(&font->font_desc.matrix))
6963 FT_Matrix worldMat;
6964 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
6965 worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21);
6966 worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12);
6967 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
6968 pFT_Matrix_Multiply(&worldMat, &transMat);
6969 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
6970 pFT_Matrix_Multiply(&worldMat, &transMatTategaki);
6971 needsTransform = TRUE;
6974 /* Extra transformation specified by caller */
6975 if (!is_identity_MAT2(lpmat))
6977 FT_Matrix extraMat;
6978 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
6979 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
6980 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
6981 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
6982 pFT_Matrix_Multiply(&extraMat, &transMat);
6983 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
6984 pFT_Matrix_Multiply(&extraMat, &transMatTategaki);
6985 needsTransform = TRUE;
6988 vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face));
6989 /* there is a freetype bug where vertical metrics are only
6990 properly scaled and correct in 2.4.0 or greater */
6991 if ((vertical_metrics) && (FT_Version.major < 2 || (FT_Version.major == 2 && FT_Version.minor < 4)))
6992 vertical_metrics = FALSE;
6994 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
6995 if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
6997 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
6999 if(err) {
7000 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
7001 return GDI_ERROR;
7004 metrics = ft_face->glyph->metrics;
7005 if(font->fake_bold) {
7006 if (!get_bold_glyph_outline(ft_face->glyph, font->ppem, &metrics) && metrics.width)
7007 metrics.width += 1 << 6;
7010 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
7011 * by the text metrics. The proper behavior is to clip the glyph metrics to
7012 * fit within the maximums specified in the text metrics. */
7013 if(incoming_font->potm || get_outline_text_metrics(incoming_font) ||
7014 get_bitmap_text_metrics(incoming_font)) {
7015 TEXTMETRICW *ptm = &incoming_font->potm->otmTextMetrics;
7016 top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
7017 bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
7018 metrics.horiBearingY = top;
7019 metrics.height = top - bottom;
7021 /* TODO: Are we supposed to clip the width as well...? */
7022 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
7025 if(!needsTransform) {
7026 left = (INT)(metrics.horiBearingX) & -64;
7027 right = (INT)((metrics.horiBearingX + metrics.width) + 63) & -64;
7028 top = (metrics.horiBearingY + 63) & -64;
7029 bottom = (metrics.horiBearingY - metrics.height) & -64;
7030 adv = get_advance_metric(incoming_font, font, &metrics, NULL, vertical_metrics);
7031 gm.gmCellIncX = adv.x >> 6;
7032 gm.gmCellIncY = 0;
7033 origin_x = left;
7034 origin_y = top;
7035 abc->abcA = origin_x >> 6;
7036 abc->abcB = (metrics.width + 63) >> 6;
7037 } else {
7038 INT xc, yc;
7039 FT_Vector vec;
7040 FT_Pos lsb;
7042 left = right = 0;
7044 for(xc = 0; xc < 2; xc++) {
7045 for(yc = 0; yc < 2; yc++) {
7046 vec.x = metrics.horiBearingX + xc * metrics.width;
7047 vec.y = metrics.horiBearingY - yc * metrics.height;
7048 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
7049 pFT_Vector_Transform(&vec, &transMatTategaki);
7050 if(xc == 0 && yc == 0) {
7051 left = right = vec.x;
7052 top = bottom = vec.y;
7053 } else {
7054 if(vec.x < left) left = vec.x;
7055 else if(vec.x > right) right = vec.x;
7056 if(vec.y < bottom) bottom = vec.y;
7057 else if(vec.y > top) top = vec.y;
7061 left = left & -64;
7062 right = (right + 63) & -64;
7063 bottom = bottom & -64;
7064 top = (top + 63) & -64;
7066 if (tategaki && (font->potm || get_outline_text_metrics(font)))
7068 if (vertical_metrics)
7069 lsb = metrics.horiBearingY + metrics.vertBearingY;
7070 else
7071 lsb = metrics.vertAdvance + (font->potm->otmDescent << 6);
7072 vec.x = lsb;
7073 vec.y = font->potm->otmDescent << 6;
7074 TRACE ("Vec %ld,%ld\n", vec.x>>6, vec.y>>6);
7075 pFT_Vector_Transform(&vec, &transMat);
7076 origin_x = (vec.x + left) & -64;
7077 origin_y = (vec.y + top + 63) & -64;
7078 lsb -= metrics.horiBearingY;
7080 else
7082 origin_x = left;
7083 origin_y = top;
7084 lsb = metrics.horiBearingX;
7087 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
7088 adv = get_advance_metric(incoming_font, font, &metrics, &transMat, vertical_metrics);
7089 gm.gmCellIncX = adv.x >> 6;
7090 gm.gmCellIncY = adv.y >> 6;
7092 adv = get_advance_metric(incoming_font, font, &metrics, &transMatUnrotated, vertical_metrics);
7093 adv.x = pFT_Vector_Length(&adv);
7094 adv.y = 0;
7096 vec.x = lsb;
7097 vec.y = 0;
7098 pFT_Vector_Transform(&vec, &transMatUnrotated);
7099 if(lsb > 0) abc->abcA = pFT_Vector_Length(&vec) >> 6;
7100 else abc->abcA = -((pFT_Vector_Length(&vec) + 63) >> 6);
7102 /* We use lsb again to avoid rounding errors */
7103 vec.x = lsb + (tategaki ? metrics.height : metrics.width);
7104 vec.y = 0;
7105 pFT_Vector_Transform(&vec, &transMatUnrotated);
7106 abc->abcB = ((pFT_Vector_Length(&vec) + 63) >> 6) - abc->abcA;
7109 width = (right - left) >> 6;
7110 height = (top - bottom) >> 6;
7111 gm.gmBlackBoxX = width ? width : 1;
7112 gm.gmBlackBoxY = height ? height : 1;
7113 gm.gmptGlyphOrigin.x = origin_x >> 6;
7114 gm.gmptGlyphOrigin.y = origin_y >> 6;
7115 if (!abc->abcB) abc->abcB = 1;
7116 abc->abcC = (adv.x >> 6) - abc->abcA - abc->abcB;
7118 TRACE("%u,%u,%s,%d,%d\n", gm.gmBlackBoxX, gm.gmBlackBoxY,
7119 wine_dbgstr_point(&gm.gmptGlyphOrigin),
7120 gm.gmCellIncX, gm.gmCellIncY);
7122 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
7123 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
7125 FONT_GM(font,original_index)->gm = gm;
7126 FONT_GM(font,original_index)->abc = *abc;
7127 FONT_GM(font,original_index)->init = TRUE;
7130 if(format == GGO_METRICS)
7132 *lpgm = gm;
7133 return 1; /* FIXME */
7136 if(ft_face->glyph->format != ft_glyph_format_outline &&
7137 (format == GGO_NATIVE || format == GGO_BEZIER))
7139 TRACE("loaded a bitmap\n");
7140 return GDI_ERROR;
7143 switch(format) {
7144 case GGO_BITMAP:
7145 pitch = ((width + 31) >> 5) << 2;
7146 needed = pitch * height;
7148 if(!buf || !buflen) break;
7149 if (!needed) return GDI_ERROR; /* empty glyph */
7150 if (needed > buflen)
7151 return GDI_ERROR;
7153 switch(ft_face->glyph->format) {
7154 case ft_glyph_format_bitmap:
7156 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
7157 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
7158 INT h = min( height, ft_face->glyph->bitmap.rows );
7159 while(h--) {
7160 if (!font->fake_bold)
7161 memcpy(dst, src, w);
7162 else {
7163 INT x;
7164 dst[0] = 0;
7165 for (x = 0; x < w; x++) {
7166 dst[x ] = (dst[x] & 0x80) | (src[x] >> 1) | src[x];
7167 if (x+1 < pitch)
7168 dst[x+1] = (src[x] & 0x01) << 7;
7171 src += ft_face->glyph->bitmap.pitch;
7172 dst += pitch;
7174 break;
7177 case ft_glyph_format_outline:
7178 ft_bitmap.width = width;
7179 ft_bitmap.rows = height;
7180 ft_bitmap.pitch = pitch;
7181 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
7182 ft_bitmap.buffer = buf;
7184 if(needsTransform)
7185 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
7187 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
7189 /* Note: FreeType will only set 'black' bits for us. */
7190 memset(buf, 0, needed);
7191 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
7192 break;
7194 default:
7195 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
7196 return GDI_ERROR;
7198 break;
7200 case GGO_GRAY2_BITMAP:
7201 case GGO_GRAY4_BITMAP:
7202 case GGO_GRAY8_BITMAP:
7203 case WINE_GGO_GRAY16_BITMAP:
7205 unsigned int max_level, row, col;
7206 BYTE *start, *ptr;
7208 pitch = (width + 3) / 4 * 4;
7209 needed = pitch * height;
7211 if(!buf || !buflen) break;
7212 if (!needed) return GDI_ERROR; /* empty glyph */
7213 if (needed > buflen)
7214 return GDI_ERROR;
7216 max_level = get_max_level( format );
7218 switch(ft_face->glyph->format) {
7219 case ft_glyph_format_bitmap:
7221 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
7222 INT h = min( height, ft_face->glyph->bitmap.rows );
7223 INT x;
7224 memset( buf, 0, needed );
7225 while(h--) {
7226 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++) {
7227 if (src[x / 8] & masks[x % 8]) {
7228 dst[x] = max_level;
7229 if (font->fake_bold && x+1 < pitch) dst[x+1] = max_level;
7232 src += ft_face->glyph->bitmap.pitch;
7233 dst += pitch;
7235 break;
7237 case ft_glyph_format_outline:
7239 ft_bitmap.width = width;
7240 ft_bitmap.rows = height;
7241 ft_bitmap.pitch = pitch;
7242 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
7243 ft_bitmap.buffer = buf;
7245 if(needsTransform)
7246 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
7248 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
7250 memset(ft_bitmap.buffer, 0, buflen);
7252 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
7254 if (max_level != 255)
7256 for (row = 0, start = buf; row < height; row++)
7258 for (col = 0, ptr = start; col < width; col++, ptr++)
7259 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
7260 start += pitch;
7263 break;
7266 default:
7267 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
7268 return GDI_ERROR;
7270 break;
7273 case WINE_GGO_HRGB_BITMAP:
7274 case WINE_GGO_HBGR_BITMAP:
7275 case WINE_GGO_VRGB_BITMAP:
7276 case WINE_GGO_VBGR_BITMAP:
7277 #ifdef FT_LCD_FILTER_H
7279 switch (ft_face->glyph->format)
7281 case FT_GLYPH_FORMAT_BITMAP:
7283 BYTE *src, *dst;
7284 INT src_pitch, x;
7286 pitch = width * 4;
7287 needed = pitch * height;
7289 if (!buf || !buflen) break;
7290 if (!needed) return GDI_ERROR; /* empty glyph */
7291 if (needed > buflen)
7292 return GDI_ERROR;
7294 memset(buf, 0, buflen);
7295 dst = buf;
7296 src = ft_face->glyph->bitmap.buffer;
7297 src_pitch = ft_face->glyph->bitmap.pitch;
7299 height = min( height, ft_face->glyph->bitmap.rows );
7300 while ( height-- )
7302 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
7304 if ( src[x / 8] & masks[x % 8] )
7306 ((unsigned int *)dst)[x] = ~0u;
7307 if (font->fake_bold && x+1 < width) ((unsigned int *)dst)[x+1] = ~0u;
7310 src += src_pitch;
7311 dst += pitch;
7314 break;
7317 case FT_GLYPH_FORMAT_OUTLINE:
7319 unsigned int *dst;
7320 BYTE *src;
7321 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
7322 INT x_shift, y_shift;
7323 BOOL rgb;
7324 FT_Render_Mode render_mode =
7325 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
7326 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
7328 if (!width || !height)
7330 if (!buf || !buflen) break;
7331 return GDI_ERROR;
7334 if ( render_mode == FT_RENDER_MODE_LCD)
7336 gm.gmBlackBoxX += 2;
7337 gm.gmptGlyphOrigin.x -= 1;
7338 left -= (1 << 6);
7340 else
7342 gm.gmBlackBoxY += 2;
7343 gm.gmptGlyphOrigin.y += 1;
7344 top += (1 << 6);
7347 width = gm.gmBlackBoxX;
7348 height = gm.gmBlackBoxY;
7349 pitch = width * 4;
7350 needed = pitch * height;
7352 if (!buf || !buflen) break;
7353 if (needed > buflen)
7354 return GDI_ERROR;
7356 memset(buf, 0, buflen);
7357 dst = buf;
7358 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
7360 if ( needsTransform )
7361 pFT_Outline_Transform (&ft_face->glyph->outline, &transMatTategaki);
7363 if ( pFT_Library_SetLcdFilter )
7364 pFT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT );
7365 pFT_Render_Glyph (ft_face->glyph, render_mode);
7367 src = ft_face->glyph->bitmap.buffer;
7368 src_pitch = ft_face->glyph->bitmap.pitch;
7369 src_width = ft_face->glyph->bitmap.width;
7370 src_height = ft_face->glyph->bitmap.rows;
7372 if ( render_mode == FT_RENDER_MODE_LCD)
7374 rgb_interval = 1;
7375 hmul = 3;
7376 vmul = 1;
7378 else
7380 rgb_interval = src_pitch;
7381 hmul = 1;
7382 vmul = 3;
7385 x_shift = ft_face->glyph->bitmap_left - (left >> 6);
7386 if ( x_shift < 0 )
7388 src += hmul * -x_shift;
7389 src_width -= hmul * -x_shift;
7391 else if ( x_shift > 0 )
7393 dst += x_shift;
7394 width -= x_shift;
7397 y_shift = (top >> 6) - ft_face->glyph->bitmap_top;
7398 if ( y_shift < 0 )
7400 src += src_pitch * vmul * -y_shift;
7401 src_height -= vmul * -y_shift;
7403 else if ( y_shift > 0 )
7405 dst += y_shift * ( pitch / sizeof(*dst) );
7406 height -= y_shift;
7409 width = min( width, src_width / hmul );
7410 height = min( height, src_height / vmul );
7412 while ( height-- )
7414 for ( x = 0; x < width; x++ )
7416 if ( rgb )
7418 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
7419 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
7420 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
7421 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
7423 else
7425 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
7426 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
7427 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
7428 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
7431 src += src_pitch * vmul;
7432 dst += pitch / sizeof(*dst);
7435 break;
7438 default:
7439 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
7440 return GDI_ERROR;
7443 break;
7445 #else
7446 return GDI_ERROR;
7447 #endif
7449 case GGO_NATIVE:
7451 FT_Outline *outline = &ft_face->glyph->outline;
7453 if(buflen == 0) buf = NULL;
7455 if (needsTransform && buf)
7456 pFT_Outline_Transform(outline, &transMatTategaki);
7458 needed = get_native_glyph_outline(outline, buflen, NULL);
7460 if (!buf || !buflen)
7461 break;
7462 if (needed > buflen)
7463 return GDI_ERROR;
7465 get_native_glyph_outline(outline, buflen, buf);
7466 break;
7468 case GGO_BEZIER:
7470 FT_Outline *outline = &ft_face->glyph->outline;
7471 if(buflen == 0) buf = NULL;
7473 if (needsTransform && buf)
7474 pFT_Outline_Transform(outline, &transMat);
7476 needed = get_bezier_glyph_outline(outline, buflen, NULL);
7478 if (!buf || !buflen)
7479 break;
7480 if (needed > buflen)
7481 return GDI_ERROR;
7483 get_bezier_glyph_outline(outline, buflen, buf);
7484 break;
7487 default:
7488 FIXME("Unsupported format %d\n", format);
7489 return GDI_ERROR;
7491 *lpgm = gm;
7492 return needed;
7495 static BOOL get_bitmap_text_metrics(GdiFont *font)
7497 FT_Face ft_face = font->ft_face;
7498 FT_WinFNT_HeaderRec winfnt_header;
7499 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
7500 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
7501 font->potm->otmSize = size;
7503 #define TM font->potm->otmTextMetrics
7504 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
7506 TM.tmHeight = winfnt_header.pixel_height;
7507 TM.tmAscent = winfnt_header.ascent;
7508 TM.tmDescent = TM.tmHeight - TM.tmAscent;
7509 TM.tmInternalLeading = winfnt_header.internal_leading;
7510 TM.tmExternalLeading = winfnt_header.external_leading;
7511 TM.tmAveCharWidth = winfnt_header.avg_width;
7512 TM.tmMaxCharWidth = winfnt_header.max_width;
7513 TM.tmWeight = winfnt_header.weight;
7514 TM.tmOverhang = 0;
7515 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
7516 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
7517 TM.tmFirstChar = winfnt_header.first_char;
7518 TM.tmLastChar = winfnt_header.last_char;
7519 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
7520 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
7521 TM.tmItalic = winfnt_header.italic;
7522 TM.tmUnderlined = font->underline;
7523 TM.tmStruckOut = font->strikeout;
7524 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
7525 TM.tmCharSet = winfnt_header.charset;
7527 else
7529 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
7530 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
7531 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7532 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
7533 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
7534 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
7535 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
7536 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
7537 TM.tmOverhang = 0;
7538 TM.tmDigitizedAspectX = 96; /* FIXME */
7539 TM.tmDigitizedAspectY = 96; /* FIXME */
7540 TM.tmFirstChar = 1;
7541 TM.tmLastChar = 255;
7542 TM.tmDefaultChar = 32;
7543 TM.tmBreakChar = 32;
7544 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
7545 TM.tmUnderlined = font->underline;
7546 TM.tmStruckOut = font->strikeout;
7547 /* NB inverted meaning of TMPF_FIXED_PITCH */
7548 TM.tmPitchAndFamily = FT_IS_FIXED_WIDTH(ft_face) ? 0 : TMPF_FIXED_PITCH;
7549 TM.tmCharSet = font->charset;
7552 if(font->fake_bold)
7553 TM.tmWeight = FW_BOLD;
7554 #undef TM
7556 return TRUE;
7560 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
7562 double scale_x, scale_y;
7564 if (font->aveWidth)
7566 scale_x = (double)font->aveWidth;
7567 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7569 else
7570 scale_x = font->scale_y;
7572 scale_x *= fabs(font->font_desc.matrix.eM11);
7573 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7575 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7576 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7578 SCALE_Y(ptm->tmHeight);
7579 SCALE_Y(ptm->tmAscent);
7580 SCALE_Y(ptm->tmDescent);
7581 SCALE_Y(ptm->tmInternalLeading);
7582 SCALE_Y(ptm->tmExternalLeading);
7584 SCALE_X(ptm->tmOverhang);
7585 if(font->fake_bold)
7587 if(!FT_IS_SCALABLE(font->ft_face))
7588 ptm->tmOverhang++;
7589 ptm->tmAveCharWidth++;
7590 ptm->tmMaxCharWidth++;
7592 SCALE_X(ptm->tmAveCharWidth);
7593 SCALE_X(ptm->tmMaxCharWidth);
7595 #undef SCALE_X
7596 #undef SCALE_Y
7599 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
7601 double scale_x, scale_y;
7603 if (font->aveWidth)
7605 scale_x = (double)font->aveWidth;
7606 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7608 else
7609 scale_x = font->scale_y;
7611 scale_x *= fabs(font->font_desc.matrix.eM11);
7612 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7614 scale_font_metrics(font, &potm->otmTextMetrics);
7616 /* Windows scales these values as signed integers even if they are unsigned */
7617 #define SCALE_X(x) (x) = GDI_ROUND((int)(x) * (scale_x))
7618 #define SCALE_Y(y) (y) = GDI_ROUND((int)(y) * (scale_y))
7620 SCALE_Y(potm->otmAscent);
7621 SCALE_Y(potm->otmDescent);
7622 SCALE_Y(potm->otmLineGap);
7623 SCALE_Y(potm->otmsCapEmHeight);
7624 SCALE_Y(potm->otmsXHeight);
7625 SCALE_Y(potm->otmrcFontBox.top);
7626 SCALE_Y(potm->otmrcFontBox.bottom);
7627 SCALE_X(potm->otmrcFontBox.left);
7628 SCALE_X(potm->otmrcFontBox.right);
7629 SCALE_Y(potm->otmMacAscent);
7630 SCALE_Y(potm->otmMacDescent);
7631 SCALE_Y(potm->otmMacLineGap);
7632 SCALE_X(potm->otmptSubscriptSize.x);
7633 SCALE_Y(potm->otmptSubscriptSize.y);
7634 SCALE_X(potm->otmptSubscriptOffset.x);
7635 SCALE_Y(potm->otmptSubscriptOffset.y);
7636 SCALE_X(potm->otmptSuperscriptSize.x);
7637 SCALE_Y(potm->otmptSuperscriptSize.y);
7638 SCALE_X(potm->otmptSuperscriptOffset.x);
7639 SCALE_Y(potm->otmptSuperscriptOffset.y);
7640 SCALE_Y(potm->otmsStrikeoutSize);
7641 SCALE_Y(potm->otmsStrikeoutPosition);
7642 SCALE_Y(potm->otmsUnderscoreSize);
7643 SCALE_Y(potm->otmsUnderscorePosition);
7645 #undef SCALE_X
7646 #undef SCALE_Y
7649 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
7651 if(!font->potm)
7653 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
7655 /* Make sure that the font has sane width/height ratio */
7656 if (font->aveWidth)
7658 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
7660 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
7661 font->aveWidth = 0;
7665 *ptm = font->potm->otmTextMetrics;
7666 scale_font_metrics(font, ptm);
7667 return TRUE;
7670 static BOOL face_has_symbol_charmap(FT_Face ft_face)
7672 int i;
7674 for(i = 0; i < ft_face->num_charmaps; i++)
7676 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
7677 return TRUE;
7679 return FALSE;
7682 static BOOL get_outline_text_metrics(GdiFont *font)
7684 BOOL ret = FALSE;
7685 FT_Face ft_face = font->ft_face;
7686 UINT needed, lenfam, lensty, lenface, lenfull;
7687 TT_OS2 *pOS2;
7688 TT_HoriHeader *pHori;
7689 TT_Postscript *pPost;
7690 FT_Fixed em_scale;
7691 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
7692 char *cp;
7693 INT ascent, descent;
7694 USHORT windescent;
7696 TRACE("font=%p\n", font);
7698 if(!FT_IS_SCALABLE(ft_face))
7699 return FALSE;
7701 needed = sizeof(*font->potm);
7703 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
7704 family_nameW = strdupW(font->name);
7706 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
7707 if (!style_nameW)
7709 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
7710 style_nameW = towstr( CP_ACP, ft_face->style_name );
7712 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
7714 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
7715 if (!face_nameW)
7717 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
7718 face_nameW = strdupW(font->name);
7720 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
7721 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
7723 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
7724 if (!full_nameW)
7726 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
7727 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
7728 full_nameW = strdupW(fake_nameW);
7730 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
7732 /* These names should be read from the TT name table */
7734 /* length of otmpFamilyName */
7735 needed += lenfam;
7737 /* length of otmpFaceName */
7738 needed += lenface;
7740 /* length of otmpStyleName */
7741 needed += lensty;
7743 /* length of otmpFullName */
7744 needed += lenfull;
7747 em_scale = (FT_Fixed)MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
7749 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
7750 if(!pOS2) {
7751 FIXME("Can't find OS/2 table - not TT font?\n");
7752 goto end;
7755 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
7756 if(!pHori) {
7757 FIXME("Can't find HHEA table - not TT font?\n");
7758 goto end;
7761 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
7763 TRACE("OS/2 winA = %u winD = %u typoA = %d typoD = %d typoLG = %d avgW %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
7764 pOS2->usWinAscent, pOS2->usWinDescent,
7765 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
7766 pOS2->xAvgCharWidth,
7767 ft_face->ascender, ft_face->descender, ft_face->height,
7768 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
7769 ft_face->bbox.yMax, ft_face->bbox.yMin);
7771 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
7772 font->potm->otmSize = needed;
7774 #define TM font->potm->otmTextMetrics
7776 windescent = get_fixed_windescent(pOS2->usWinDescent);
7777 if(pOS2->usWinAscent + windescent == 0) {
7778 ascent = pHori->Ascender;
7779 descent = -pHori->Descender;
7780 } else {
7781 ascent = pOS2->usWinAscent;
7782 descent = windescent;
7785 font->ntmCellHeight = ascent + descent;
7786 font->ntmAvgWidth = pOS2->xAvgCharWidth;
7788 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7789 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7791 if(font->yMax) {
7792 TM.tmAscent = font->yMax;
7793 TM.tmDescent = -font->yMin;
7794 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
7795 } else {
7796 TM.tmAscent = SCALE_Y(ascent);
7797 TM.tmDescent = SCALE_Y(descent);
7798 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
7801 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7803 /* MSDN says:
7804 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7806 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
7807 ((ascent + descent) -
7808 (pHori->Ascender - pHori->Descender))));
7810 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
7811 if (TM.tmAveCharWidth == 0) {
7812 TM.tmAveCharWidth = 1;
7814 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
7815 TM.tmWeight = FW_REGULAR;
7816 if (font->fake_bold)
7817 TM.tmWeight = FW_BOLD;
7818 else
7820 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
7822 if (pOS2->usWeightClass > FW_MEDIUM)
7823 TM.tmWeight = pOS2->usWeightClass;
7825 else if (pOS2->usWeightClass <= FW_MEDIUM)
7826 TM.tmWeight = pOS2->usWeightClass;
7828 TM.tmOverhang = 0;
7829 TM.tmDigitizedAspectX = 96; /* FIXME */
7830 TM.tmDigitizedAspectY = 96; /* FIXME */
7831 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7832 * symbol range to 0 - f0ff
7835 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
7837 TM.tmFirstChar = 0;
7838 switch(GetACP())
7840 case 1255: /* Hebrew */
7841 TM.tmLastChar = 0xf896;
7842 break;
7843 case 1257: /* Baltic */
7844 TM.tmLastChar = 0xf8fd;
7845 break;
7846 default:
7847 TM.tmLastChar = 0xf0ff;
7849 TM.tmBreakChar = 0x20;
7850 TM.tmDefaultChar = 0x1f;
7852 else
7854 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
7855 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
7857 if(pOS2->usFirstCharIndex <= 1)
7858 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
7859 else if (pOS2->usFirstCharIndex > 0xff)
7860 TM.tmBreakChar = 0x20;
7861 else
7862 TM.tmBreakChar = pOS2->usFirstCharIndex;
7863 TM.tmDefaultChar = TM.tmBreakChar - 1;
7865 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
7866 TM.tmUnderlined = font->underline;
7867 TM.tmStruckOut = font->strikeout;
7869 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7870 if(!FT_IS_FIXED_WIDTH(ft_face) &&
7871 (pOS2->version == 0xFFFFU ||
7872 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
7873 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
7874 else
7875 TM.tmPitchAndFamily = 0;
7877 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
7879 case PAN_FAMILY_SCRIPT:
7880 TM.tmPitchAndFamily |= FF_SCRIPT;
7881 break;
7883 case PAN_FAMILY_DECORATIVE:
7884 TM.tmPitchAndFamily |= FF_DECORATIVE;
7885 break;
7887 case PAN_ANY:
7888 case PAN_NO_FIT:
7889 case PAN_FAMILY_TEXT_DISPLAY:
7890 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
7891 /* which is clearly not what the panose spec says. */
7892 default:
7893 if(TM.tmPitchAndFamily == 0 || /* fixed */
7894 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
7895 TM.tmPitchAndFamily = FF_MODERN;
7896 else
7898 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
7900 case PAN_ANY:
7901 case PAN_NO_FIT:
7902 default:
7903 TM.tmPitchAndFamily |= FF_DONTCARE;
7904 break;
7906 case PAN_SERIF_COVE:
7907 case PAN_SERIF_OBTUSE_COVE:
7908 case PAN_SERIF_SQUARE_COVE:
7909 case PAN_SERIF_OBTUSE_SQUARE_COVE:
7910 case PAN_SERIF_SQUARE:
7911 case PAN_SERIF_THIN:
7912 case PAN_SERIF_BONE:
7913 case PAN_SERIF_EXAGGERATED:
7914 case PAN_SERIF_TRIANGLE:
7915 TM.tmPitchAndFamily |= FF_ROMAN;
7916 break;
7918 case PAN_SERIF_NORMAL_SANS:
7919 case PAN_SERIF_OBTUSE_SANS:
7920 case PAN_SERIF_PERP_SANS:
7921 case PAN_SERIF_FLARED:
7922 case PAN_SERIF_ROUNDED:
7923 TM.tmPitchAndFamily |= FF_SWISS;
7924 break;
7927 break;
7930 if(FT_IS_SCALABLE(ft_face))
7931 TM.tmPitchAndFamily |= TMPF_VECTOR;
7933 if(FT_IS_SFNT(ft_face))
7935 if (font->ntmFlags & NTM_PS_OPENTYPE)
7936 TM.tmPitchAndFamily |= TMPF_DEVICE;
7937 else
7938 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
7941 TM.tmCharSet = font->charset;
7943 font->potm->otmFiller = 0;
7944 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
7945 font->potm->otmfsSelection = pOS2->fsSelection;
7946 if (font->fake_italic)
7947 font->potm->otmfsSelection |= 1;
7948 if (font->fake_bold)
7949 font->potm->otmfsSelection |= 1 << 5;
7950 /* Only return valid bits that define embedding and subsetting restrictions */
7951 font->potm->otmfsType = pOS2->fsType & 0x30e;
7952 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
7953 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
7954 font->potm->otmItalicAngle = 0; /* POST table */
7955 font->potm->otmEMSquare = ft_face->units_per_EM;
7956 font->potm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
7957 font->potm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
7958 font->potm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
7959 font->potm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
7960 font->potm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
7961 font->potm->otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
7962 font->potm->otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
7963 font->potm->otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
7964 font->potm->otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
7965 font->potm->otmMacAscent = TM.tmAscent;
7966 font->potm->otmMacDescent = -TM.tmDescent;
7967 font->potm->otmMacLineGap = SCALE_Y(pHori->Line_Gap);
7968 font->potm->otmusMinimumPPEM = 0; /* TT Header */
7969 font->potm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
7970 font->potm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
7971 font->potm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
7972 font->potm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
7973 font->potm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
7974 font->potm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
7975 font->potm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
7976 font->potm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
7977 font->potm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
7978 font->potm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
7979 if(!pPost) {
7980 font->potm->otmsUnderscoreSize = 0;
7981 font->potm->otmsUnderscorePosition = 0;
7982 } else {
7983 font->potm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
7984 font->potm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
7986 #undef SCALE_X
7987 #undef SCALE_Y
7988 #undef TM
7990 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7991 cp = (char*)font->potm + sizeof(*font->potm);
7992 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
7993 strcpyW((WCHAR*)cp, family_nameW);
7994 cp += lenfam;
7995 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
7996 strcpyW((WCHAR*)cp, style_nameW);
7997 cp += lensty;
7998 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7999 strcpyW((WCHAR*)cp, face_nameW);
8000 cp += lenface;
8001 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
8002 strcpyW((WCHAR*)cp, full_nameW);
8003 ret = TRUE;
8005 end:
8006 HeapFree(GetProcessHeap(), 0, style_nameW);
8007 HeapFree(GetProcessHeap(), 0, family_nameW);
8008 HeapFree(GetProcessHeap(), 0, face_nameW);
8009 HeapFree(GetProcessHeap(), 0, full_nameW);
8010 return ret;
8013 /*************************************************************
8014 * freetype_GetGlyphOutline
8016 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
8017 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
8019 struct freetype_physdev *physdev = get_freetype_dev( dev );
8020 DWORD ret;
8021 ABC abc;
8023 if (!physdev->font)
8025 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
8026 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
8029 GDI_CheckNotLock();
8030 EnterCriticalSection( &freetype_cs );
8031 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
8032 LeaveCriticalSection( &freetype_cs );
8033 return ret;
8036 /*************************************************************
8037 * freetype_GetTextMetrics
8039 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
8041 struct freetype_physdev *physdev = get_freetype_dev( dev );
8042 BOOL ret;
8044 if (!physdev->font)
8046 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
8047 return dev->funcs->pGetTextMetrics( dev, metrics );
8050 GDI_CheckNotLock();
8051 EnterCriticalSection( &freetype_cs );
8052 ret = get_text_metrics( physdev->font, metrics );
8053 LeaveCriticalSection( &freetype_cs );
8054 return ret;
8057 /*************************************************************
8058 * freetype_GetOutlineTextMetrics
8060 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
8062 struct freetype_physdev *physdev = get_freetype_dev( dev );
8063 UINT ret = 0;
8065 if (!physdev->font)
8067 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
8068 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
8071 TRACE("font=%p\n", physdev->font);
8073 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
8075 GDI_CheckNotLock();
8076 EnterCriticalSection( &freetype_cs );
8078 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
8080 if(potm && cbSize >= physdev->font->potm->otmSize)
8082 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
8083 scale_outline_font_metrics(physdev->font, potm);
8085 ret = physdev->font->potm->otmSize;
8087 LeaveCriticalSection( &freetype_cs );
8088 return ret;
8091 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
8093 child->font = alloc_font();
8094 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
8095 if(!child->font->ft_face)
8097 free_font(child->font);
8098 child->font = NULL;
8099 return FALSE;
8102 child->font->font_desc = font->font_desc;
8103 child->font->ntmFlags = child->face->ntmFlags;
8104 child->font->orientation = font->orientation;
8105 child->font->scale_y = font->scale_y;
8106 child->font->name = strdupW(child->face->family->FamilyName);
8107 child->font->base_font = font;
8108 TRACE("created child font %p for base %p\n", child->font, font);
8109 return TRUE;
8112 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL* vert)
8114 FT_UInt g,o;
8115 CHILD_FONT *child_font;
8117 if(font->base_font)
8118 font = font->base_font;
8120 *linked_font = font;
8122 if((*glyph = get_glyph_index(font, c)))
8124 o = *glyph;
8125 *glyph = get_GSUB_vert_glyph(font, *glyph);
8126 *vert = (o != *glyph);
8127 return TRUE;
8130 if (c < 32) goto done; /* don't check linked fonts for control characters */
8132 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
8134 if(!child_font->font)
8135 if(!load_child_font(font, child_font))
8136 continue;
8138 if(!child_font->font->ft_face)
8139 continue;
8140 g = get_glyph_index(child_font->font, c);
8141 o = g;
8142 g = get_GSUB_vert_glyph(child_font->font, g);
8143 if(g)
8145 *glyph = g;
8146 *linked_font = child_font->font;
8147 *vert = (o != g);
8148 return TRUE;
8152 done:
8153 *vert = FALSE;
8154 return FALSE;
8157 /*************************************************************
8158 * freetype_GetCharWidth
8160 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
8162 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8163 UINT c;
8164 GLYPHMETRICS gm;
8165 ABC abc;
8166 struct freetype_physdev *physdev = get_freetype_dev( dev );
8168 if (!physdev->font)
8170 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
8171 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
8174 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
8176 GDI_CheckNotLock();
8177 EnterCriticalSection( &freetype_cs );
8178 for(c = firstChar; c <= lastChar; c++) {
8179 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
8180 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
8182 LeaveCriticalSection( &freetype_cs );
8183 return TRUE;
8186 /*************************************************************
8187 * freetype_GetCharABCWidths
8189 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
8191 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8192 UINT c;
8193 GLYPHMETRICS gm;
8194 struct freetype_physdev *physdev = get_freetype_dev( dev );
8196 if (!physdev->font)
8198 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
8199 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
8202 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
8204 GDI_CheckNotLock();
8205 EnterCriticalSection( &freetype_cs );
8207 for(c = firstChar; c <= lastChar; c++, buffer++)
8208 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
8210 LeaveCriticalSection( &freetype_cs );
8211 return TRUE;
8214 /*************************************************************
8215 * freetype_GetCharABCWidthsI
8217 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
8219 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8220 UINT c;
8221 GLYPHMETRICS gm;
8222 struct freetype_physdev *physdev = get_freetype_dev( dev );
8224 if (!physdev->font)
8226 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
8227 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
8230 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
8231 return FALSE;
8233 GDI_CheckNotLock();
8234 EnterCriticalSection( &freetype_cs );
8236 for(c = 0; c < count; c++, buffer++)
8237 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
8238 &gm, buffer, 0, NULL, &identity );
8240 LeaveCriticalSection( &freetype_cs );
8241 return TRUE;
8244 /*************************************************************
8245 * freetype_GetTextExtentExPoint
8247 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
8249 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8250 INT idx, pos;
8251 ABC abc;
8252 GLYPHMETRICS gm;
8253 struct freetype_physdev *physdev = get_freetype_dev( dev );
8255 if (!physdev->font)
8257 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
8258 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
8261 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
8263 GDI_CheckNotLock();
8264 EnterCriticalSection( &freetype_cs );
8266 for (idx = pos = 0; idx < count; idx++)
8268 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
8269 pos += abc.abcA + abc.abcB + abc.abcC;
8270 dxs[idx] = pos;
8273 LeaveCriticalSection( &freetype_cs );
8274 return TRUE;
8277 /*************************************************************
8278 * freetype_GetTextExtentExPointI
8280 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
8282 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8283 INT idx, pos;
8284 ABC abc;
8285 GLYPHMETRICS gm;
8286 struct freetype_physdev *physdev = get_freetype_dev( dev );
8288 if (!physdev->font)
8290 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
8291 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
8294 TRACE("%p, %p, %d\n", physdev->font, indices, count);
8296 GDI_CheckNotLock();
8297 EnterCriticalSection( &freetype_cs );
8299 for (idx = pos = 0; idx < count; idx++)
8301 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
8302 &gm, &abc, 0, NULL, &identity );
8303 pos += abc.abcA + abc.abcB + abc.abcC;
8304 dxs[idx] = pos;
8307 LeaveCriticalSection( &freetype_cs );
8308 return TRUE;
8311 /*************************************************************
8312 * freetype_GetFontData
8314 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
8316 struct freetype_physdev *physdev = get_freetype_dev( dev );
8318 if (!physdev->font)
8320 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
8321 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
8324 TRACE("font=%p, table=%s, offset=0x%x, buf=%p, cbData=0x%x\n",
8325 physdev->font, debugstr_an((char*)&table, 4), offset, buf, cbData);
8327 return get_font_data( physdev->font, table, offset, buf, cbData );
8330 /*************************************************************
8331 * freetype_GetTextFace
8333 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
8335 INT n;
8336 struct freetype_physdev *physdev = get_freetype_dev( dev );
8338 if (!physdev->font)
8340 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
8341 return dev->funcs->pGetTextFace( dev, count, str );
8344 n = strlenW(physdev->font->name) + 1;
8345 if (str)
8347 lstrcpynW(str, physdev->font->name, count);
8348 n = min(count, n);
8350 return n;
8353 /*************************************************************
8354 * freetype_GetTextCharsetInfo
8356 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
8358 struct freetype_physdev *physdev = get_freetype_dev( dev );
8360 if (!physdev->font)
8362 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
8363 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
8365 if (fs) *fs = physdev->font->fs;
8366 return physdev->font->charset;
8369 /* Retrieve a list of supported Unicode ranges for a given font.
8370 * Can be called with NULL gs to calculate the buffer size. Returns
8371 * the number of ranges found.
8373 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
8375 DWORD num_ranges = 0;
8377 if (face->charmap->encoding == FT_ENCODING_UNICODE)
8379 FT_UInt glyph_code;
8380 FT_ULong char_code, char_code_prev;
8382 glyph_code = 0;
8383 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
8385 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
8386 face->num_glyphs, glyph_code, char_code);
8388 if (!glyph_code) return 0;
8390 if (gs)
8392 gs->ranges[0].wcLow = (USHORT)char_code;
8393 gs->ranges[0].cGlyphs = 0;
8394 gs->cGlyphsSupported = 0;
8397 num_ranges = 1;
8398 while (glyph_code)
8400 if (char_code < char_code_prev)
8402 ERR("expected increasing char code from FT_Get_Next_Char\n");
8403 return 0;
8405 if (char_code - char_code_prev > 1)
8407 num_ranges++;
8408 if (gs)
8410 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
8411 gs->ranges[num_ranges - 1].cGlyphs = 1;
8412 gs->cGlyphsSupported++;
8415 else if (gs)
8417 gs->ranges[num_ranges - 1].cGlyphs++;
8418 gs->cGlyphsSupported++;
8420 char_code_prev = char_code;
8421 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
8424 else
8426 DWORD encoding = RtlUlongByteSwap(face->charmap->encoding);
8427 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding, 4));
8430 return num_ranges;
8433 /*************************************************************
8434 * freetype_GetFontUnicodeRanges
8436 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
8438 struct freetype_physdev *physdev = get_freetype_dev( dev );
8439 DWORD size, num_ranges;
8441 if (!physdev->font)
8443 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
8444 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
8447 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
8448 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
8449 if (glyphset)
8451 glyphset->cbThis = size;
8452 glyphset->cRanges = num_ranges;
8453 glyphset->flAccel = 0;
8455 return size;
8458 /*************************************************************
8459 * freetype_FontIsLinked
8461 static BOOL freetype_FontIsLinked( PHYSDEV dev )
8463 struct freetype_physdev *physdev = get_freetype_dev( dev );
8464 BOOL ret;
8466 if (!physdev->font)
8468 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
8469 return dev->funcs->pFontIsLinked( dev );
8472 GDI_CheckNotLock();
8473 EnterCriticalSection( &freetype_cs );
8474 ret = !list_empty(&physdev->font->child_fonts);
8475 LeaveCriticalSection( &freetype_cs );
8476 return ret;
8479 /*************************************************************************
8480 * GetRasterizerCaps (GDI32.@)
8482 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8484 lprs->nSize = sizeof(RASTERIZER_STATUS);
8485 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
8486 lprs->nLanguageID = 0;
8487 return TRUE;
8490 /*************************************************************
8491 * freetype_GetFontRealizationInfo
8493 static BOOL freetype_GetFontRealizationInfo( PHYSDEV dev, void *ptr )
8495 struct freetype_physdev *physdev = get_freetype_dev( dev );
8496 struct font_realization_info *info = ptr;
8498 if (!physdev->font)
8500 dev = GET_NEXT_PHYSDEV( dev, pGetFontRealizationInfo );
8501 return dev->funcs->pGetFontRealizationInfo( dev, ptr );
8504 TRACE("(%p, %p)\n", physdev->font, info);
8506 info->flags = 1;
8507 if(FT_IS_SCALABLE(physdev->font->ft_face))
8508 info->flags |= 2;
8510 info->cache_num = physdev->font->cache_num;
8511 info->instance_id = physdev->font->instance_id;
8512 if (info->size == sizeof(*info))
8514 info->unk = 0;
8515 info->face_index = physdev->font->ft_face->face_index;
8516 info->simulations = 0;
8517 if (physdev->font->fake_bold)
8518 info->simulations |= 0x1;
8519 if (physdev->font->fake_italic)
8520 info->simulations |= 0x2;
8523 return TRUE;
8526 /*************************************************************************
8527 * GetFontFileInfo (GDI32.@)
8529 BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_fileinfo *info, DWORD size, DWORD *needed )
8531 struct font_handle_entry *entry = handle_entry( instance_id );
8532 const GdiFont *font;
8534 if (!entry)
8536 SetLastError(ERROR_INVALID_PARAMETER);
8537 return FALSE;
8540 font = entry->obj;
8541 *needed = sizeof(*info) + strlenW(font->fileinfo->path) * sizeof(WCHAR);
8542 if (*needed > size)
8544 SetLastError(ERROR_INSUFFICIENT_BUFFER);
8545 return FALSE;
8548 /* path is included too */
8549 memcpy(info, font->fileinfo, *needed);
8550 return TRUE;
8553 /*************************************************************************
8554 * Kerning support for TrueType fonts
8557 struct TT_kern_table
8559 USHORT version;
8560 USHORT nTables;
8563 struct TT_kern_subtable
8565 USHORT version;
8566 USHORT length;
8567 union
8569 USHORT word;
8570 struct
8572 USHORT horizontal : 1;
8573 USHORT minimum : 1;
8574 USHORT cross_stream: 1;
8575 USHORT override : 1;
8576 USHORT reserved1 : 4;
8577 USHORT format : 8;
8578 } bits;
8579 } coverage;
8582 struct TT_format0_kern_subtable
8584 USHORT nPairs;
8585 USHORT searchRange;
8586 USHORT entrySelector;
8587 USHORT rangeShift;
8590 struct TT_kern_pair
8592 USHORT left;
8593 USHORT right;
8594 short value;
8597 static DWORD parse_format0_kern_subtable(GdiFont *font,
8598 const struct TT_format0_kern_subtable *tt_f0_ks,
8599 const USHORT *glyph_to_char,
8600 KERNINGPAIR *kern_pair, DWORD cPairs)
8602 USHORT i, nPairs;
8603 const struct TT_kern_pair *tt_kern_pair;
8605 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
8607 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
8609 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8610 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
8611 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
8613 if (!kern_pair || !cPairs)
8614 return nPairs;
8616 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
8618 nPairs = min(nPairs, cPairs);
8620 for (i = 0; i < nPairs; i++)
8622 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
8623 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
8624 /* this algorithm appears to better match what Windows does */
8625 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
8626 if (kern_pair->iKernAmount < 0)
8628 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
8629 kern_pair->iKernAmount -= font->ppem;
8631 else if (kern_pair->iKernAmount > 0)
8633 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
8634 kern_pair->iKernAmount += font->ppem;
8636 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
8638 TRACE("left %u right %u value %d\n",
8639 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
8641 kern_pair++;
8643 TRACE("copied %u entries\n", nPairs);
8644 return nPairs;
8647 /*************************************************************
8648 * freetype_GetKerningPairs
8650 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
8652 DWORD length;
8653 void *buf;
8654 const struct TT_kern_table *tt_kern_table;
8655 const struct TT_kern_subtable *tt_kern_subtable;
8656 USHORT i, nTables;
8657 USHORT *glyph_to_char;
8658 GdiFont *font;
8659 struct freetype_physdev *physdev = get_freetype_dev( dev );
8661 if (!(font = physdev->font))
8663 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
8664 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
8667 GDI_CheckNotLock();
8668 EnterCriticalSection( &freetype_cs );
8669 if (font->total_kern_pairs != (DWORD)-1)
8671 if (cPairs && kern_pair)
8673 cPairs = min(cPairs, font->total_kern_pairs);
8674 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8676 else cPairs = font->total_kern_pairs;
8678 LeaveCriticalSection( &freetype_cs );
8679 return cPairs;
8682 font->total_kern_pairs = 0;
8684 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
8686 if (length == GDI_ERROR)
8688 TRACE("no kerning data in the font\n");
8689 LeaveCriticalSection( &freetype_cs );
8690 return 0;
8693 buf = HeapAlloc(GetProcessHeap(), 0, length);
8694 if (!buf)
8696 WARN("Out of memory\n");
8697 LeaveCriticalSection( &freetype_cs );
8698 return 0;
8701 get_font_data(font, MS_KERN_TAG, 0, buf, length);
8703 /* build a glyph index to char code map */
8704 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
8705 if (!glyph_to_char)
8707 WARN("Out of memory allocating a glyph index to char code map\n");
8708 HeapFree(GetProcessHeap(), 0, buf);
8709 LeaveCriticalSection( &freetype_cs );
8710 return 0;
8713 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
8715 FT_UInt glyph_code;
8716 FT_ULong char_code;
8718 glyph_code = 0;
8719 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
8721 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
8722 font->ft_face->num_glyphs, glyph_code, char_code);
8724 while (glyph_code)
8726 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
8728 /* FIXME: This doesn't match what Windows does: it does some fancy
8729 * things with duplicate glyph index to char code mappings, while
8730 * we just avoid overriding existing entries.
8732 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
8733 glyph_to_char[glyph_code] = (USHORT)char_code;
8735 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
8738 else
8740 DWORD encoding = RtlUlongByteSwap(font->ft_face->charmap->encoding);
8741 ULONG n;
8743 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding, 4));
8744 for (n = 0; n <= 65535; n++)
8745 glyph_to_char[n] = (USHORT)n;
8748 tt_kern_table = buf;
8749 nTables = GET_BE_WORD(tt_kern_table->nTables);
8750 TRACE("version %u, nTables %u\n",
8751 GET_BE_WORD(tt_kern_table->version), nTables);
8753 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
8755 for (i = 0; i < nTables; i++)
8757 struct TT_kern_subtable tt_kern_subtable_copy;
8759 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
8760 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
8761 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
8763 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8764 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
8765 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
8767 /* According to the TrueType specification this is the only format
8768 * that will be properly interpreted by Windows and OS/2
8770 if (tt_kern_subtable_copy.coverage.bits.format == 0)
8772 DWORD new_chunk, old_total = font->total_kern_pairs;
8774 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8775 glyph_to_char, NULL, 0);
8776 font->total_kern_pairs += new_chunk;
8778 if (!font->kern_pairs)
8779 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
8780 font->total_kern_pairs * sizeof(*font->kern_pairs));
8781 else
8782 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
8783 font->total_kern_pairs * sizeof(*font->kern_pairs));
8785 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8786 glyph_to_char, font->kern_pairs + old_total, new_chunk);
8788 else
8789 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
8791 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
8794 HeapFree(GetProcessHeap(), 0, glyph_to_char);
8795 HeapFree(GetProcessHeap(), 0, buf);
8797 if (cPairs && kern_pair)
8799 cPairs = min(cPairs, font->total_kern_pairs);
8800 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8802 else cPairs = font->total_kern_pairs;
8804 LeaveCriticalSection( &freetype_cs );
8805 return cPairs;
8808 static const struct gdi_dc_funcs freetype_funcs =
8810 NULL, /* pAbortDoc */
8811 NULL, /* pAbortPath */
8812 NULL, /* pAlphaBlend */
8813 NULL, /* pAngleArc */
8814 NULL, /* pArc */
8815 NULL, /* pArcTo */
8816 NULL, /* pBeginPath */
8817 NULL, /* pBlendImage */
8818 NULL, /* pChord */
8819 NULL, /* pCloseFigure */
8820 NULL, /* pCreateCompatibleDC */
8821 freetype_CreateDC, /* pCreateDC */
8822 freetype_DeleteDC, /* pDeleteDC */
8823 NULL, /* pDeleteObject */
8824 NULL, /* pDeviceCapabilities */
8825 NULL, /* pEllipse */
8826 NULL, /* pEndDoc */
8827 NULL, /* pEndPage */
8828 NULL, /* pEndPath */
8829 freetype_EnumFonts, /* pEnumFonts */
8830 NULL, /* pEnumICMProfiles */
8831 NULL, /* pExcludeClipRect */
8832 NULL, /* pExtDeviceMode */
8833 NULL, /* pExtEscape */
8834 NULL, /* pExtFloodFill */
8835 NULL, /* pExtSelectClipRgn */
8836 NULL, /* pExtTextOut */
8837 NULL, /* pFillPath */
8838 NULL, /* pFillRgn */
8839 NULL, /* pFlattenPath */
8840 freetype_FontIsLinked, /* pFontIsLinked */
8841 NULL, /* pFrameRgn */
8842 NULL, /* pGdiComment */
8843 NULL, /* pGetBoundsRect */
8844 freetype_GetCharABCWidths, /* pGetCharABCWidths */
8845 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
8846 freetype_GetCharWidth, /* pGetCharWidth */
8847 NULL, /* pGetDeviceCaps */
8848 NULL, /* pGetDeviceGammaRamp */
8849 freetype_GetFontData, /* pGetFontData */
8850 freetype_GetFontRealizationInfo, /* pGetFontRealizationInfo */
8851 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
8852 freetype_GetGlyphIndices, /* pGetGlyphIndices */
8853 freetype_GetGlyphOutline, /* pGetGlyphOutline */
8854 NULL, /* pGetICMProfile */
8855 NULL, /* pGetImage */
8856 freetype_GetKerningPairs, /* pGetKerningPairs */
8857 NULL, /* pGetNearestColor */
8858 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
8859 NULL, /* pGetPixel */
8860 NULL, /* pGetSystemPaletteEntries */
8861 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
8862 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
8863 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
8864 freetype_GetTextFace, /* pGetTextFace */
8865 freetype_GetTextMetrics, /* pGetTextMetrics */
8866 NULL, /* pGradientFill */
8867 NULL, /* pIntersectClipRect */
8868 NULL, /* pInvertRgn */
8869 NULL, /* pLineTo */
8870 NULL, /* pModifyWorldTransform */
8871 NULL, /* pMoveTo */
8872 NULL, /* pOffsetClipRgn */
8873 NULL, /* pOffsetViewportOrg */
8874 NULL, /* pOffsetWindowOrg */
8875 NULL, /* pPaintRgn */
8876 NULL, /* pPatBlt */
8877 NULL, /* pPie */
8878 NULL, /* pPolyBezier */
8879 NULL, /* pPolyBezierTo */
8880 NULL, /* pPolyDraw */
8881 NULL, /* pPolyPolygon */
8882 NULL, /* pPolyPolyline */
8883 NULL, /* pPolygon */
8884 NULL, /* pPolyline */
8885 NULL, /* pPolylineTo */
8886 NULL, /* pPutImage */
8887 NULL, /* pRealizeDefaultPalette */
8888 NULL, /* pRealizePalette */
8889 NULL, /* pRectangle */
8890 NULL, /* pResetDC */
8891 NULL, /* pRestoreDC */
8892 NULL, /* pRoundRect */
8893 NULL, /* pSaveDC */
8894 NULL, /* pScaleViewportExt */
8895 NULL, /* pScaleWindowExt */
8896 NULL, /* pSelectBitmap */
8897 NULL, /* pSelectBrush */
8898 NULL, /* pSelectClipPath */
8899 freetype_SelectFont, /* pSelectFont */
8900 NULL, /* pSelectPalette */
8901 NULL, /* pSelectPen */
8902 NULL, /* pSetArcDirection */
8903 NULL, /* pSetBkColor */
8904 NULL, /* pSetBkMode */
8905 NULL, /* pSetDCBrushColor */
8906 NULL, /* pSetDCPenColor */
8907 NULL, /* pSetDIBColorTable */
8908 NULL, /* pSetDIBitsToDevice */
8909 NULL, /* pSetDeviceClipping */
8910 NULL, /* pSetDeviceGammaRamp */
8911 NULL, /* pSetLayout */
8912 NULL, /* pSetMapMode */
8913 NULL, /* pSetMapperFlags */
8914 NULL, /* pSetPixel */
8915 NULL, /* pSetPolyFillMode */
8916 NULL, /* pSetROP2 */
8917 NULL, /* pSetRelAbs */
8918 NULL, /* pSetStretchBltMode */
8919 NULL, /* pSetTextAlign */
8920 NULL, /* pSetTextCharacterExtra */
8921 NULL, /* pSetTextColor */
8922 NULL, /* pSetTextJustification */
8923 NULL, /* pSetViewportExt */
8924 NULL, /* pSetViewportOrg */
8925 NULL, /* pSetWindowExt */
8926 NULL, /* pSetWindowOrg */
8927 NULL, /* pSetWorldTransform */
8928 NULL, /* pStartDoc */
8929 NULL, /* pStartPage */
8930 NULL, /* pStretchBlt */
8931 NULL, /* pStretchDIBits */
8932 NULL, /* pStrokeAndFillPath */
8933 NULL, /* pStrokePath */
8934 NULL, /* pUnrealizePalette */
8935 NULL, /* pWidenPath */
8936 NULL, /* wine_get_wgl_driver */
8937 NULL, /* wine_get_vulkan_driver */
8938 GDI_PRIORITY_FONT_DRV /* priority */
8941 #else /* HAVE_FREETYPE */
8943 struct font_fileinfo;
8945 /*************************************************************************/
8947 BOOL WineEngInit(void)
8949 return FALSE;
8952 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8954 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8955 return 1;
8958 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8960 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8961 return TRUE;
8964 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
8966 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
8967 return NULL;
8970 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
8971 LPCWSTR font_file, LPCWSTR font_path )
8973 FIXME("stub\n");
8974 return FALSE;
8977 /*************************************************************************
8978 * GetRasterizerCaps (GDI32.@)
8980 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8982 lprs->nSize = sizeof(RASTERIZER_STATUS);
8983 lprs->wFlags = 0;
8984 lprs->nLanguageID = 0;
8985 return TRUE;
8988 /*************************************************************************
8989 * GetFontFileInfo (GDI32.@)
8991 BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_fileinfo *info, DWORD size, DWORD *needed)
8993 *needed = 0;
8994 return FALSE;
8997 #endif /* HAVE_FREETYPE */