quartz/avidec: Call IMemInputPin::Receive() directly.
[wine.git] / dlls / gdi32 / freetype.c
blob10127bb77a66015881da1ddb424cf58815cc89b2
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 GetCurrentProcess
65 #undef AnimatePalette
66 #undef EqualRgn
67 #undef FillRgn
68 #undef FrameRgn
69 #undef GetPixel
70 #undef InvertRgn
71 #undef LineTo
72 #undef OffsetRgn
73 #undef PaintRgn
74 #undef Polygon
75 #undef ResizePalette
76 #undef SetRectRgn
77 #endif /* HAVE_CARBON_CARBON_H */
79 #ifdef HAVE_FT2BUILD_H
80 #include <ft2build.h>
81 #include FT_FREETYPE_H
82 #include FT_GLYPH_H
83 #include FT_TYPES_H
84 #include FT_TRUETYPE_TABLES_H
85 #include FT_SFNT_NAMES_H
86 #include FT_TRUETYPE_IDS_H
87 #include FT_OUTLINE_H
88 #include FT_TRIGONOMETRY_H
89 #include FT_MODULE_H
90 #include FT_WINFONTS_H
91 #ifdef FT_LCD_FILTER_H
92 #include FT_LCD_FILTER_H
93 #endif
94 #endif /* HAVE_FT2BUILD_H */
96 #include "windef.h"
97 #include "winbase.h"
98 #include "winternl.h"
99 #include "winerror.h"
100 #include "winreg.h"
101 #include "wingdi.h"
102 #include "gdi_private.h"
103 #include "wine/library.h"
104 #include "wine/unicode.h"
105 #include "wine/debug.h"
106 #include "wine/list.h"
108 #include "resource.h"
110 WINE_DEFAULT_DEBUG_CHANNEL(font);
112 #ifdef HAVE_FREETYPE
114 #ifndef HAVE_FT_TRUETYPEENGINETYPE
115 typedef enum
117 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
118 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
119 FT_TRUETYPE_ENGINE_TYPE_PATENTED
120 } FT_TrueTypeEngineType;
121 #endif
123 static FT_Library library = 0;
124 typedef struct
126 FT_Int major;
127 FT_Int minor;
128 FT_Int patch;
129 } FT_Version_t;
130 static FT_Version_t FT_Version;
131 static DWORD FT_SimpleVersion;
132 #define FT_VERSION_VALUE(major, minor, patch) (((major) << 16) | ((minor) << 8) | (patch))
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
172 static FT_Error (*pFT_Property_Set)(FT_Library, const FT_String *, const FT_String *, const void *);
174 #ifdef SONAME_LIBFONTCONFIG
175 #include <fontconfig/fontconfig.h>
176 MAKE_FUNCPTR(FcConfigSubstitute);
177 MAKE_FUNCPTR(FcDefaultSubstitute);
178 MAKE_FUNCPTR(FcFontList);
179 MAKE_FUNCPTR(FcFontMatch);
180 MAKE_FUNCPTR(FcFontSetDestroy);
181 MAKE_FUNCPTR(FcInit);
182 MAKE_FUNCPTR(FcPatternAddString);
183 MAKE_FUNCPTR(FcPatternCreate);
184 MAKE_FUNCPTR(FcPatternDestroy);
185 MAKE_FUNCPTR(FcPatternGetBool);
186 MAKE_FUNCPTR(FcPatternGetInteger);
187 MAKE_FUNCPTR(FcPatternGetString);
188 #ifndef FC_NAMELANG
189 #define FC_NAMELANG "namelang"
190 #endif
191 #ifndef FC_PRGNAME
192 #define FC_PRGNAME "prgname"
193 #endif
194 #endif /* SONAME_LIBFONTCONFIG */
196 #undef MAKE_FUNCPTR
198 #ifndef FT_MAKE_TAG
199 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
200 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
201 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
202 #endif
204 #ifndef ft_encoding_none
205 #define FT_ENCODING_NONE ft_encoding_none
206 #endif
207 #ifndef ft_encoding_ms_symbol
208 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
209 #endif
210 #ifndef ft_encoding_unicode
211 #define FT_ENCODING_UNICODE ft_encoding_unicode
212 #endif
213 #ifndef ft_encoding_apple_roman
214 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
215 #endif
217 #ifdef WORDS_BIGENDIAN
218 #define GET_BE_WORD(x) (x)
219 #define GET_BE_DWORD(x) (x)
220 #else
221 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
222 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
223 #endif
225 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
226 ( ( (FT_ULong)_x4 << 24 ) | \
227 ( (FT_ULong)_x3 << 16 ) | \
228 ( (FT_ULong)_x2 << 8 ) | \
229 (FT_ULong)_x1 )
231 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
232 #define MS_GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
233 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
234 #define MS_TTCF_TAG MS_MAKE_TAG('t', 't', 'c', 'f')
235 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
237 /* 'gasp' flags */
238 #define GASP_GRIDFIT 0x01
239 #define GASP_DOGRAY 0x02
241 #ifndef WINE_FONT_DIR
242 #define WINE_FONT_DIR "fonts"
243 #endif
245 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
246 typedef struct {
247 FT_Short height;
248 FT_Short width;
249 FT_Pos size;
250 FT_Pos x_ppem;
251 FT_Pos y_ppem;
252 FT_Short internal_leading;
253 } Bitmap_Size;
255 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
256 So to let this compile on older versions of FreeType we'll define the
257 new structure here. */
258 typedef struct {
259 FT_Short height, width;
260 FT_Pos size, x_ppem, y_ppem;
261 } My_FT_Bitmap_Size;
263 struct enum_data
265 ENUMLOGFONTEXW elf;
266 NEWTEXTMETRICEXW ntm;
267 DWORD type;
270 typedef struct tagFace {
271 struct list entry;
272 unsigned int refcount;
273 WCHAR *StyleName;
274 WCHAR *FullName;
275 WCHAR *file;
276 dev_t dev;
277 ino_t ino;
278 void *font_data_ptr;
279 DWORD font_data_size;
280 FT_Long face_index;
281 FONTSIGNATURE fs;
282 DWORD ntmFlags;
283 FT_Fixed font_version;
284 BOOL scalable;
285 Bitmap_Size size; /* set if face is a bitmap */
286 DWORD flags; /* ADDFONT flags */
287 struct tagFamily *family;
288 /* Cached data for Enum */
289 struct enum_data *cached_enum_data;
290 } Face;
292 #define ADDFONT_EXTERNAL_FONT 0x01
293 #define ADDFONT_ALLOW_BITMAP 0x02
294 #define ADDFONT_ADD_TO_CACHE 0x04
295 #define ADDFONT_ADD_RESOURCE 0x08 /* added through AddFontResource */
296 #define ADDFONT_VERTICAL_FONT 0x10
297 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
299 typedef struct tagFamily {
300 struct list entry;
301 unsigned int refcount;
302 WCHAR *FamilyName;
303 WCHAR *EnglishName;
304 struct list faces;
305 struct list *replacement;
306 } Family;
308 typedef struct {
309 GLYPHMETRICS gm;
310 ABC abc; /* metrics of the unrotated char */
311 BOOL init;
312 } GM;
314 typedef struct {
315 FLOAT eM11, eM12;
316 FLOAT eM21, eM22;
317 } FMAT2;
319 typedef struct {
320 DWORD hash;
321 LOGFONTW lf;
322 FMAT2 matrix;
323 BOOL can_use_bitmap;
324 } FONT_DESC;
326 typedef struct tagGdiFont GdiFont;
328 #define FIRST_FONT_HANDLE 1
329 #define MAX_FONT_HANDLES 256
331 struct font_handle_entry
333 void *obj;
334 WORD generation; /* generation count for reusing handle values */
337 static struct font_handle_entry font_handles[MAX_FONT_HANDLES];
338 static struct font_handle_entry *next_free;
339 static struct font_handle_entry *next_unused = font_handles;
341 static inline DWORD entry_to_handle( struct font_handle_entry *entry )
343 unsigned int idx = entry - font_handles + FIRST_FONT_HANDLE;
344 return idx | (entry->generation << 16);
347 static inline struct font_handle_entry *handle_entry( DWORD handle )
349 unsigned int idx = LOWORD(handle) - FIRST_FONT_HANDLE;
351 if (idx < MAX_FONT_HANDLES)
353 if (!HIWORD( handle ) || HIWORD( handle ) == font_handles[idx].generation)
354 return &font_handles[idx];
356 if (handle) WARN( "invalid handle 0x%08x\n", handle );
357 return NULL;
360 static DWORD alloc_font_handle( void *obj )
362 struct font_handle_entry *entry;
364 entry = next_free;
365 if (entry)
366 next_free = entry->obj;
367 else if (next_unused < font_handles + MAX_FONT_HANDLES)
368 entry = next_unused++;
369 else
371 ERR( "out of realized font handles\n" );
372 return 0;
374 entry->obj = obj;
375 if (++entry->generation == 0xffff) entry->generation = 1;
376 return entry_to_handle( entry );
379 static void free_font_handle( DWORD handle )
381 struct font_handle_entry *entry;
383 if ((entry = handle_entry( handle )))
385 entry->obj = next_free;
386 next_free = entry;
390 typedef struct {
391 struct list entry;
392 Face *face;
393 GdiFont *font;
394 } CHILD_FONT;
396 struct font_fileinfo {
397 FILETIME writetime;
398 LARGE_INTEGER size;
399 WCHAR path[1];
402 struct tagGdiFont {
403 struct list entry;
404 struct list unused_entry;
405 unsigned int refcount;
406 GM **gm;
407 DWORD gmsize;
408 OUTLINETEXTMETRICW *potm;
409 DWORD total_kern_pairs;
410 KERNINGPAIR *kern_pairs;
411 struct list child_fonts;
413 /* the following members can be accessed without locking, they are never modified after creation */
414 FT_Face ft_face;
415 struct font_mapping *mapping;
416 LPWSTR name;
417 int charset;
418 int codepage;
419 BOOL fake_italic;
420 BOOL fake_bold;
421 BYTE underline;
422 BYTE strikeout;
423 INT orientation;
424 FONT_DESC font_desc;
425 LONG aveWidth, ppem;
426 double scale_y;
427 SHORT yMax;
428 SHORT yMin;
429 DWORD ntmFlags;
430 DWORD aa_flags;
431 UINT ntmCellHeight, ntmAvgWidth;
432 FONTSIGNATURE fs;
433 GdiFont *base_font;
434 VOID *GSUB_Table;
435 const VOID *vert_feature;
436 ULONG ttc_item_offset; /* 0 if font is not a part of TrueType collection */
437 DWORD cache_num;
438 DWORD instance_id;
439 struct font_fileinfo *fileinfo;
442 typedef struct {
443 struct list entry;
444 const WCHAR *font_name;
445 FONTSIGNATURE fs;
446 struct list links;
447 } SYSTEM_LINKS;
449 struct enum_charset_element {
450 DWORD mask;
451 DWORD charset;
452 WCHAR name[LF_FACESIZE];
455 struct enum_charset_list {
456 DWORD total;
457 struct enum_charset_element element[32];
460 #define GM_BLOCK_SIZE 128
461 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
463 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
464 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
465 static unsigned int unused_font_count;
466 #define UNUSED_CACHE_SIZE 10
467 static struct list system_links = LIST_INIT(system_links);
469 static struct list font_subst_list = LIST_INIT(font_subst_list);
471 static struct list font_list = LIST_INIT(font_list);
473 struct freetype_physdev
475 struct gdi_physdev dev;
476 GdiFont *font;
479 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
481 return (struct freetype_physdev *)dev;
484 static const struct gdi_dc_funcs freetype_funcs;
486 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
487 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
488 'W','i','n','d','o','w','s','\\',
489 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
490 'F','o','n','t','s','\0'};
492 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
493 'W','i','n','d','o','w','s',' ','N','T','\\',
494 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
495 'F','o','n','t','s','\0'};
497 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
498 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
499 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
500 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
502 static const WCHAR * const SystemFontValues[] = {
503 System_Value,
504 OEMFont_Value,
505 FixedSys_Value,
506 NULL
509 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
510 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
512 /* Interesting and well-known (frequently-assumed!) font names */
513 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
514 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 };
515 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
516 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
517 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
518 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
519 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
520 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
522 static const WCHAR arial[] = {'A','r','i','a','l',0};
523 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
524 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};
525 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};
526 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
527 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
528 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
529 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
530 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
531 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
533 static const WCHAR *default_serif_list[] =
535 times_new_roman,
536 liberation_serif,
537 bitstream_vera_serif,
538 NULL
541 static const WCHAR *default_fixed_list[] =
543 courier_new,
544 liberation_mono,
545 bitstream_vera_sans_mono,
546 NULL
549 static const WCHAR *default_sans_list[] =
551 arial,
552 liberation_sans,
553 bitstream_vera_sans,
554 NULL
557 static const WCHAR *default_serif = times_new_roman;
558 static const WCHAR *default_fixed = courier_new;
559 static const WCHAR *default_sans = arial;
561 typedef struct {
562 WCHAR *name;
563 INT charset;
564 } NameCs;
566 typedef struct tagFontSubst {
567 struct list entry;
568 NameCs from;
569 NameCs to;
570 } FontSubst;
572 /* Registry font cache key and value names */
573 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
574 'F','o','n','t','s',0};
575 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
576 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
577 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
578 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
579 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
580 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
581 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
582 static const WCHAR face_size_value[] = {'S','i','z','e',0};
583 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
584 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
585 static const WCHAR face_flags_value[] = {'F','l','a','g','s',0};
586 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
587 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
588 static const WCHAR face_file_name_value[] = {'F','i','l','e',' ','N','a','m','e','\0'};
589 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
592 struct font_mapping
594 struct list entry;
595 int refcount;
596 dev_t dev;
597 ino_t ino;
598 void *data;
599 size_t size;
602 static struct list mappings_list = LIST_INIT( mappings_list );
604 static UINT default_aa_flags;
605 static HKEY hkey_font_cache;
606 static BOOL antialias_fakes = TRUE;
608 static CRITICAL_SECTION freetype_cs;
609 static CRITICAL_SECTION_DEBUG critsect_debug =
611 0, 0, &freetype_cs,
612 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
613 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
615 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
617 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
619 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
620 static BOOL use_default_fallback = FALSE;
622 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL *vert);
623 static BOOL get_outline_text_metrics(GdiFont *font);
624 static BOOL get_bitmap_text_metrics(GdiFont *font);
625 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
626 static void remove_face_from_cache( Face *face );
628 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
629 'W','i','n','d','o','w','s',' ','N','T','\\',
630 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
631 'S','y','s','t','e','m','L','i','n','k',0};
633 /****************************************
634 * Notes on .fon files
636 * The fonts System, FixedSys and Terminal are special. There are typically multiple
637 * versions installed for different resolutions and codepages. Windows stores which one to use
638 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
639 * Key Meaning
640 * FIXEDFON.FON FixedSys
641 * FONTS.FON System
642 * OEMFONT.FON Terminal
643 * LogPixels Current dpi set by the display control panel applet
644 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
645 * also has a LogPixels value that appears to mirror this)
647 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
648 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
649 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
650 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
651 * so that makes sense.
653 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
654 * to be mapped into the registry on Windows 2000 at least).
655 * I have
656 * woafont=app850.fon
657 * ega80woa.fon=ega80850.fon
658 * ega40woa.fon=ega40850.fon
659 * cga80woa.fon=cga80850.fon
660 * cga40woa.fon=cga40850.fon
663 /* These are all structures needed for the GSUB table */
666 typedef struct {
667 DWORD version;
668 WORD ScriptList;
669 WORD FeatureList;
670 WORD LookupList;
671 } GSUB_Header;
673 typedef struct {
674 CHAR ScriptTag[4];
675 WORD Script;
676 } GSUB_ScriptRecord;
678 typedef struct {
679 WORD ScriptCount;
680 GSUB_ScriptRecord ScriptRecord[1];
681 } GSUB_ScriptList;
683 typedef struct {
684 CHAR LangSysTag[4];
685 WORD LangSys;
686 } GSUB_LangSysRecord;
688 typedef struct {
689 WORD DefaultLangSys;
690 WORD LangSysCount;
691 GSUB_LangSysRecord LangSysRecord[1];
692 } GSUB_Script;
694 typedef struct {
695 WORD LookupOrder; /* Reserved */
696 WORD ReqFeatureIndex;
697 WORD FeatureCount;
698 WORD FeatureIndex[1];
699 } GSUB_LangSys;
701 typedef struct {
702 CHAR FeatureTag[4];
703 WORD Feature;
704 } GSUB_FeatureRecord;
706 typedef struct {
707 WORD FeatureCount;
708 GSUB_FeatureRecord FeatureRecord[1];
709 } GSUB_FeatureList;
711 typedef struct {
712 WORD FeatureParams; /* Reserved */
713 WORD LookupCount;
714 WORD LookupListIndex[1];
715 } GSUB_Feature;
717 typedef struct {
718 WORD LookupCount;
719 WORD Lookup[1];
720 } GSUB_LookupList;
722 typedef struct {
723 WORD LookupType;
724 WORD LookupFlag;
725 WORD SubTableCount;
726 WORD SubTable[1];
727 } GSUB_LookupTable;
729 typedef struct {
730 WORD CoverageFormat;
731 WORD GlyphCount;
732 WORD GlyphArray[1];
733 } GSUB_CoverageFormat1;
735 typedef struct {
736 WORD Start;
737 WORD End;
738 WORD StartCoverageIndex;
739 } GSUB_RangeRecord;
741 typedef struct {
742 WORD CoverageFormat;
743 WORD RangeCount;
744 GSUB_RangeRecord RangeRecord[1];
745 } GSUB_CoverageFormat2;
747 typedef struct {
748 WORD SubstFormat; /* = 1 */
749 WORD Coverage;
750 WORD DeltaGlyphID;
751 } GSUB_SingleSubstFormat1;
753 typedef struct {
754 WORD SubstFormat; /* = 2 */
755 WORD Coverage;
756 WORD GlyphCount;
757 WORD Substitute[1];
758 }GSUB_SingleSubstFormat2;
760 #ifdef HAVE_CARBON_CARBON_H
761 static char *find_cache_dir(void)
763 FSRef ref;
764 OSErr err;
765 static char cached_path[MAX_PATH];
766 static const char *wine = "/Wine", *fonts = "/Fonts";
768 if(*cached_path) return cached_path;
770 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
771 if(err != noErr)
773 WARN("can't create cached data folder\n");
774 return NULL;
776 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
777 if(err != noErr)
779 WARN("can't create cached data path\n");
780 *cached_path = '\0';
781 return NULL;
783 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
785 ERR("Could not create full path\n");
786 *cached_path = '\0';
787 return NULL;
789 strcat(cached_path, wine);
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 strcat(cached_path, fonts);
798 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
800 WARN("Couldn't mkdir %s\n", cached_path);
801 *cached_path = '\0';
802 return NULL;
804 return cached_path;
807 /******************************************************************
808 * expand_mac_font
810 * Extracts individual TrueType font files from a Mac suitcase font
811 * and saves them into the user's caches directory (see
812 * find_cache_dir()).
813 * Returns a NULL terminated array of filenames.
815 * We do this because they are apps that try to read ttf files
816 * themselves and they don't like Mac suitcase files.
818 static char **expand_mac_font(const char *path)
820 FSRef ref;
821 ResFileRefNum res_ref;
822 OSStatus s;
823 unsigned int idx;
824 const char *out_dir;
825 const char *filename;
826 int output_len;
827 struct {
828 char **array;
829 unsigned int size, max_size;
830 } ret;
832 TRACE("path %s\n", path);
834 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
835 if(s != noErr)
837 WARN("failed to get ref\n");
838 return NULL;
841 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
842 if(s != noErr)
844 TRACE("no data fork, so trying resource fork\n");
845 res_ref = FSOpenResFile(&ref, fsRdPerm);
846 if(res_ref == -1)
848 TRACE("unable to open resource fork\n");
849 return NULL;
853 ret.size = 0;
854 ret.max_size = 10;
855 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
856 if(!ret.array)
858 CloseResFile(res_ref);
859 return NULL;
862 out_dir = find_cache_dir();
864 filename = strrchr(path, '/');
865 if(!filename) filename = path;
866 else filename++;
868 /* output filename has the form out_dir/filename_%04x.ttf */
869 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
871 UseResFile(res_ref);
872 idx = 1;
873 while(1)
875 FamRec *fam_rec;
876 unsigned short *num_faces_ptr, num_faces, face;
877 AsscEntry *assoc;
878 Handle fond;
879 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
881 fond = Get1IndResource(fond_res, idx);
882 if(!fond) break;
883 TRACE("got fond resource %d\n", idx);
884 HLock(fond);
886 fam_rec = *(FamRec**)fond;
887 num_faces_ptr = (unsigned short *)(fam_rec + 1);
888 num_faces = GET_BE_WORD(*num_faces_ptr);
889 num_faces++;
890 assoc = (AsscEntry*)(num_faces_ptr + 1);
891 TRACE("num faces %04x\n", num_faces);
892 for(face = 0; face < num_faces; face++, assoc++)
894 Handle sfnt;
895 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
896 unsigned short size, font_id;
897 char *output;
899 size = GET_BE_WORD(assoc->fontSize);
900 font_id = GET_BE_WORD(assoc->fontID);
901 if(size != 0)
903 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
904 continue;
907 TRACE("trying to load sfnt id %04x\n", font_id);
908 sfnt = GetResource(sfnt_res, font_id);
909 if(!sfnt)
911 TRACE("can't get sfnt resource %04x\n", font_id);
912 continue;
915 output = HeapAlloc(GetProcessHeap(), 0, output_len);
916 if(output)
918 int fd;
920 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
922 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
923 if(fd != -1 || errno == EEXIST)
925 if(fd != -1)
927 unsigned char *sfnt_data;
929 HLock(sfnt);
930 sfnt_data = *(unsigned char**)sfnt;
931 write(fd, sfnt_data, GetHandleSize(sfnt));
932 HUnlock(sfnt);
933 close(fd);
935 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
937 ret.max_size *= 2;
938 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
940 ret.array[ret.size++] = output;
942 else
944 WARN("unable to create %s\n", output);
945 HeapFree(GetProcessHeap(), 0, output);
948 ReleaseResource(sfnt);
950 HUnlock(fond);
951 ReleaseResource(fond);
952 idx++;
954 CloseResFile(res_ref);
956 return ret.array;
959 #endif /* HAVE_CARBON_CARBON_H */
961 static inline BOOL is_win9x(void)
963 return GetVersion() & 0x80000000;
966 This function builds an FT_Fixed from a double. It fails if the absolute
967 value of the float number is greater than 32768.
969 static inline FT_Fixed FT_FixedFromFloat(double f)
971 return f * 0x10000;
975 This function builds an FT_Fixed from a FIXED. It simply put f.value
976 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
978 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
980 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
983 static BOOL is_hinting_enabled(void)
985 static int enabled = -1;
987 if (enabled == -1)
989 /* Use the >= 2.2.0 function if available */
990 if (pFT_Get_TrueType_Engine_Type)
992 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
993 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
995 else enabled = FALSE;
996 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
998 return enabled;
1001 static BOOL is_subpixel_rendering_enabled( void )
1003 static int enabled = -1;
1004 if (enabled == -1)
1006 /* FreeType >= 2.8.1 offers LCD-optimezed rendering without lcd filters. */
1007 if (FT_SimpleVersion >= FT_VERSION_VALUE(2, 8, 1))
1008 enabled = TRUE;
1009 #ifdef FT_LCD_FILTER_H
1010 else if (pFT_Library_SetLcdFilter &&
1011 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature)
1012 enabled = TRUE;
1013 #endif
1014 else enabled = FALSE;
1016 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
1018 return enabled;
1022 static const struct list *get_face_list_from_family(const Family *family)
1024 if (!list_empty(&family->faces))
1025 return &family->faces;
1026 else
1027 return family->replacement;
1030 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
1032 Family *family;
1033 Face *face;
1034 const WCHAR *file;
1036 TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
1038 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1040 const struct list *face_list;
1041 if(face_name && strncmpiW(face_name, family->FamilyName, LF_FACESIZE - 1))
1042 continue;
1043 face_list = get_face_list_from_family(family);
1044 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
1046 if (!face->file)
1047 continue;
1048 file = strrchrW(face->file, '/');
1049 if(!file)
1050 file = face->file;
1051 else
1052 file++;
1053 if(strcmpiW(file, file_name)) continue;
1054 face->refcount++;
1055 return face;
1058 return NULL;
1061 static Family *find_family_from_name(const WCHAR *name)
1063 Family *family;
1065 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1067 if(!strncmpiW(family->FamilyName, name, LF_FACESIZE -1))
1068 return family;
1071 return NULL;
1074 static Family *find_family_from_any_name(const WCHAR *name)
1076 Family *family;
1078 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1080 if(!strncmpiW(family->FamilyName, name, LF_FACESIZE - 1))
1081 return family;
1082 if(family->EnglishName && !strncmpiW(family->EnglishName, name, LF_FACESIZE - 1))
1083 return family;
1086 return NULL;
1089 static void DumpSubstList(void)
1091 FontSubst *psub;
1093 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
1095 if(psub->from.charset != -1 || psub->to.charset != -1)
1096 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
1097 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
1098 else
1099 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
1100 debugstr_w(psub->to.name));
1104 static LPWSTR strdupW(LPCWSTR p)
1106 LPWSTR ret;
1107 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
1108 ret = HeapAlloc(GetProcessHeap(), 0, len);
1109 memcpy(ret, p, len);
1110 return ret;
1113 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1114 INT from_charset)
1116 FontSubst *element;
1118 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1120 if(!strcmpiW(element->from.name, from_name) &&
1121 (element->from.charset == from_charset ||
1122 element->from.charset == -1))
1123 return element;
1126 return NULL;
1129 #define ADD_FONT_SUBST_FORCE 1
1131 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1133 FontSubst *from_exist, *to_exist;
1135 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1137 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1139 list_remove(&from_exist->entry);
1140 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
1141 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
1142 HeapFree(GetProcessHeap(), 0, from_exist);
1143 from_exist = NULL;
1146 if(!from_exist)
1148 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1150 if(to_exist)
1152 HeapFree(GetProcessHeap(), 0, subst->to.name);
1153 subst->to.name = strdupW(to_exist->to.name);
1156 list_add_tail(subst_list, &subst->entry);
1158 return TRUE;
1161 HeapFree(GetProcessHeap(), 0, subst->from.name);
1162 HeapFree(GetProcessHeap(), 0, subst->to.name);
1163 HeapFree(GetProcessHeap(), 0, subst);
1164 return FALSE;
1167 static WCHAR *towstr(UINT cp, const char *str)
1169 int len;
1170 WCHAR *wstr;
1172 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1173 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1174 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1175 return wstr;
1178 static char *strWtoA(UINT cp, const WCHAR *str)
1180 int len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL );
1181 char *ret = HeapAlloc( GetProcessHeap(), 0, len );
1182 WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL );
1183 return ret;
1186 static void split_subst_info(NameCs *nc, LPSTR str)
1188 CHAR *p = strrchr(str, ',');
1190 nc->charset = -1;
1191 if(p && *(p+1)) {
1192 nc->charset = strtol(p+1, NULL, 10);
1193 *p = '\0';
1195 nc->name = towstr(CP_ACP, str);
1198 static void LoadSubstList(void)
1200 FontSubst *psub;
1201 HKEY hkey;
1202 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1203 LPSTR value;
1204 LPVOID data;
1206 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1207 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1208 &hkey) == ERROR_SUCCESS) {
1210 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1211 &valuelen, &datalen, NULL, NULL);
1213 valuelen++; /* returned value doesn't include room for '\0' */
1214 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1215 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1217 dlen = datalen;
1218 vlen = valuelen;
1219 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1220 &dlen) == ERROR_SUCCESS) {
1221 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1223 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1224 split_subst_info(&psub->from, value);
1225 split_subst_info(&psub->to, data);
1227 /* Win 2000 doesn't allow mapping between different charsets
1228 or mapping of DEFAULT_CHARSET */
1229 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1230 psub->to.charset == DEFAULT_CHARSET) {
1231 HeapFree(GetProcessHeap(), 0, psub->to.name);
1232 HeapFree(GetProcessHeap(), 0, psub->from.name);
1233 HeapFree(GetProcessHeap(), 0, psub);
1234 } else {
1235 add_font_subst(&font_subst_list, psub, 0);
1237 /* reset dlen and vlen */
1238 dlen = datalen;
1239 vlen = valuelen;
1241 HeapFree(GetProcessHeap(), 0, data);
1242 HeapFree(GetProcessHeap(), 0, value);
1243 RegCloseKey(hkey);
1248 static const LANGID mac_langid_table[] =
1250 MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */
1251 MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */
1252 MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */
1253 MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */
1254 MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */
1255 MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */
1256 MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */
1257 MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */
1258 MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */
1259 MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */
1260 MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */
1261 MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */
1262 MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */
1263 MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */
1264 MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */
1265 MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */
1266 MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */
1267 MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */
1268 MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */
1269 MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
1270 MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */
1271 MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */
1272 MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */
1273 MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */
1274 MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */
1275 MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */
1276 MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */
1277 MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */
1278 MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */
1279 MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */
1280 MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */
1281 MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */
1282 MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */
1283 MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
1284 MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */
1285 MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */
1286 MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */
1287 MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */
1288 MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */
1289 MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */
1290 MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */
1291 0, /* TT_MAC_LANGID_YIDDISH */
1292 MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */
1293 MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */
1294 MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */
1295 MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */
1296 MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */
1297 MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */
1298 MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */
1299 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */
1300 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
1301 MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */
1302 MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */
1303 0, /* TT_MAC_LANGID_MOLDAVIAN */
1304 MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */
1305 MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */
1306 MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */
1307 MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */
1308 MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
1309 MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */
1310 0, /* TT_MAC_LANGID_KURDISH */
1311 MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */
1312 MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */
1313 MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */
1314 MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */
1315 MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */
1316 MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */
1317 MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */
1318 MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */
1319 MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */
1320 MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */
1321 MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */
1322 MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */
1323 MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */
1324 MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */
1325 MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */
1326 MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */
1327 0, /* TT_MAC_LANGID_BURMESE */
1328 MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */
1329 MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */
1330 MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */
1331 MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */
1332 0, /* TT_MAC_LANGID_TAGALOG */
1333 MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
1334 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
1335 MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */
1336 MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */
1337 0, /* TT_MAC_LANGID_GALLA */
1338 0, /* TT_MAC_LANGID_SOMALI */
1339 MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */
1340 0, /* TT_MAC_LANGID_RUANDA */
1341 0, /* TT_MAC_LANGID_RUNDI */
1342 0, /* TT_MAC_LANGID_CHEWA */
1343 MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */
1344 MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */
1345 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
1346 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
1347 MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */
1348 MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */
1349 MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */
1350 0, /* TT_MAC_LANGID_LATIN */
1351 MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */
1352 0, /* TT_MAC_LANGID_GUARANI */
1353 0, /* TT_MAC_LANGID_AYMARA */
1354 MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */
1355 MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */
1356 0, /* TT_MAC_LANGID_DZONGKHA */
1357 0, /* TT_MAC_LANGID_JAVANESE */
1358 0, /* TT_MAC_LANGID_SUNDANESE */
1359 MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */
1360 MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */
1361 MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */
1362 MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */
1363 MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
1364 MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */
1365 MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */
1366 0, /* TT_MAC_LANGID_TONGAN */
1367 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
1368 MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */
1369 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
1372 static inline WORD get_mac_code_page( const FT_SfntName *name )
1374 if (name->encoding_id == TT_MAC_ID_SIMPLIFIED_CHINESE) return 10008; /* special case */
1375 return 10000 + name->encoding_id;
1378 static int match_name_table_language( const FT_SfntName *name, LANGID lang )
1380 LANGID name_lang;
1381 int res = 0;
1383 switch (name->platform_id)
1385 case TT_PLATFORM_MICROSOFT:
1386 res += 5; /* prefer the Microsoft name */
1387 switch (name->encoding_id)
1389 case TT_MS_ID_UNICODE_CS:
1390 case TT_MS_ID_SYMBOL_CS:
1391 name_lang = name->language_id;
1392 break;
1393 default:
1394 return 0;
1396 break;
1397 case TT_PLATFORM_MACINTOSH:
1398 if (!IsValidCodePage( get_mac_code_page( name ))) return 0;
1399 if (name->language_id >= ARRAY_SIZE( mac_langid_table )) return 0;
1400 name_lang = mac_langid_table[name->language_id];
1401 break;
1402 case TT_PLATFORM_APPLE_UNICODE:
1403 res += 2; /* prefer Unicode encodings */
1404 switch (name->encoding_id)
1406 case TT_APPLE_ID_DEFAULT:
1407 case TT_APPLE_ID_ISO_10646:
1408 case TT_APPLE_ID_UNICODE_2_0:
1409 if (name->language_id >= ARRAY_SIZE( mac_langid_table )) return 0;
1410 name_lang = mac_langid_table[name->language_id];
1411 break;
1412 default:
1413 return 0;
1415 break;
1416 default:
1417 return 0;
1419 if (name_lang == lang) res += 30;
1420 else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20;
1421 else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10;
1422 return res;
1425 static WCHAR *copy_name_table_string( const FT_SfntName *name )
1427 WCHAR *ret;
1428 WORD codepage;
1429 int i;
1431 switch (name->platform_id)
1433 case TT_PLATFORM_APPLE_UNICODE:
1434 case TT_PLATFORM_MICROSOFT:
1435 ret = HeapAlloc( GetProcessHeap(), 0, name->string_len + sizeof(WCHAR) );
1436 for (i = 0; i < name->string_len / 2; i++)
1437 ret[i] = (name->string[i * 2] << 8) | name->string[i * 2 + 1];
1438 ret[i] = 0;
1439 return ret;
1440 case TT_PLATFORM_MACINTOSH:
1441 codepage = get_mac_code_page( name );
1442 i = MultiByteToWideChar( codepage, 0, (char *)name->string, name->string_len, NULL, 0 );
1443 ret = HeapAlloc( GetProcessHeap(), 0, (i + 1) * sizeof(WCHAR) );
1444 MultiByteToWideChar( codepage, 0, (char *)name->string, name->string_len, ret, i );
1445 ret[i] = 0;
1446 return ret;
1448 return NULL;
1451 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, LANGID language_id)
1453 FT_SfntName name;
1454 FT_UInt num_names, name_index;
1455 int res, best_lang = 0, best_index = -1;
1457 if (!FT_IS_SFNT(ft_face)) return NULL;
1459 num_names = pFT_Get_Sfnt_Name_Count( ft_face );
1461 for (name_index = 0; name_index < num_names; name_index++)
1463 if (pFT_Get_Sfnt_Name( ft_face, name_index, &name )) continue;
1464 if (name.name_id != name_id) continue;
1465 res = match_name_table_language( &name, language_id );
1466 if (res > best_lang)
1468 best_lang = res;
1469 best_index = name_index;
1473 if (best_index != -1 && !pFT_Get_Sfnt_Name( ft_face, best_index, &name ))
1475 WCHAR *ret = copy_name_table_string( &name );
1476 TRACE( "name %u found platform %u lang %04x %s\n",
1477 name_id, name.platform_id, name.language_id, debugstr_w( ret ));
1478 return ret;
1480 return NULL;
1483 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1485 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1486 if (f1->scalable) return TRUE;
1487 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1488 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1491 static void release_family( Family *family )
1493 if (--family->refcount) return;
1494 assert( list_empty( &family->faces ));
1495 list_remove( &family->entry );
1496 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1497 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1498 HeapFree( GetProcessHeap(), 0, family );
1501 static void release_face( Face *face )
1503 if (--face->refcount) return;
1504 if (face->family)
1506 if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
1507 list_remove( &face->entry );
1508 release_family( face->family );
1510 HeapFree( GetProcessHeap(), 0, face->file );
1511 HeapFree( GetProcessHeap(), 0, face->StyleName );
1512 HeapFree( GetProcessHeap(), 0, face->FullName );
1513 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1514 HeapFree( GetProcessHeap(), 0, face );
1517 static inline int style_order(const Face *face)
1519 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1521 case NTM_REGULAR:
1522 return 0;
1523 case NTM_BOLD:
1524 return 1;
1525 case NTM_ITALIC:
1526 return 2;
1527 case NTM_BOLD | NTM_ITALIC:
1528 return 3;
1529 default:
1530 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1531 debugstr_w(face->family->FamilyName),
1532 debugstr_w(face->StyleName),
1533 face->ntmFlags);
1534 return 9999;
1538 static BOOL insert_face_in_family_list( Face *face, Family *family )
1540 Face *cursor;
1542 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1544 if (faces_equal( face, cursor ))
1546 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1547 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1548 cursor->font_version, face->font_version);
1550 if (face->file && face->dev == cursor->dev && face->ino == cursor->ino)
1552 cursor->refcount++;
1553 TRACE("Font %s already in list, refcount now %d\n",
1554 debugstr_w(face->file), cursor->refcount);
1555 return FALSE;
1557 if (face->font_version <= cursor->font_version)
1559 TRACE("Original font %s is newer so skipping %s\n",
1560 debugstr_w(cursor->file), debugstr_w(face->file));
1561 return FALSE;
1563 else
1565 TRACE("Replacing original %s with %s\n",
1566 debugstr_w(cursor->file), debugstr_w(face->file));
1567 list_add_before( &cursor->entry, &face->entry );
1568 face->family = family;
1569 family->refcount++;
1570 face->refcount++;
1571 release_face( cursor );
1572 return TRUE;
1575 else
1576 TRACE("Adding new %s\n", debugstr_w(face->file));
1578 if (style_order( face ) < style_order( cursor )) break;
1581 list_add_before( &cursor->entry, &face->entry );
1582 face->family = family;
1583 family->refcount++;
1584 face->refcount++;
1585 return TRUE;
1588 /****************************************************************
1589 * NB This function stores the ptrs to the strings to save copying.
1590 * Don't free them after calling.
1592 static Family *create_family( WCHAR *name, WCHAR *english_name )
1594 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1595 family->refcount = 1;
1596 family->FamilyName = name;
1597 family->EnglishName = english_name;
1598 list_init( &family->faces );
1599 family->replacement = &family->faces;
1600 list_add_tail( &font_list, &family->entry );
1602 return family;
1605 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1607 DWORD type, size = sizeof(DWORD);
1609 if (RegQueryValueExW(hkey, value, NULL, &type, (BYTE *)data, &size) ||
1610 type != REG_DWORD || size != sizeof(DWORD))
1612 *data = 0;
1613 return ERROR_BAD_CONFIGURATION;
1615 return ERROR_SUCCESS;
1618 static inline LONG reg_load_ftlong(HKEY hkey, const WCHAR *value, FT_Long *data)
1620 DWORD dw;
1621 LONG ret = reg_load_dword(hkey, value, &dw);
1622 *data = dw;
1623 return ret;
1626 static inline LONG reg_load_ftshort(HKEY hkey, const WCHAR *value, FT_Short *data)
1628 DWORD dw;
1629 LONG ret = reg_load_dword(hkey, value, &dw);
1630 *data = dw;
1631 return ret;
1634 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1636 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1639 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1641 DWORD needed, strike_index = 0;
1642 HKEY hkey_strike;
1644 /* If we have a File Name key then this is a real font, not just the parent
1645 key of a bunch of non-scalable strikes */
1646 needed = buffer_size;
1647 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1649 Face *face;
1650 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1651 face->cached_enum_data = NULL;
1652 face->family = NULL;
1654 face->refcount = 1;
1655 face->file = strdupW( buffer );
1656 face->StyleName = strdupW(face_name);
1658 needed = buffer_size;
1659 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1660 face->FullName = strdupW( buffer );
1661 else
1662 face->FullName = NULL;
1664 reg_load_ftlong(hkey_face, face_index_value, &face->face_index);
1665 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1666 reg_load_ftlong(hkey_face, face_version_value, &face->font_version);
1667 reg_load_dword(hkey_face, face_flags_value, &face->flags);
1669 needed = sizeof(face->fs);
1670 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1672 if(reg_load_ftshort(hkey_face, face_height_value, &face->size.height) != ERROR_SUCCESS)
1674 face->scalable = TRUE;
1675 memset(&face->size, 0, sizeof(face->size));
1677 else
1679 face->scalable = FALSE;
1680 reg_load_ftshort(hkey_face, face_width_value, &face->size.width);
1681 reg_load_ftlong(hkey_face, face_size_value, &face->size.size);
1682 reg_load_ftlong(hkey_face, face_x_ppem_value, &face->size.x_ppem);
1683 reg_load_ftlong(hkey_face, face_y_ppem_value, &face->size.y_ppem);
1684 reg_load_ftshort(hkey_face, face_internal_leading_value, &face->size.internal_leading);
1686 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1687 face->size.height, face->size.width, face->size.size >> 6,
1688 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1691 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1692 face->fs.fsCsb[0], face->fs.fsCsb[1],
1693 face->fs.fsUsb[0], face->fs.fsUsb[1],
1694 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1696 if (insert_face_in_family_list(face, family))
1697 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1699 release_face( face );
1702 /* load bitmap strikes */
1704 needed = buffer_size;
1705 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1707 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1709 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1710 RegCloseKey(hkey_strike);
1712 needed = buffer_size;
1716 /* move vertical fonts after their horizontal counterpart */
1717 /* assumes that font_list is already sorted by family name */
1718 static void reorder_vertical_fonts(void)
1720 Family *family, *next, *vert_family;
1721 struct list *ptr, *vptr;
1722 struct list vertical_families = LIST_INIT( vertical_families );
1724 LIST_FOR_EACH_ENTRY_SAFE( family, next, &font_list, Family, entry )
1726 if (family->FamilyName[0] != '@') continue;
1727 list_remove( &family->entry );
1728 list_add_tail( &vertical_families, &family->entry );
1731 ptr = list_head( &font_list );
1732 vptr = list_head( &vertical_families );
1733 while (ptr && vptr)
1735 family = LIST_ENTRY( ptr, Family, entry );
1736 vert_family = LIST_ENTRY( vptr, Family, entry );
1737 if (strcmpiW( family->FamilyName, vert_family->FamilyName + 1 ) > 0)
1739 list_remove( vptr );
1740 list_add_before( ptr, vptr );
1741 vptr = list_head( &vertical_families );
1743 else ptr = list_next( &font_list, ptr );
1745 list_move_tail( &font_list, &vertical_families );
1748 static void load_font_list_from_cache(HKEY hkey_font_cache)
1750 DWORD size, family_index = 0;
1751 Family *family;
1752 HKEY hkey_family;
1753 WCHAR buffer[4096];
1755 size = sizeof(buffer);
1756 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1758 WCHAR *english_family = NULL;
1759 WCHAR *family_name = strdupW( buffer );
1760 DWORD face_index = 0;
1762 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1763 TRACE("opened family key %s\n", debugstr_w(family_name));
1764 size = sizeof(buffer);
1765 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1766 english_family = strdupW( buffer );
1768 family = create_family(family_name, english_family);
1770 if(english_family)
1772 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1773 subst->from.name = strdupW(english_family);
1774 subst->from.charset = -1;
1775 subst->to.name = strdupW(family_name);
1776 subst->to.charset = -1;
1777 add_font_subst(&font_subst_list, subst, 0);
1780 size = sizeof(buffer);
1781 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1783 WCHAR *face_name = strdupW( buffer );
1784 HKEY hkey_face;
1786 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1788 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1789 RegCloseKey(hkey_face);
1791 HeapFree( GetProcessHeap(), 0, face_name );
1792 size = sizeof(buffer);
1794 RegCloseKey(hkey_family);
1795 release_family( family );
1796 size = sizeof(buffer);
1799 reorder_vertical_fonts();
1802 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1804 LONG ret;
1805 HKEY hkey_wine_fonts;
1807 /* We don't want to create the fonts key as volatile, so open this first */
1808 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1809 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1810 if(ret != ERROR_SUCCESS)
1812 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1813 return ret;
1816 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1817 KEY_ALL_ACCESS, NULL, hkey, disposition);
1818 RegCloseKey(hkey_wine_fonts);
1819 return ret;
1822 static void add_face_to_cache(Face *face)
1824 HKEY hkey_family, hkey_face;
1825 WCHAR *face_key_name;
1827 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1828 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1829 if(face->family->EnglishName)
1830 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1831 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1833 if(face->scalable)
1834 face_key_name = face->StyleName;
1835 else
1837 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1838 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1839 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1841 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1842 &hkey_face, NULL);
1843 if(!face->scalable)
1844 HeapFree(GetProcessHeap(), 0, face_key_name);
1846 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1847 (strlenW(face->file) + 1) * sizeof(WCHAR));
1848 if (face->FullName)
1849 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1850 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1852 reg_save_dword(hkey_face, face_index_value, face->face_index);
1853 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1854 reg_save_dword(hkey_face, face_version_value, face->font_version);
1855 if (face->flags) reg_save_dword(hkey_face, face_flags_value, face->flags);
1857 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1859 if(!face->scalable)
1861 reg_save_dword(hkey_face, face_height_value, face->size.height);
1862 reg_save_dword(hkey_face, face_width_value, face->size.width);
1863 reg_save_dword(hkey_face, face_size_value, face->size.size);
1864 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1865 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1866 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1868 RegCloseKey(hkey_face);
1869 RegCloseKey(hkey_family);
1872 static void remove_face_from_cache( Face *face )
1874 HKEY hkey_family;
1876 RegOpenKeyExW( hkey_font_cache, face->family->FamilyName, 0, KEY_ALL_ACCESS, &hkey_family );
1878 if (face->scalable)
1880 RegDeleteKeyW( hkey_family, face->StyleName );
1882 else
1884 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1885 WCHAR *face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1886 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1887 RegDeleteKeyW( hkey_family, face_key_name );
1888 HeapFree(GetProcessHeap(), 0, face_key_name);
1890 RegCloseKey(hkey_family);
1893 static WCHAR *prepend_at(WCHAR *family)
1895 WCHAR *str;
1897 if (!family)
1898 return NULL;
1900 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1901 str[0] = '@';
1902 strcpyW(str + 1, family);
1903 HeapFree(GetProcessHeap(), 0, family);
1904 return str;
1907 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1909 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT) );
1910 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1912 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1913 if (!*name)
1915 *name = *english;
1916 *english = NULL;
1918 else if (!strcmpiW( *name, *english ))
1920 HeapFree( GetProcessHeap(), 0, *english );
1921 *english = NULL;
1924 if (vertical)
1926 *name = prepend_at( *name );
1927 *english = prepend_at( *english );
1931 static Family *get_family( FT_Face ft_face, BOOL vertical )
1933 Family *family;
1934 WCHAR *name, *english_name;
1936 get_family_names( ft_face, &name, &english_name, vertical );
1938 family = find_family_from_name( name );
1940 if (!family)
1942 family = create_family( name, english_name );
1943 if (english_name)
1945 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1946 subst->from.name = strdupW( english_name );
1947 subst->from.charset = -1;
1948 subst->to.name = strdupW( name );
1949 subst->to.charset = -1;
1950 add_font_subst( &font_subst_list, subst, 0 );
1953 else
1955 HeapFree( GetProcessHeap(), 0, name );
1956 HeapFree( GetProcessHeap(), 0, english_name );
1957 family->refcount++;
1960 return family;
1963 static inline FT_Fixed get_font_version( FT_Face ft_face )
1965 FT_Fixed version = 0;
1966 TT_Header *header;
1968 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1969 if (header) version = header->Font_Revision;
1971 return version;
1974 static inline DWORD get_ntm_flags( FT_Face ft_face )
1976 DWORD flags = 0;
1977 FT_ULong table_size = 0;
1978 FT_WinFNT_HeaderRec winfnt_header;
1980 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1981 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1983 /* fixup the flag for our fake-bold implementation. */
1984 if (!FT_IS_SCALABLE( ft_face ) &&
1985 !pFT_Get_WinFNT_Header( ft_face, &winfnt_header ) &&
1986 winfnt_header.weight > FW_NORMAL )
1987 flags |= NTM_BOLD;
1989 if (flags == 0) flags = NTM_REGULAR;
1991 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1992 flags |= NTM_PS_OPENTYPE;
1994 return flags;
1997 static inline void get_bitmap_size( FT_Face ft_face, Bitmap_Size *face_size )
1999 My_FT_Bitmap_Size *size;
2000 FT_WinFNT_HeaderRec winfnt_header;
2002 size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
2003 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
2004 size->height, size->width, size->size >> 6,
2005 size->x_ppem >> 6, size->y_ppem >> 6);
2006 face_size->height = size->height;
2007 face_size->width = size->width;
2008 face_size->size = size->size;
2009 face_size->x_ppem = size->x_ppem;
2010 face_size->y_ppem = size->y_ppem;
2012 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header )) {
2013 face_size->internal_leading = winfnt_header.internal_leading;
2014 if (winfnt_header.external_leading > 0 &&
2015 (face_size->height ==
2016 winfnt_header.pixel_height + winfnt_header.external_leading))
2017 face_size->height = winfnt_header.pixel_height;
2021 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
2023 TT_OS2 *os2;
2024 CHARSETINFO csi;
2025 FT_WinFNT_HeaderRec winfnt_header;
2026 int i;
2028 memset( fs, 0, sizeof(*fs) );
2030 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
2031 if (os2)
2033 fs->fsUsb[0] = os2->ulUnicodeRange1;
2034 fs->fsUsb[1] = os2->ulUnicodeRange2;
2035 fs->fsUsb[2] = os2->ulUnicodeRange3;
2036 fs->fsUsb[3] = os2->ulUnicodeRange4;
2038 if (os2->version == 0)
2040 if (os2->usFirstCharIndex >= 0xf000 && os2->usFirstCharIndex < 0xf100)
2041 fs->fsCsb[0] = FS_SYMBOL;
2042 else
2043 fs->fsCsb[0] = FS_LATIN1;
2045 else
2047 fs->fsCsb[0] = os2->ulCodePageRange1;
2048 fs->fsCsb[1] = os2->ulCodePageRange2;
2051 else
2053 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
2055 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
2056 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
2057 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
2058 *fs = csi.fs;
2062 if (fs->fsCsb[0] == 0)
2064 /* let's see if we can find any interesting cmaps */
2065 for (i = 0; i < ft_face->num_charmaps; i++)
2067 switch (ft_face->charmaps[i]->encoding)
2069 case FT_ENCODING_UNICODE:
2070 case FT_ENCODING_APPLE_ROMAN:
2071 fs->fsCsb[0] |= FS_LATIN1;
2072 break;
2073 case FT_ENCODING_MS_SYMBOL:
2074 fs->fsCsb[0] |= FS_SYMBOL;
2075 break;
2076 default:
2077 break;
2083 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
2084 DWORD flags )
2086 struct stat st;
2087 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
2089 face->refcount = 1;
2090 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
2091 if (!face->StyleName) face->StyleName = towstr( CP_ACP, ft_face->style_name );
2093 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
2094 if (flags & ADDFONT_VERTICAL_FONT)
2095 face->FullName = prepend_at( face->FullName );
2097 face->dev = 0;
2098 face->ino = 0;
2099 if (file)
2101 face->file = towstr( CP_UNIXCP, file );
2102 face->font_data_ptr = NULL;
2103 face->font_data_size = 0;
2104 if (!stat( file, &st ))
2106 face->dev = st.st_dev;
2107 face->ino = st.st_ino;
2110 else
2112 face->file = NULL;
2113 face->font_data_ptr = font_data_ptr;
2114 face->font_data_size = font_data_size;
2117 face->face_index = face_index;
2118 get_fontsig( ft_face, &face->fs );
2119 face->ntmFlags = get_ntm_flags( ft_face );
2120 face->font_version = get_font_version( ft_face );
2122 if (FT_IS_SCALABLE( ft_face ))
2124 memset( &face->size, 0, sizeof(face->size) );
2125 face->scalable = TRUE;
2127 else
2129 get_bitmap_size( ft_face, &face->size );
2130 face->scalable = FALSE;
2133 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
2134 face->flags = flags;
2135 face->family = NULL;
2136 face->cached_enum_data = NULL;
2138 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
2139 face->fs.fsCsb[0], face->fs.fsCsb[1],
2140 face->fs.fsUsb[0], face->fs.fsUsb[1],
2141 face->fs.fsUsb[2], face->fs.fsUsb[3]);
2143 return face;
2146 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
2147 FT_Long face_index, DWORD flags )
2149 Face *face;
2150 Family *family;
2152 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags );
2153 family = get_family( ft_face, flags & ADDFONT_VERTICAL_FONT );
2155 if (insert_face_in_family_list( face, family ))
2157 if (flags & ADDFONT_ADD_TO_CACHE)
2158 add_face_to_cache( face );
2160 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
2161 debugstr_w(face->StyleName));
2163 release_face( face );
2164 release_family( family );
2167 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
2168 FT_Long face_index, BOOL allow_bitmap )
2170 FT_Error err;
2171 TT_OS2 *pOS2;
2172 FT_Face ft_face;
2174 if (file)
2176 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
2177 err = pFT_New_Face(library, file, face_index, &ft_face);
2179 else
2181 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
2182 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
2185 if (err != 0)
2187 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
2188 return NULL;
2191 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
2192 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < FT_VERSION_VALUE(2, 1, 9))
2194 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
2195 goto fail;
2198 if (!FT_IS_SFNT( ft_face ))
2200 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
2202 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
2203 goto fail;
2206 else
2208 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
2209 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
2210 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
2212 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
2213 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
2214 goto fail;
2217 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
2218 we don't want to load these. */
2219 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
2221 FT_ULong len = 0;
2223 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
2225 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
2226 goto fail;
2231 if (!ft_face->family_name || !ft_face->style_name)
2233 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
2234 goto fail;
2237 return ft_face;
2238 fail:
2239 pFT_Done_Face( ft_face );
2240 return NULL;
2243 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
2245 FT_Face ft_face;
2246 FT_Long face_index = 0, num_faces;
2247 INT ret = 0;
2249 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
2250 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
2252 #ifdef HAVE_CARBON_CARBON_H
2253 if(file)
2255 char **mac_list = expand_mac_font(file);
2256 if(mac_list)
2258 BOOL had_one = FALSE;
2259 char **cursor;
2260 for(cursor = mac_list; *cursor; cursor++)
2262 had_one = TRUE;
2263 AddFontToList(*cursor, NULL, 0, flags);
2264 HeapFree(GetProcessHeap(), 0, *cursor);
2266 HeapFree(GetProcessHeap(), 0, mac_list);
2267 if(had_one)
2268 return 1;
2271 #endif /* HAVE_CARBON_CARBON_H */
2273 do {
2274 const DWORD FS_DBCS_MASK = FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB;
2275 FONTSIGNATURE fs;
2277 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_ALLOW_BITMAP );
2278 if (!ft_face) return 0;
2280 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
2282 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
2283 pFT_Done_Face(ft_face);
2284 return 0;
2287 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags);
2288 ++ret;
2290 get_fontsig(ft_face, &fs);
2291 if (fs.fsCsb[0] & FS_DBCS_MASK)
2293 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index,
2294 flags | ADDFONT_VERTICAL_FONT);
2295 ++ret;
2298 num_faces = ft_face->num_faces;
2299 pFT_Done_Face(ft_face);
2300 } while(num_faces > ++face_index);
2301 return ret;
2304 static int remove_font_resource( const char *file, DWORD flags )
2306 Family *family, *family_next;
2307 Face *face, *face_next;
2308 struct stat st;
2309 int count = 0;
2311 if (stat( file, &st ) == -1) return 0;
2312 LIST_FOR_EACH_ENTRY_SAFE( family, family_next, &font_list, Family, entry )
2314 family->refcount++;
2315 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, Face, entry )
2317 if (!face->file) continue;
2318 if (LOWORD(face->flags) != LOWORD(flags)) continue;
2319 if (st.st_dev == face->dev && st.st_ino == face->ino)
2321 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount );
2322 release_face( face );
2323 count++;
2326 release_family( family );
2328 return count;
2331 static void DumpFontList(void)
2333 Family *family;
2334 Face *face;
2336 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2337 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
2338 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2339 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
2340 if(!face->scalable)
2341 TRACE(" %d", face->size.height);
2342 TRACE("\n");
2347 static BOOL map_font_family(const WCHAR *orig, const WCHAR *repl)
2349 Family *family = find_family_from_any_name(repl);
2350 if (family != NULL)
2352 Family *new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2353 if (new_family != NULL)
2355 TRACE("mapping %s to %s\n", debugstr_w(repl), debugstr_w(orig));
2356 new_family->FamilyName = strdupW(orig);
2357 new_family->EnglishName = NULL;
2358 list_init(&new_family->faces);
2359 new_family->replacement = &family->faces;
2360 list_add_tail(&font_list, &new_family->entry);
2361 return TRUE;
2364 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(repl));
2365 return FALSE;
2368 /***********************************************************
2369 * The replacement list is a way to map an entire font
2370 * family onto another family. For example adding
2372 * [HKCU\Software\Wine\Fonts\Replacements]
2373 * "Wingdings"="Winedings"
2375 * would enumerate the Winedings font both as Winedings and
2376 * Wingdings. However if a real Wingdings font is present the
2377 * replacement does not take place.
2380 static void LoadReplaceList(void)
2382 HKEY hkey;
2383 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2384 LPWSTR value;
2385 LPVOID data;
2387 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2388 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
2390 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2391 &valuelen, &datalen, NULL, NULL);
2393 valuelen++; /* returned value doesn't include room for '\0' */
2394 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2395 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2397 dlen = datalen;
2398 vlen = valuelen;
2399 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data, &dlen) == ERROR_SUCCESS)
2401 /* "NewName"="Oldname" */
2402 if(!find_family_from_any_name(value))
2404 if (type == REG_MULTI_SZ)
2406 WCHAR *replace = data;
2407 while(*replace)
2409 if (map_font_family(value, replace))
2410 break;
2411 replace += strlenW(replace) + 1;
2414 else if (type == REG_SZ)
2415 map_font_family(value, data);
2417 else
2418 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2420 /* reset dlen and vlen */
2421 dlen = datalen;
2422 vlen = valuelen;
2424 HeapFree(GetProcessHeap(), 0, data);
2425 HeapFree(GetProcessHeap(), 0, value);
2426 RegCloseKey(hkey);
2430 static const WCHAR *font_links_list[] =
2432 Lucida_Sans_Unicode,
2433 Microsoft_Sans_Serif,
2434 Tahoma
2437 static const struct font_links_defaults_list
2439 /* Keyed off substitution for "MS Shell Dlg" */
2440 const WCHAR *shelldlg;
2441 /* Maximum of four substitutes, plus terminating NULL pointer */
2442 const WCHAR *substitutes[5];
2443 } font_links_defaults_list[] =
2445 /* Non East-Asian */
2446 { Tahoma, /* FIXME unverified ordering */
2447 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2449 /* Below lists are courtesy of
2450 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2452 /* Japanese */
2453 { MS_UI_Gothic,
2454 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2456 /* Chinese Simplified */
2457 { SimSun,
2458 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2460 /* Korean */
2461 { Gulim,
2462 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2464 /* Chinese Traditional */
2465 { PMingLiU,
2466 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2471 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2473 SYSTEM_LINKS *font_link;
2475 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2477 if(!strncmpiW(font_link->font_name, name, LF_FACESIZE - 1))
2478 return font_link;
2481 return NULL;
2484 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2486 const WCHAR *value;
2487 int i;
2488 FontSubst *psub;
2489 Family *family;
2490 Face *face;
2491 const WCHAR *file;
2493 if (values)
2495 SYSTEM_LINKS *font_link;
2497 psub = get_font_subst(&font_subst_list, name, -1);
2498 /* Don't store fonts that are only substitutes for other fonts */
2499 if(psub)
2501 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2502 return;
2505 font_link = find_font_link(name);
2506 if (font_link == NULL)
2508 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2509 font_link->font_name = strdupW(name);
2510 list_init(&font_link->links);
2511 list_add_tail(&system_links, &font_link->entry);
2514 memset(&font_link->fs, 0, sizeof font_link->fs);
2515 for (i = 0; values[i] != NULL; i++)
2517 const struct list *face_list;
2518 CHILD_FONT *child_font;
2520 value = values[i];
2521 if (!strcmpiW(name,value))
2522 continue;
2523 psub = get_font_subst(&font_subst_list, value, -1);
2524 if(psub)
2525 value = psub->to.name;
2526 family = find_family_from_name(value);
2527 if (!family)
2528 continue;
2529 file = NULL;
2530 /* Use first extant filename for this Family */
2531 face_list = get_face_list_from_family(family);
2532 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2534 if (!face->file)
2535 continue;
2536 file = strrchrW(face->file, '/');
2537 if (!file)
2538 file = face->file;
2539 else
2540 file++;
2541 break;
2543 if (!file)
2544 continue;
2545 face = find_face_from_filename(file, value);
2546 if(!face)
2548 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2549 continue;
2552 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2553 child_font->face = face;
2554 child_font->font = NULL;
2555 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2556 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2557 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2558 child_font->face->face_index);
2559 list_add_tail(&font_link->links, &child_font->entry);
2561 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2567 /*************************************************************
2568 * init_system_links
2570 static void init_system_links(void)
2572 HKEY hkey;
2573 DWORD type, max_val, max_data, val_len, data_len, index;
2574 WCHAR *value, *data;
2575 WCHAR *entry, *next;
2576 SYSTEM_LINKS *font_link, *system_font_link;
2577 CHILD_FONT *child_font;
2578 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2579 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2580 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2581 Face *face;
2582 FontSubst *psub;
2583 UINT i, j;
2585 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2587 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2588 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2589 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2590 val_len = max_val + 1;
2591 data_len = max_data;
2592 index = 0;
2593 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2595 psub = get_font_subst(&font_subst_list, value, -1);
2596 /* Don't store fonts that are only substitutes for other fonts */
2597 if(psub)
2599 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2600 goto next;
2602 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2603 font_link->font_name = strdupW(value);
2604 memset(&font_link->fs, 0, sizeof font_link->fs);
2605 list_init(&font_link->links);
2606 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2608 WCHAR *face_name;
2609 CHILD_FONT *child_font;
2611 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2613 next = entry + strlenW(entry) + 1;
2615 face_name = strchrW(entry, ',');
2616 if(face_name)
2618 *face_name++ = 0;
2619 while(isspaceW(*face_name))
2620 face_name++;
2622 psub = get_font_subst(&font_subst_list, face_name, -1);
2623 if(psub)
2624 face_name = psub->to.name;
2626 face = find_face_from_filename(entry, face_name);
2627 if(!face)
2629 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2630 continue;
2633 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2634 child_font->face = face;
2635 child_font->font = NULL;
2636 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2637 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2638 TRACE("Adding file %s index %ld\n",
2639 debugstr_w(child_font->face->file), child_font->face->face_index);
2640 list_add_tail(&font_link->links, &child_font->entry);
2642 list_add_tail(&system_links, &font_link->entry);
2643 next:
2644 val_len = max_val + 1;
2645 data_len = max_data;
2648 HeapFree(GetProcessHeap(), 0, value);
2649 HeapFree(GetProcessHeap(), 0, data);
2650 RegCloseKey(hkey);
2654 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2655 if (!psub) {
2656 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2657 goto skip_internal;
2660 for (i = 0; i < ARRAY_SIZE(font_links_defaults_list); i++)
2662 const FontSubst *psub2;
2663 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2665 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2667 for (j = 0; j < ARRAY_SIZE(font_links_list); j++)
2668 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2670 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2671 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2673 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2675 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2679 skip_internal:
2681 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2682 that Tahoma has */
2684 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2685 system_font_link->font_name = strdupW(System);
2686 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2687 list_init(&system_font_link->links);
2689 face = find_face_from_filename(tahoma_ttf, Tahoma);
2690 if(face)
2692 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2693 child_font->face = face;
2694 child_font->font = NULL;
2695 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2696 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2697 TRACE("Found Tahoma in %s index %ld\n",
2698 debugstr_w(child_font->face->file), child_font->face->face_index);
2699 list_add_tail(&system_font_link->links, &child_font->entry);
2701 font_link = find_font_link(Tahoma);
2702 if (font_link != NULL)
2704 CHILD_FONT *font_link_entry;
2705 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2707 CHILD_FONT *new_child;
2708 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2709 new_child->face = font_link_entry->face;
2710 new_child->font = NULL;
2711 new_child->face->refcount++;
2712 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2713 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2714 list_add_tail(&system_font_link->links, &new_child->entry);
2717 list_add_tail(&system_links, &system_font_link->entry);
2720 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2722 DIR *dir;
2723 struct dirent *dent;
2724 char path[MAX_PATH];
2726 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2728 dir = opendir(dirname);
2729 if(!dir) {
2730 WARN("Can't open directory %s\n", debugstr_a(dirname));
2731 return FALSE;
2733 while((dent = readdir(dir)) != NULL) {
2734 struct stat statbuf;
2736 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2737 continue;
2739 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2741 sprintf(path, "%s/%s", dirname, dent->d_name);
2743 if(stat(path, &statbuf) == -1)
2745 WARN("Can't stat %s\n", debugstr_a(path));
2746 continue;
2748 if(S_ISDIR(statbuf.st_mode))
2749 ReadFontDir(path, external_fonts);
2750 else
2752 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2753 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2754 AddFontToList(path, NULL, 0, addfont_flags);
2757 closedir(dir);
2758 return TRUE;
2761 #ifdef SONAME_LIBFONTCONFIG
2763 static BOOL fontconfig_enabled;
2765 static UINT parse_aa_pattern( FcPattern *pattern )
2767 FcBool antialias;
2768 int rgba;
2769 UINT aa_flags = 0;
2771 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2772 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2774 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2776 switch (rgba)
2778 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2779 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2780 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2781 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2782 case FC_RGBA_NONE: aa_flags = aa_flags ? aa_flags : GGO_GRAY4_BITMAP; break;
2785 return aa_flags;
2788 static void init_fontconfig(void)
2790 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2792 if (!fc_handle)
2794 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2795 return;
2798 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2799 LOAD_FUNCPTR(FcConfigSubstitute);
2800 LOAD_FUNCPTR(FcDefaultSubstitute);
2801 LOAD_FUNCPTR(FcFontList);
2802 LOAD_FUNCPTR(FcFontMatch);
2803 LOAD_FUNCPTR(FcFontSetDestroy);
2804 LOAD_FUNCPTR(FcInit);
2805 LOAD_FUNCPTR(FcPatternAddString);
2806 LOAD_FUNCPTR(FcPatternCreate);
2807 LOAD_FUNCPTR(FcPatternDestroy);
2808 LOAD_FUNCPTR(FcPatternGetBool);
2809 LOAD_FUNCPTR(FcPatternGetInteger);
2810 LOAD_FUNCPTR(FcPatternGetString);
2811 #undef LOAD_FUNCPTR
2813 if (pFcInit())
2815 FcPattern *pattern = pFcPatternCreate();
2816 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2817 default_aa_flags = parse_aa_pattern( pattern );
2818 pFcPatternDestroy( pattern );
2820 if (!default_aa_flags)
2822 FcPattern *pattern = pFcPatternCreate();
2823 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
2824 default_aa_flags = parse_aa_pattern( pattern );
2825 pFcPatternDestroy( pattern );
2828 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2829 fontconfig_enabled = TRUE;
2833 static void load_fontconfig_fonts(void)
2835 FcPattern *pat;
2836 FcFontSet *fontset;
2837 int i, len;
2838 char *file;
2839 const char *ext;
2841 if (!fontconfig_enabled) return;
2843 pat = pFcPatternCreate();
2844 if (!pat) return;
2846 fontset = pFcFontList(NULL, pat, NULL);
2847 if (!fontset)
2849 pFcPatternDestroy(pat);
2850 return;
2853 for(i = 0; i < fontset->nfont; i++) {
2854 FcBool scalable;
2855 DWORD aa_flags;
2857 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2858 continue;
2860 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2862 /* We're just interested in OT/TT fonts for now, so this hack just
2863 picks up the scalable fonts without extensions .pf[ab] to save time
2864 loading every other font */
2866 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2868 TRACE("not scalable\n");
2869 continue;
2872 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2873 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2875 len = strlen( file );
2876 if(len < 4) continue;
2877 ext = &file[ len - 3 ];
2878 if(_strnicmp(ext, "pfa", -1) && _strnicmp(ext, "pfb", -1))
2879 AddFontToList(file, NULL, 0,
2880 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2882 pFcFontSetDestroy(fontset);
2883 pFcPatternDestroy(pat);
2886 #elif defined(HAVE_CARBON_CARBON_H)
2888 static void load_mac_font_callback(const void *value, void *context)
2890 CFStringRef pathStr = value;
2891 CFIndex len;
2892 char* path;
2894 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2895 path = HeapAlloc(GetProcessHeap(), 0, len);
2896 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2898 TRACE("font file %s\n", path);
2899 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2901 HeapFree(GetProcessHeap(), 0, path);
2904 static void load_mac_fonts(void)
2906 CFStringRef removeDupesKey;
2907 CFBooleanRef removeDupesValue;
2908 CFDictionaryRef options;
2909 CTFontCollectionRef col;
2910 CFArrayRef descs;
2911 CFMutableSetRef paths;
2912 CFIndex i;
2914 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2915 removeDupesValue = kCFBooleanTrue;
2916 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2917 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2918 col = CTFontCollectionCreateFromAvailableFonts(options);
2919 if (options) CFRelease(options);
2920 if (!col)
2922 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2923 return;
2926 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2927 CFRelease(col);
2928 if (!descs)
2930 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2931 return;
2934 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2935 if (!paths)
2937 WARN("CFSetCreateMutable failed\n");
2938 CFRelease(descs);
2939 return;
2942 for (i = 0; i < CFArrayGetCount(descs); i++)
2944 CTFontDescriptorRef desc;
2945 CFURLRef url;
2946 CFStringRef ext;
2947 CFStringRef path;
2949 desc = CFArrayGetValueAtIndex(descs, i);
2951 #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2952 url = CTFontDescriptorCopyAttribute(desc, kCTFontURLAttribute);
2953 #else
2954 /* CTFontDescriptor doesn't support kCTFontURLAttribute prior to 10.6, so
2955 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2957 CTFontRef font;
2958 ATSFontRef atsFont;
2959 OSStatus status;
2960 FSRef fsref;
2962 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2963 if (!font) continue;
2965 atsFont = CTFontGetPlatformFont(font, NULL);
2966 if (!atsFont)
2968 CFRelease(font);
2969 continue;
2972 status = ATSFontGetFileReference(atsFont, &fsref);
2973 CFRelease(font);
2974 if (status != noErr) continue;
2976 url = CFURLCreateFromFSRef(NULL, &fsref);
2978 #endif
2979 if (!url) continue;
2981 ext = CFURLCopyPathExtension(url);
2982 if (ext)
2984 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2985 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2986 CFRelease(ext);
2987 if (skip)
2989 CFRelease(url);
2990 continue;
2994 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2995 CFRelease(url);
2996 if (!path) continue;
2998 CFSetAddValue(paths, path);
2999 CFRelease(path);
3002 CFRelease(descs);
3004 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
3005 CFRelease(paths);
3008 #endif
3010 static char *get_font_dir(void)
3012 const char *build_dir, *data_dir;
3013 char *name = NULL;
3015 if ((data_dir = wine_get_data_dir()))
3017 if (!(name = HeapAlloc( GetProcessHeap(), 0, strlen(data_dir) + 1 + sizeof(WINE_FONT_DIR) )))
3018 return NULL;
3019 strcpy( name, data_dir );
3020 strcat( name, "/" );
3021 strcat( name, WINE_FONT_DIR );
3023 else if ((build_dir = wine_get_build_dir()))
3025 if (!(name = HeapAlloc( GetProcessHeap(), 0, strlen(build_dir) + sizeof("/fonts") )))
3026 return NULL;
3027 strcpy( name, build_dir );
3028 strcat( name, "/fonts" );
3030 return name;
3033 static char *get_data_dir_path( LPCWSTR file )
3035 char *unix_name = NULL;
3036 char *font_dir = get_font_dir();
3038 if (font_dir)
3040 INT len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
3042 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(font_dir) + len + 1 );
3043 strcpy(unix_name, font_dir);
3044 strcat(unix_name, "/");
3046 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
3047 HeapFree( GetProcessHeap(), 0, font_dir );
3049 return unix_name;
3052 static BOOL load_font_from_data_dir(LPCWSTR file)
3054 BOOL ret = FALSE;
3055 char *unix_name = get_data_dir_path( file );
3057 if (unix_name)
3059 EnterCriticalSection( &freetype_cs );
3060 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3061 LeaveCriticalSection( &freetype_cs );
3062 HeapFree(GetProcessHeap(), 0, unix_name);
3064 return ret;
3067 static char *get_winfonts_dir_path(LPCWSTR file)
3069 static const WCHAR slashW[] = {'\\','\0'};
3070 WCHAR windowsdir[MAX_PATH];
3072 GetWindowsDirectoryW(windowsdir, ARRAY_SIZE(windowsdir));
3073 strcatW(windowsdir, fontsW);
3074 strcatW(windowsdir, slashW);
3075 strcatW(windowsdir, file);
3076 return wine_get_unix_file_name( windowsdir );
3079 static void load_system_fonts(void)
3081 HKEY hkey;
3082 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
3083 const WCHAR * const *value;
3084 DWORD dlen, type;
3085 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3086 char *unixname;
3088 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
3089 GetWindowsDirectoryW(windowsdir, ARRAY_SIZE(windowsdir));
3090 strcatW(windowsdir, fontsW);
3091 for(value = SystemFontValues; *value; value++) {
3092 dlen = sizeof(data);
3093 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
3094 type == REG_SZ) {
3095 BOOL added = FALSE;
3097 sprintfW(pathW, fmtW, windowsdir, data);
3098 if((unixname = wine_get_unix_file_name(pathW))) {
3099 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3100 HeapFree(GetProcessHeap(), 0, unixname);
3102 if (!added)
3103 load_font_from_data_dir(data);
3106 RegCloseKey(hkey);
3110 static WCHAR *get_full_path_name(const WCHAR *name)
3112 WCHAR *full_path;
3113 DWORD len;
3115 if (!(len = GetFullPathNameW(name, 0, NULL, NULL)))
3117 ERR("GetFullPathNameW() failed, name %s.\n", debugstr_w(name));
3118 return NULL;
3121 if (!(full_path = HeapAlloc(GetProcessHeap(), 0, len * sizeof(*full_path))))
3123 ERR("Could not get memory.\n");
3124 return NULL;
3127 if (GetFullPathNameW(name, len, full_path, NULL) != len - 1)
3129 ERR("Unexpected GetFullPathNameW() result, name %s.\n", debugstr_w(name));
3130 HeapFree(GetProcessHeap(), 0, full_path);
3131 return NULL;
3134 return full_path;
3137 /*************************************************************
3139 * This adds registry entries for any externally loaded fonts
3140 * (fonts from fontconfig or FontDirs). It also deletes entries
3141 * of no longer existing fonts.
3144 static void update_reg_entries(void)
3146 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
3147 LPWSTR valueW;
3148 DWORD len;
3149 Family *family;
3150 Face *face;
3151 WCHAR *file, *path, *full_path;
3152 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
3154 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
3155 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
3156 ERR("Can't create Windows font reg key\n");
3157 goto end;
3160 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
3161 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
3162 ERR("Can't create Windows font reg key\n");
3163 goto end;
3166 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
3167 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
3168 ERR("Can't create external font reg key\n");
3169 goto end;
3172 /* enumerate the fonts and add external ones to the two keys */
3174 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
3175 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
3176 char *buffer;
3177 WCHAR *name;
3179 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
3181 name = face->FullName ? face->FullName : family->FamilyName;
3183 len = strlenW(name) + 1;
3184 if (face->scalable)
3185 len += ARRAY_SIZE(TrueType);
3187 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3188 strcpyW(valueW, name);
3190 if (face->scalable)
3191 strcatW(valueW, TrueType);
3193 buffer = strWtoA( CP_UNIXCP, face->file );
3194 path = wine_get_dos_file_name( buffer );
3195 HeapFree( GetProcessHeap(), 0, buffer );
3197 if (path)
3199 if ((full_path = get_full_path_name(path)))
3201 HeapFree(GetProcessHeap(), 0, path);
3202 path = full_path;
3204 file = path;
3206 else if ((file = strrchrW(face->file, '/')))
3208 file++;
3210 else
3212 file = face->file;
3215 len = strlenW(file) + 1;
3216 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3217 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3218 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3220 HeapFree(GetProcessHeap(), 0, path);
3221 HeapFree(GetProcessHeap(), 0, valueW);
3224 end:
3225 if(external_key) RegCloseKey(external_key);
3226 if(win9x_key) RegCloseKey(win9x_key);
3227 if(winnt_key) RegCloseKey(winnt_key);
3230 static void delete_external_font_keys(void)
3232 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
3233 DWORD dlen, plen, vlen, datalen, valuelen, i, type, path_type;
3234 LPWSTR valueW;
3235 LPVOID data;
3236 BYTE *path;
3238 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
3239 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
3240 ERR("Can't create Windows font reg key\n");
3241 goto end;
3244 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
3245 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
3246 ERR("Can't create Windows font reg key\n");
3247 goto end;
3250 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
3251 ERR("Can't create external font reg key\n");
3252 goto end;
3255 /* Delete all external fonts added last time */
3257 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3258 &valuelen, &datalen, NULL, NULL);
3259 valuelen++; /* returned value doesn't include room for '\0' */
3260 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3261 data = HeapAlloc(GetProcessHeap(), 0, datalen);
3262 path = HeapAlloc(GetProcessHeap(), 0, datalen);
3264 dlen = datalen;
3265 vlen = valuelen;
3266 i = 0;
3267 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
3268 &dlen) == ERROR_SUCCESS) {
3269 plen = dlen;
3270 if (RegQueryValueExW(winnt_key, valueW, 0, &path_type, path, &plen) == ERROR_SUCCESS &&
3271 type == path_type && dlen == plen && !memcmp(data, path, plen))
3272 RegDeleteValueW(winnt_key, valueW);
3274 plen = dlen;
3275 if (RegQueryValueExW(win9x_key, valueW, 0, &path_type, path, &plen) == ERROR_SUCCESS &&
3276 type == path_type && dlen == plen && !memcmp(data, path, plen))
3277 RegDeleteValueW(win9x_key, valueW);
3279 /* reset dlen and vlen */
3280 dlen = datalen;
3281 vlen = valuelen;
3283 HeapFree(GetProcessHeap(), 0, path);
3284 HeapFree(GetProcessHeap(), 0, data);
3285 HeapFree(GetProcessHeap(), 0, valueW);
3287 /* Delete the old external fonts key */
3288 RegCloseKey(external_key);
3289 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
3291 end:
3292 if(win9x_key) RegCloseKey(win9x_key);
3293 if(winnt_key) RegCloseKey(winnt_key);
3296 /*************************************************************
3297 * WineEngAddFontResourceEx
3300 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3302 INT ret = 0;
3304 GDI_CheckNotLock();
3306 if (ft_handle) /* do it only if we have freetype up and running */
3308 char *unixname;
3310 EnterCriticalSection( &freetype_cs );
3312 if((unixname = wine_get_unix_file_name(file)))
3314 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3316 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3317 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
3318 HeapFree(GetProcessHeap(), 0, unixname);
3320 if (!ret && !strchrW(file, '\\')) {
3321 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
3322 if ((unixname = get_winfonts_dir_path( file )))
3324 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3325 HeapFree(GetProcessHeap(), 0, unixname);
3327 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
3328 if (!ret && (unixname = get_data_dir_path( file )))
3330 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3331 HeapFree(GetProcessHeap(), 0, unixname);
3335 LeaveCriticalSection( &freetype_cs );
3337 return ret;
3340 /*************************************************************
3341 * WineEngAddFontMemResourceEx
3344 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3346 GDI_CheckNotLock();
3348 if (ft_handle) /* do it only if we have freetype up and running */
3350 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
3352 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
3353 memcpy(pFontCopy, pbFont, cbFont);
3355 EnterCriticalSection( &freetype_cs );
3356 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3357 LeaveCriticalSection( &freetype_cs );
3359 if (*pcFonts == 0)
3361 TRACE("AddFontToList failed\n");
3362 HeapFree(GetProcessHeap(), 0, pFontCopy);
3363 return 0;
3365 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
3366 * For now return something unique but quite random
3368 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
3369 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
3372 *pcFonts = 0;
3373 return 0;
3376 /*************************************************************
3377 * WineEngRemoveFontResourceEx
3380 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3382 INT ret = 0;
3384 GDI_CheckNotLock();
3386 if (ft_handle) /* do it only if we have freetype up and running */
3388 char *unixname;
3390 EnterCriticalSection( &freetype_cs );
3392 if ((unixname = wine_get_unix_file_name(file)))
3394 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3396 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3397 ret = remove_font_resource( unixname, addfont_flags );
3398 HeapFree(GetProcessHeap(), 0, unixname);
3400 if (!ret && !strchrW(file, '\\'))
3402 if ((unixname = get_winfonts_dir_path( file )))
3404 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3405 HeapFree(GetProcessHeap(), 0, unixname);
3407 if (!ret && (unixname = get_data_dir_path( file )))
3409 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3410 HeapFree(GetProcessHeap(), 0, unixname);
3414 LeaveCriticalSection( &freetype_cs );
3416 return ret;
3419 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
3421 WCHAR *fullname;
3422 char *unix_name;
3423 int file_len;
3425 if (!font_file) return NULL;
3427 file_len = strlenW( font_file );
3429 if (font_path && font_path[0])
3431 int path_len = strlenW( font_path );
3432 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
3433 if (!fullname) return NULL;
3434 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
3435 fullname[path_len] = '\\';
3436 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
3438 else
3440 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
3441 if (!len) return NULL;
3442 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3443 if (!fullname) return NULL;
3444 GetFullPathNameW( font_file, len, fullname, NULL );
3447 unix_name = wine_get_unix_file_name( fullname );
3448 HeapFree( GetProcessHeap(), 0, fullname );
3449 return unix_name;
3452 #include <pshpack1.h>
3453 struct fontdir
3455 WORD num_of_resources;
3456 WORD res_id;
3457 WORD dfVersion;
3458 DWORD dfSize;
3459 CHAR dfCopyright[60];
3460 WORD dfType;
3461 WORD dfPoints;
3462 WORD dfVertRes;
3463 WORD dfHorizRes;
3464 WORD dfAscent;
3465 WORD dfInternalLeading;
3466 WORD dfExternalLeading;
3467 BYTE dfItalic;
3468 BYTE dfUnderline;
3469 BYTE dfStrikeOut;
3470 WORD dfWeight;
3471 BYTE dfCharSet;
3472 WORD dfPixWidth;
3473 WORD dfPixHeight;
3474 BYTE dfPitchAndFamily;
3475 WORD dfAvgWidth;
3476 WORD dfMaxWidth;
3477 BYTE dfFirstChar;
3478 BYTE dfLastChar;
3479 BYTE dfDefaultChar;
3480 BYTE dfBreakChar;
3481 WORD dfWidthBytes;
3482 DWORD dfDevice;
3483 DWORD dfFace;
3484 DWORD dfReserved;
3485 CHAR szFaceName[LF_FACESIZE];
3488 #include <poppack.h>
3490 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
3491 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
3493 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
3495 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3496 Face *face;
3497 WCHAR *name, *english_name;
3498 ENUMLOGFONTEXW elf;
3499 NEWTEXTMETRICEXW ntm;
3500 DWORD type;
3502 if (!ft_face) return FALSE;
3503 face = create_face( ft_face, 0, unix_name, NULL, 0, 0 );
3504 get_family_names( ft_face, &name, &english_name, FALSE );
3505 pFT_Done_Face( ft_face );
3507 GetEnumStructs( face, name, &elf, &ntm, &type );
3508 release_face( face );
3509 HeapFree( GetProcessHeap(), 0, name );
3510 HeapFree( GetProcessHeap(), 0, english_name );
3512 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3514 memset( fd, 0, sizeof(*fd) );
3516 fd->num_of_resources = 1;
3517 fd->res_id = 0;
3518 fd->dfVersion = 0x200;
3519 fd->dfSize = sizeof(*fd);
3520 strcpy( fd->dfCopyright, "Wine fontdir" );
3521 fd->dfType = 0x4003; /* 0x0080 set if private */
3522 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3523 fd->dfVertRes = 72;
3524 fd->dfHorizRes = 72;
3525 fd->dfAscent = ntm.ntmTm.tmAscent;
3526 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3527 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3528 fd->dfItalic = ntm.ntmTm.tmItalic;
3529 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3530 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3531 fd->dfWeight = ntm.ntmTm.tmWeight;
3532 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3533 fd->dfPixWidth = 0;
3534 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3535 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3536 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3537 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3538 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3539 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3540 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3541 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3542 fd->dfWidthBytes = 0;
3543 fd->dfDevice = 0;
3544 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3545 fd->dfReserved = 0;
3546 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3548 return TRUE;
3551 #define NE_FFLAGS_LIBMODULE 0x8000
3552 #define NE_OSFLAGS_WINDOWS 0x02
3554 static const char dos_string[0x40] = "This is a TrueType resource file";
3555 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3557 #include <pshpack2.h>
3559 struct ne_typeinfo
3561 WORD type_id;
3562 WORD count;
3563 DWORD res;
3566 struct ne_nameinfo
3568 WORD off;
3569 WORD len;
3570 WORD flags;
3571 WORD id;
3572 DWORD res;
3575 struct rsrc_tab
3577 WORD align;
3578 struct ne_typeinfo fontdir_type;
3579 struct ne_nameinfo fontdir_name;
3580 struct ne_typeinfo scalable_type;
3581 struct ne_nameinfo scalable_name;
3582 WORD end_of_rsrc;
3583 BYTE fontdir_res_name[8];
3586 #include <poppack.h>
3588 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3590 BOOL ret = FALSE;
3591 HANDLE file;
3592 DWORD size, written;
3593 BYTE *ptr, *start;
3594 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3595 char *font_fileA, *last_part, *ext;
3596 IMAGE_DOS_HEADER dos;
3597 IMAGE_OS2_HEADER ne =
3599 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3600 0, 0, 0, 0, 0, 0,
3601 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3602 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3604 struct rsrc_tab rsrc_tab =
3607 { 0x8007, 1, 0 },
3608 { 0, 0, 0x0c50, 0x2c, 0 },
3609 { 0x80cc, 1, 0 },
3610 { 0, 0, 0x0c50, 0x8001, 0 },
3612 { 7,'F','O','N','T','D','I','R'}
3615 memset( &dos, 0, sizeof(dos) );
3616 dos.e_magic = IMAGE_DOS_SIGNATURE;
3617 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3619 /* import name is last part\0, resident name is last part without extension
3620 non-resident name is "FONTRES:" + lfFaceName */
3622 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3623 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3624 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3626 last_part = strrchr( font_fileA, '\\' );
3627 if (last_part) last_part++;
3628 else last_part = font_fileA;
3629 import_name_len = strlen( last_part ) + 1;
3631 ext = strchr( last_part, '.' );
3632 if (ext) res_name_len = ext - last_part;
3633 else res_name_len = import_name_len - 1;
3635 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3637 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3638 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3639 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3640 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3641 ne.ne_cbenttab = 2;
3642 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3644 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3645 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3646 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3647 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3649 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3650 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3652 if (!ptr)
3654 HeapFree( GetProcessHeap(), 0, font_fileA );
3655 return FALSE;
3658 memcpy( ptr, &dos, sizeof(dos) );
3659 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3660 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3662 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3663 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3665 ptr = start + dos.e_lfanew + ne.ne_restab;
3666 *ptr++ = res_name_len;
3667 memcpy( ptr, last_part, res_name_len );
3669 ptr = start + dos.e_lfanew + ne.ne_imptab;
3670 *ptr++ = import_name_len;
3671 memcpy( ptr, last_part, import_name_len );
3673 ptr = start + ne.ne_nrestab;
3674 *ptr++ = non_res_name_len;
3675 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3676 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3678 ptr = start + (rsrc_tab.scalable_name.off << 4);
3679 memcpy( ptr, font_fileA, font_file_len );
3681 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3682 memcpy( ptr, fontdir, fontdir->dfSize );
3684 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3685 if (file != INVALID_HANDLE_VALUE)
3687 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3688 ret = TRUE;
3689 CloseHandle( file );
3692 HeapFree( GetProcessHeap(), 0, start );
3693 HeapFree( GetProcessHeap(), 0, font_fileA );
3695 return ret;
3698 /*************************************************************
3699 * WineEngCreateScalableFontResource
3702 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3703 LPCWSTR font_file, LPCWSTR font_path )
3705 char *unix_name = get_ttf_file_name( font_file, font_path );
3706 struct fontdir fontdir;
3707 BOOL ret = FALSE;
3709 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3710 SetLastError( ERROR_INVALID_PARAMETER );
3711 else
3713 if (hidden) fontdir.dfType |= 0x80;
3714 ret = create_fot( resource, font_file, &fontdir );
3717 HeapFree( GetProcessHeap(), 0, unix_name );
3718 return ret;
3721 static const struct nls_update_font_list
3723 UINT ansi_cp, oem_cp;
3724 const char *oem, *fixed, *system;
3725 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3726 /* these are for font substitutes */
3727 const char *shelldlg, *tmsrmn;
3728 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3729 *helv_0, *tmsrmn_0;
3730 const struct subst
3732 const char *from, *to;
3733 } arial_0, courier_new_0, times_new_roman_0;
3734 } nls_update_font_list[] =
3736 /* Latin 1 (United States) */
3737 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3738 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3739 "Tahoma","Times New Roman",
3740 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3741 { 0 }, { 0 }, { 0 }
3743 /* Latin 1 (Multilingual) */
3744 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3745 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3746 "Tahoma","Times New Roman", /* FIXME unverified */
3747 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3748 { 0 }, { 0 }, { 0 }
3750 /* Eastern Europe */
3751 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3752 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3753 "Tahoma","Times New Roman", /* FIXME unverified */
3754 "Fixedsys,238", "System,238",
3755 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3756 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3757 { "Arial CE,0", "Arial,238" },
3758 { "Courier New CE,0", "Courier New,238" },
3759 { "Times New Roman CE,0", "Times New Roman,238" }
3761 /* Cyrillic */
3762 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3763 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3764 "Tahoma","Times New Roman", /* FIXME unverified */
3765 "Fixedsys,204", "System,204",
3766 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3767 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3768 { "Arial Cyr,0", "Arial,204" },
3769 { "Courier New Cyr,0", "Courier New,204" },
3770 { "Times New Roman Cyr,0", "Times New Roman,204" }
3772 /* Greek */
3773 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3774 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3775 "Tahoma","Times New Roman", /* FIXME unverified */
3776 "Fixedsys,161", "System,161",
3777 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3778 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3779 { "Arial Greek,0", "Arial,161" },
3780 { "Courier New Greek,0", "Courier New,161" },
3781 { "Times New Roman Greek,0", "Times New Roman,161" }
3783 /* Turkish */
3784 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3785 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3786 "Tahoma","Times New Roman", /* FIXME unverified */
3787 "Fixedsys,162", "System,162",
3788 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3789 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3790 { "Arial Tur,0", "Arial,162" },
3791 { "Courier New Tur,0", "Courier New,162" },
3792 { "Times New Roman Tur,0", "Times New Roman,162" }
3794 /* Hebrew */
3795 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3796 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3797 "Tahoma","Times New Roman", /* FIXME unverified */
3798 "Fixedsys,177", "System,177",
3799 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3800 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3801 { 0 }, { 0 }, { 0 }
3803 /* Arabic */
3804 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3805 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3806 "Microsoft Sans Serif","Times New Roman",
3807 "Fixedsys,178", "System,178",
3808 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3809 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3810 { 0 }, { 0 }, { 0 }
3812 /* Baltic */
3813 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3814 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3815 "Tahoma","Times New Roman", /* FIXME unverified */
3816 "Fixedsys,186", "System,186",
3817 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3818 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3819 { "Arial Baltic,0", "Arial,186" },
3820 { "Courier New Baltic,0", "Courier New,186" },
3821 { "Times New Roman Baltic,0", "Times New Roman,186" }
3823 /* Vietnamese */
3824 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3825 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3826 "Tahoma","Times New Roman", /* FIXME unverified */
3827 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3828 { 0 }, { 0 }, { 0 }
3830 /* Thai */
3831 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3832 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3833 "Tahoma","Times New Roman", /* FIXME unverified */
3834 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3835 { 0 }, { 0 }, { 0 }
3837 /* Japanese */
3838 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3839 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3840 "MS UI Gothic","MS Serif",
3841 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3842 { 0 }, { 0 }, { 0 }
3844 /* Chinese Simplified */
3845 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3846 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3847 "SimSun", "NSimSun",
3848 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3849 { 0 }, { 0 }, { 0 }
3851 /* Korean */
3852 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3853 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3854 "Gulim", "Batang",
3855 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3856 { 0 }, { 0 }, { 0 }
3858 /* Chinese Traditional */
3859 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3860 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3861 "PMingLiU", "MingLiU",
3862 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3863 { 0 }, { 0 }, { 0 }
3867 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3869 return ( ansi_cp == 932 /* CP932 for Japanese */
3870 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3871 || ansi_cp == 949 /* CP949 for Korean */
3872 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3875 static inline HKEY create_fonts_NT_registry_key(void)
3877 HKEY hkey = 0;
3879 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3880 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3881 return hkey;
3884 static inline HKEY create_fonts_9x_registry_key(void)
3886 HKEY hkey = 0;
3888 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3889 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3890 return hkey;
3893 static inline HKEY create_config_fonts_registry_key(void)
3895 HKEY hkey = 0;
3897 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3898 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3899 return hkey;
3902 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3904 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3906 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3907 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3908 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3909 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3912 static void set_value_key(HKEY hkey, const char *name, const char *value)
3914 if (value)
3915 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3916 else if (name)
3917 RegDeleteValueA(hkey, name);
3920 static void update_font_association_info(UINT current_ansi_codepage)
3922 static const char *font_assoc_reg_key = "System\\CurrentControlSet\\Control\\FontAssoc";
3923 static const char *assoc_charset_subkey = "Associated Charset";
3925 if (is_dbcs_ansi_cp(current_ansi_codepage))
3927 HKEY hkey;
3928 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, font_assoc_reg_key, &hkey) == ERROR_SUCCESS)
3930 HKEY hsubkey;
3931 if (RegCreateKeyA(hkey, assoc_charset_subkey, &hsubkey) == ERROR_SUCCESS)
3933 switch (current_ansi_codepage)
3935 case 932:
3936 set_value_key(hsubkey, "ANSI(00)", "NO");
3937 set_value_key(hsubkey, "OEM(FF)", "NO");
3938 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3939 break;
3940 case 936:
3941 case 949:
3942 case 950:
3943 set_value_key(hsubkey, "ANSI(00)", "YES");
3944 set_value_key(hsubkey, "OEM(FF)", "YES");
3945 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3946 break;
3948 RegCloseKey(hsubkey);
3951 /* TODO: Associated DefaultFonts */
3953 RegCloseKey(hkey);
3956 else
3957 RegDeleteTreeA(HKEY_LOCAL_MACHINE, font_assoc_reg_key);
3960 static void set_multi_value_key(HKEY hkey, const WCHAR *name, const WCHAR *value, DWORD len)
3962 if (value)
3963 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (const BYTE *)value, len);
3964 else if (name)
3965 RegDeleteValueW(hkey, name);
3968 static void update_font_system_link_info(UINT current_ansi_codepage)
3970 static const WCHAR system_link_simplified_chinese[] =
3971 {'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3972 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3973 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3974 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3975 '\0'};
3976 static const WCHAR system_link_traditional_chinese[] =
3977 {'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3978 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3979 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3980 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3981 '\0'};
3982 static const WCHAR system_link_japanese[] =
3983 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3984 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3985 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3986 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3987 '\0'};
3988 static const WCHAR system_link_korean[] =
3989 {'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3990 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3991 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3992 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3993 '\0'};
3994 static const WCHAR system_link_non_cjk[] =
3995 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3996 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3997 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3998 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3999 '\0'};
4000 HKEY hkey;
4002 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
4004 const WCHAR *link;
4005 DWORD len;
4007 switch (current_ansi_codepage)
4009 case 932:
4010 link = system_link_japanese;
4011 len = sizeof(system_link_japanese);
4012 break;
4013 case 936:
4014 link = system_link_simplified_chinese;
4015 len = sizeof(system_link_simplified_chinese);
4016 break;
4017 case 949:
4018 link = system_link_korean;
4019 len = sizeof(system_link_korean);
4020 break;
4021 case 950:
4022 link = system_link_traditional_chinese;
4023 len = sizeof(system_link_traditional_chinese);
4024 break;
4025 default:
4026 link = system_link_non_cjk;
4027 len = sizeof(system_link_non_cjk);
4029 set_multi_value_key(hkey, Lucida_Sans_Unicode, link, len);
4030 set_multi_value_key(hkey, Microsoft_Sans_Serif, link, len);
4031 set_multi_value_key(hkey, Tahoma, link, len);
4032 RegCloseKey(hkey);
4036 static void update_font_info(void)
4038 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
4039 char buf[40], cpbuf[40];
4040 DWORD len, type;
4041 HKEY hkey = 0;
4042 UINT i, ansi_cp = 0, oem_cp = 0;
4043 DWORD screen_dpi, font_dpi = 0;
4044 BOOL done = FALSE;
4046 screen_dpi = get_dpi();
4047 if (!screen_dpi) screen_dpi = 96;
4049 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
4050 return;
4052 reg_load_dword(hkey, logpixels, &font_dpi);
4054 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
4055 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
4056 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
4057 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
4058 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
4060 /* Setup Default_Fallback usage for DBCS ANSI codepages */
4061 if (is_dbcs_ansi_cp(ansi_cp))
4062 use_default_fallback = TRUE;
4064 buf[0] = 0;
4065 len = sizeof(buf);
4066 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
4068 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
4070 RegCloseKey(hkey);
4071 return;
4073 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
4074 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
4076 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
4077 ansi_cp, oem_cp, screen_dpi);
4079 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
4080 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
4081 RegCloseKey(hkey);
4083 for (i = 0; i < ARRAY_SIZE(nls_update_font_list); i++)
4085 HKEY hkey;
4087 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
4088 nls_update_font_list[i].oem_cp == oem_cp)
4090 hkey = create_config_fonts_registry_key();
4091 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
4092 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
4093 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
4094 RegCloseKey(hkey);
4096 hkey = create_fonts_NT_registry_key();
4097 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
4098 RegCloseKey(hkey);
4100 hkey = create_fonts_9x_registry_key();
4101 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
4102 RegCloseKey(hkey);
4104 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
4106 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
4107 strlen(nls_update_font_list[i].shelldlg)+1);
4108 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
4109 strlen(nls_update_font_list[i].tmsrmn)+1);
4111 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
4112 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
4113 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
4114 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
4115 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
4116 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
4117 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
4118 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
4120 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
4121 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
4122 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
4124 RegCloseKey(hkey);
4126 done = TRUE;
4128 else
4130 /* Delete the FontSubstitutes from other locales */
4131 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
4133 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
4134 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
4135 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
4136 RegCloseKey(hkey);
4140 if (!done)
4141 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
4143 /* update locale dependent font association info and font system link info in registry.
4144 update only when codepages changed, not logpixels. */
4145 if (strcmp(buf, cpbuf) != 0)
4147 update_font_association_info(ansi_cp);
4148 update_font_system_link_info(ansi_cp);
4152 static BOOL init_freetype(void)
4154 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
4155 if(!ft_handle) {
4156 WINE_MESSAGE(
4157 "Wine cannot find the FreeType font library. To enable Wine to\n"
4158 "use TrueType fonts please install a version of FreeType greater than\n"
4159 "or equal to 2.0.5.\n"
4160 "http://www.freetype.org\n");
4161 return FALSE;
4164 #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;}
4166 LOAD_FUNCPTR(FT_Done_Face)
4167 LOAD_FUNCPTR(FT_Get_Char_Index)
4168 LOAD_FUNCPTR(FT_Get_First_Char)
4169 LOAD_FUNCPTR(FT_Get_Next_Char)
4170 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
4171 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
4172 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
4173 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
4174 LOAD_FUNCPTR(FT_Init_FreeType)
4175 LOAD_FUNCPTR(FT_Library_Version)
4176 LOAD_FUNCPTR(FT_Load_Glyph)
4177 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
4178 LOAD_FUNCPTR(FT_Matrix_Multiply)
4179 #ifndef FT_MULFIX_INLINED
4180 LOAD_FUNCPTR(FT_MulFix)
4181 #endif
4182 LOAD_FUNCPTR(FT_New_Face)
4183 LOAD_FUNCPTR(FT_New_Memory_Face)
4184 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
4185 LOAD_FUNCPTR(FT_Outline_Get_CBox)
4186 LOAD_FUNCPTR(FT_Outline_Transform)
4187 LOAD_FUNCPTR(FT_Outline_Translate)
4188 LOAD_FUNCPTR(FT_Render_Glyph)
4189 LOAD_FUNCPTR(FT_Set_Charmap)
4190 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
4191 LOAD_FUNCPTR(FT_Vector_Length)
4192 LOAD_FUNCPTR(FT_Vector_Transform)
4193 LOAD_FUNCPTR(FT_Vector_Unit)
4194 #undef LOAD_FUNCPTR
4195 /* Don't warn if these ones are missing */
4196 pFT_Outline_Embolden = wine_dlsym(ft_handle, "FT_Outline_Embolden", NULL, 0);
4197 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
4198 #ifdef FT_LCD_FILTER_H
4199 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
4200 #endif
4201 pFT_Property_Set = wine_dlsym(ft_handle, "FT_Property_Set", NULL, 0);
4203 if(pFT_Init_FreeType(&library) != 0) {
4204 ERR("Can't init FreeType library\n");
4205 wine_dlclose(ft_handle, NULL, 0);
4206 ft_handle = NULL;
4207 return FALSE;
4209 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
4211 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
4212 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
4213 ((FT_Version.minor << 8) & 0x00ff00) |
4214 ((FT_Version.patch ) & 0x0000ff);
4216 /* In FreeType < 2.8.1 v40's FT_LOAD_TARGET_MONO has broken advance widths. */
4217 if (pFT_Property_Set && FT_SimpleVersion < FT_VERSION_VALUE(2, 8, 1))
4219 FT_UInt interpreter_version = 35;
4220 pFT_Property_Set( library, "truetype", "interpreter-version", &interpreter_version );
4223 font_driver = &freetype_funcs;
4224 return TRUE;
4226 sym_not_found:
4227 WINE_MESSAGE(
4228 "Wine cannot find certain functions that it needs inside the FreeType\n"
4229 "font library. To enable Wine to use TrueType fonts please upgrade\n"
4230 "FreeType to at least version 2.1.4.\n"
4231 "http://www.freetype.org\n");
4232 wine_dlclose(ft_handle, NULL, 0);
4233 ft_handle = NULL;
4234 return FALSE;
4237 static void init_font_list(void)
4239 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
4240 static const WCHAR pathW[] = {'P','a','t','h',0};
4241 HKEY hkey;
4242 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
4243 WCHAR windowsdir[MAX_PATH];
4244 char *unixname;
4246 delete_external_font_keys();
4248 /* load the system bitmap fonts */
4249 load_system_fonts();
4251 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
4252 GetWindowsDirectoryW(windowsdir, ARRAY_SIZE(windowsdir));
4253 strcatW(windowsdir, fontsW);
4254 if((unixname = wine_get_unix_file_name(windowsdir)))
4256 ReadFontDir(unixname, FALSE);
4257 HeapFree(GetProcessHeap(), 0, unixname);
4260 /* load the wine fonts */
4261 if ((unixname = get_font_dir()))
4263 ReadFontDir(unixname, TRUE);
4264 HeapFree(GetProcessHeap(), 0, unixname);
4267 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
4268 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
4269 full path as the entry. Also look for any .fon fonts, since ReadFontDir
4270 will skip these. */
4271 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
4272 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
4273 &hkey) == ERROR_SUCCESS)
4275 LPWSTR data, valueW;
4276 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
4277 &valuelen, &datalen, NULL, NULL);
4279 valuelen++; /* returned value doesn't include room for '\0' */
4280 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
4281 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
4282 if (valueW && data)
4284 dlen = datalen * sizeof(WCHAR);
4285 vlen = valuelen;
4286 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
4287 &dlen) == ERROR_SUCCESS)
4289 if(data[0] && (data[1] == ':'))
4291 if((unixname = wine_get_unix_file_name(data)))
4293 AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
4294 HeapFree(GetProcessHeap(), 0, unixname);
4297 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
4299 WCHAR pathW[MAX_PATH];
4300 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
4301 BOOL added = FALSE;
4303 sprintfW(pathW, fmtW, windowsdir, data);
4304 if((unixname = wine_get_unix_file_name(pathW)))
4306 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
4307 HeapFree(GetProcessHeap(), 0, unixname);
4309 if (!added)
4310 load_font_from_data_dir(data);
4312 /* reset dlen and vlen */
4313 dlen = datalen;
4314 vlen = valuelen;
4317 HeapFree(GetProcessHeap(), 0, data);
4318 HeapFree(GetProcessHeap(), 0, valueW);
4319 RegCloseKey(hkey);
4322 #ifdef SONAME_LIBFONTCONFIG
4323 load_fontconfig_fonts();
4324 #elif defined(HAVE_CARBON_CARBON_H)
4325 load_mac_fonts();
4326 #elif defined(__ANDROID__)
4327 ReadFontDir("/system/fonts", TRUE);
4328 #endif
4330 /* then look in any directories that we've specified in the config file */
4331 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
4332 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
4334 DWORD len;
4335 LPWSTR valueW;
4336 LPSTR valueA, ptr;
4338 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
4340 len += sizeof(WCHAR);
4341 valueW = HeapAlloc( GetProcessHeap(), 0, len );
4342 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
4344 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
4345 valueA = HeapAlloc( GetProcessHeap(), 0, len );
4346 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
4347 TRACE( "got font path %s\n", debugstr_a(valueA) );
4348 ptr = valueA;
4349 while (ptr)
4351 const char* home;
4352 LPSTR next = strchr( ptr, ':' );
4353 if (next) *next++ = 0;
4354 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
4355 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
4357 strcpy( unixname, home );
4358 strcat( unixname, ptr + 1 );
4359 ReadFontDir( unixname, TRUE );
4360 HeapFree( GetProcessHeap(), 0, unixname );
4362 else
4363 ReadFontDir( ptr, TRUE );
4364 ptr = next;
4366 HeapFree( GetProcessHeap(), 0, valueA );
4368 HeapFree( GetProcessHeap(), 0, valueW );
4370 RegCloseKey(hkey);
4374 static BOOL move_to_front(const WCHAR *name)
4376 Family *family, *cursor2;
4377 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
4379 if(!strncmpiW(family->FamilyName, name, LF_FACESIZE - 1))
4381 list_remove(&family->entry);
4382 list_add_head(&font_list, &family->entry);
4383 return TRUE;
4386 return FALSE;
4389 static const WCHAR *set_default(const WCHAR **name_list)
4391 const WCHAR **entry = name_list;
4393 while (*entry)
4395 if (move_to_front(*entry)) return *entry;
4396 entry++;
4399 return *name_list;
4402 static void reorder_font_list(void)
4404 default_serif = set_default( default_serif_list );
4405 default_fixed = set_default( default_fixed_list );
4406 default_sans = set_default( default_sans_list );
4409 /*************************************************************
4410 * WineEngInit
4412 * Initialize FreeType library and create a list of available faces
4414 BOOL WineEngInit(void)
4416 HKEY hkey;
4417 DWORD disposition;
4418 HANDLE font_mutex;
4420 /* update locale dependent font info in registry */
4421 update_font_info();
4423 if(!init_freetype()) return FALSE;
4425 #ifdef SONAME_LIBFONTCONFIG
4426 init_fontconfig();
4427 #endif
4429 if (!RegOpenKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, KEY_READ, &hkey))
4431 static const WCHAR antialias_fake_bold_or_italic[] = { 'A','n','t','i','a','l','i','a','s','F','a','k','e',
4432 'B','o','l','d','O','r','I','t','a','l','i','c',0 };
4433 static const WCHAR true_options[] = { 'y','Y','t','T','1',0 };
4434 DWORD type, size;
4435 WCHAR buffer[20];
4437 size = sizeof(buffer);
4438 if (!RegQueryValueExW(hkey, antialias_fake_bold_or_italic, NULL, &type, (BYTE*)buffer, &size) &&
4439 type == REG_SZ && size >= 1)
4441 antialias_fakes = (strchrW(true_options, buffer[0]) != NULL);
4443 RegCloseKey(hkey);
4446 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
4448 ERR("Failed to create font mutex\n");
4449 return FALSE;
4451 WaitForSingleObject(font_mutex, INFINITE);
4453 create_font_cache_key(&hkey_font_cache, &disposition);
4455 if(disposition == REG_CREATED_NEW_KEY)
4456 init_font_list();
4457 else
4458 load_font_list_from_cache(hkey_font_cache);
4460 reorder_font_list();
4462 DumpFontList();
4463 LoadSubstList();
4464 DumpSubstList();
4465 LoadReplaceList();
4467 if(disposition == REG_CREATED_NEW_KEY)
4468 update_reg_entries();
4470 init_system_links();
4472 ReleaseMutex(font_mutex);
4473 return TRUE;
4476 /* Some fonts have large usWinDescent values, as a result of storing signed short
4477 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
4478 some font generation tools. */
4479 static inline USHORT get_fixed_windescent(USHORT windescent)
4481 return abs((SHORT)windescent);
4484 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
4486 TT_OS2 *pOS2;
4487 TT_HoriHeader *pHori;
4489 LONG ppem;
4490 const LONG MAX_PPEM = (1 << 16) - 1;
4492 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4493 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4495 if(height == 0) height = 16;
4497 /* Calc. height of EM square:
4499 * For +ve lfHeight we have
4500 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
4501 * Re-arranging gives:
4502 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4504 * For -ve lfHeight we have
4505 * |lfHeight| = ppem
4506 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4507 * with il = winAscent + winDescent - units_per_em]
4511 if(height > 0) {
4512 USHORT windescent = get_fixed_windescent(pOS2->usWinDescent);
4513 if(pOS2->usWinAscent + windescent == 0)
4514 ppem = MulDiv(ft_face->units_per_EM, height,
4515 pHori->Ascender - pHori->Descender);
4516 else
4517 ppem = MulDiv(ft_face->units_per_EM, height,
4518 pOS2->usWinAscent + windescent);
4519 if(ppem > MAX_PPEM) {
4520 WARN("Ignoring too large height %d, ppem %d\n", height, ppem);
4521 ppem = 1;
4524 else if(height >= -MAX_PPEM)
4525 ppem = -height;
4526 else {
4527 WARN("Ignoring too large height %d\n", height);
4528 ppem = 1;
4531 return ppem;
4534 static struct font_mapping *map_font_file( const char *name )
4536 struct font_mapping *mapping;
4537 struct stat st;
4538 int fd;
4540 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
4541 if (fstat( fd, &st ) == -1) goto error;
4543 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
4545 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
4547 mapping->refcount++;
4548 close( fd );
4549 return mapping;
4552 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
4553 goto error;
4555 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
4556 close( fd );
4558 if (mapping->data == MAP_FAILED)
4560 HeapFree( GetProcessHeap(), 0, mapping );
4561 return NULL;
4563 mapping->refcount = 1;
4564 mapping->dev = st.st_dev;
4565 mapping->ino = st.st_ino;
4566 mapping->size = st.st_size;
4567 list_add_tail( &mappings_list, &mapping->entry );
4568 return mapping;
4570 error:
4571 close( fd );
4572 return NULL;
4575 static void unmap_font_file( struct font_mapping *mapping )
4577 if (!--mapping->refcount)
4579 list_remove( &mapping->entry );
4580 munmap( mapping->data, mapping->size );
4581 HeapFree( GetProcessHeap(), 0, mapping );
4585 static LONG load_VDMX(GdiFont*, LONG);
4587 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
4589 FT_Error err;
4590 FT_Face ft_face;
4591 void *data_ptr;
4592 DWORD data_size;
4594 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
4596 if (face->file)
4598 char *filename = strWtoA( CP_UNIXCP, face->file );
4599 font->mapping = map_font_file( filename );
4600 HeapFree( GetProcessHeap(), 0, filename );
4601 if (!font->mapping)
4603 WARN("failed to map %s\n", debugstr_w(face->file));
4604 return 0;
4606 data_ptr = font->mapping->data;
4607 data_size = font->mapping->size;
4609 else
4611 data_ptr = face->font_data_ptr;
4612 data_size = face->font_data_size;
4615 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
4616 if(err) {
4617 ERR("FT_New_Face rets %d\n", err);
4618 return 0;
4621 /* set it here, as load_VDMX needs it */
4622 font->ft_face = ft_face;
4624 if(FT_IS_SCALABLE(ft_face)) {
4625 FT_ULong len;
4626 DWORD header;
4628 /* load the VDMX table if we have one */
4629 font->ppem = load_VDMX(font, height);
4630 if(font->ppem == 0)
4631 font->ppem = calc_ppem_for_height(ft_face, height);
4632 TRACE("height %d => ppem %d\n", height, font->ppem);
4634 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
4635 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
4637 /* see if it's a TTC */
4638 len = sizeof(header);
4639 if (!pFT_Load_Sfnt_Table(ft_face, 0, 0, (void*)&header, &len)) {
4640 if (header == MS_TTCF_TAG)
4642 len = sizeof(font->ttc_item_offset);
4643 if (pFT_Load_Sfnt_Table(ft_face, 0, (3 + face->face_index) * sizeof(DWORD),
4644 (void*)&font->ttc_item_offset, &len))
4645 font->ttc_item_offset = 0;
4646 else
4647 font->ttc_item_offset = GET_BE_DWORD(font->ttc_item_offset);
4650 } else {
4651 font->ppem = height;
4652 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
4653 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
4655 return ft_face;
4659 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
4661 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4662 a single face with the requested charset. The idea is to check if
4663 the selected font supports the current ANSI codepage, if it does
4664 return the corresponding charset, else return the first charset */
4666 CHARSETINFO csi;
4667 int acp = GetACP(), i;
4668 DWORD fs0;
4670 *cp = acp;
4671 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
4673 const SYSTEM_LINKS *font_link;
4675 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4676 return csi.ciCharset;
4678 font_link = find_font_link(family_name);
4679 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4680 return csi.ciCharset;
4683 for(i = 0; i < 32; i++) {
4684 fs0 = 1L << i;
4685 if(face->fs.fsCsb[0] & fs0) {
4686 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4687 *cp = csi.ciACP;
4688 return csi.ciCharset;
4690 else
4691 FIXME("TCI failing on %x\n", fs0);
4695 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4696 face->fs.fsCsb[0], debugstr_w(face->file));
4697 *cp = acp;
4698 return DEFAULT_CHARSET;
4701 static GdiFont *alloc_font(void)
4703 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4704 ret->refcount = 1;
4705 ret->gmsize = 1;
4706 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4707 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4708 ret->potm = NULL;
4709 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4710 ret->total_kern_pairs = (DWORD)-1;
4711 ret->kern_pairs = NULL;
4712 ret->instance_id = alloc_font_handle(ret);
4713 list_init(&ret->child_fonts);
4714 return ret;
4717 static void free_font(GdiFont *font)
4719 CHILD_FONT *child, *child_next;
4720 DWORD i;
4722 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
4724 list_remove(&child->entry);
4725 if(child->font)
4726 free_font(child->font);
4727 release_face( child->face );
4728 HeapFree(GetProcessHeap(), 0, child);
4731 HeapFree(GetProcessHeap(), 0, font->fileinfo);
4732 free_font_handle(font->instance_id);
4733 if (font->ft_face) pFT_Done_Face(font->ft_face);
4734 if (font->mapping) unmap_font_file( font->mapping );
4735 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4736 HeapFree(GetProcessHeap(), 0, font->potm);
4737 HeapFree(GetProcessHeap(), 0, font->name);
4738 for (i = 0; i < font->gmsize; i++)
4739 HeapFree(GetProcessHeap(),0,font->gm[i]);
4740 HeapFree(GetProcessHeap(), 0, font->gm);
4741 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4742 HeapFree(GetProcessHeap(), 0, font);
4745 /* TODO: GGO format support */
4746 static BOOL get_cached_metrics( GdiFont *font, UINT index, GLYPHMETRICS *gm, ABC *abc )
4748 UINT block = index / GM_BLOCK_SIZE;
4749 UINT entry = index % GM_BLOCK_SIZE;
4751 if (block < font->gmsize && font->gm[block] && font->gm[block][entry].init)
4753 *gm = font->gm[block][entry].gm;
4754 *abc = font->gm[block][entry].abc;
4756 TRACE( "cached gm: %u, %u, %s, %d, %d abc: %d, %u, %d\n",
4757 gm->gmBlackBoxX, gm->gmBlackBoxY, wine_dbgstr_point( &gm->gmptGlyphOrigin ),
4758 gm->gmCellIncX, gm->gmCellIncY, abc->abcA, abc->abcB, abc->abcC );
4759 return TRUE;
4762 return FALSE;
4765 static void set_cached_metrics( GdiFont *font, UINT index, const GLYPHMETRICS *gm, const ABC *abc )
4767 UINT block = index / GM_BLOCK_SIZE;
4768 UINT entry = index % GM_BLOCK_SIZE;
4770 if (block >= font->gmsize)
4772 GM **ptr = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
4773 font->gm, (block + 1) * sizeof(GM *) );
4774 if (!ptr) return;
4776 font->gmsize = block + 1;
4777 font->gm = ptr;
4780 if (!font->gm[block])
4782 font->gm[block] = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
4783 sizeof(GM) * GM_BLOCK_SIZE );
4784 if (!font->gm[block]) return;
4787 font->gm[block][entry].gm = *gm;
4788 font->gm[block][entry].abc = *abc;
4789 font->gm[block][entry].init = TRUE;
4792 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4794 FT_Face ft_face = font->ft_face;
4795 FT_ULong len;
4796 FT_Error err;
4798 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4800 if(!buf)
4801 len = 0;
4802 else
4803 len = cbData;
4805 /* if font is a member of TTC, 'ttcf' tag allows reading from beginning of TTC file,
4806 0 tag means to read from start of collection member data. */
4807 if (font->ttc_item_offset)
4809 if (table == MS_TTCF_TAG)
4810 table = 0;
4811 else if (table == 0)
4812 offset += font->ttc_item_offset;
4815 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4817 /* make sure value of len is the value freetype says it needs */
4818 if (buf && len)
4820 FT_ULong needed = 0;
4821 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4822 if( !err && needed < len) len = needed;
4824 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4825 if (err)
4827 table = RtlUlongByteSwap( table );
4828 TRACE("Can't find table %s\n", debugstr_an((char*)&table, 4));
4829 return GDI_ERROR;
4831 return len;
4834 /*************************************************************
4835 * load_VDMX
4837 * load the vdmx entry for the specified height
4842 typedef struct {
4843 WORD version;
4844 WORD numRecs;
4845 WORD numRatios;
4846 } VDMX_Header;
4848 typedef struct {
4849 BYTE bCharSet;
4850 BYTE xRatio;
4851 BYTE yStartRatio;
4852 BYTE yEndRatio;
4853 } Ratios;
4855 typedef struct {
4856 WORD recs;
4857 BYTE startsz;
4858 BYTE endsz;
4859 } VDMX_group;
4861 typedef struct {
4862 WORD yPelHeight;
4863 WORD yMax;
4864 WORD yMin;
4865 } VDMX_vTable;
4867 static LONG load_VDMX(GdiFont *font, LONG height)
4869 VDMX_Header hdr;
4870 VDMX_group group;
4871 BYTE devXRatio, devYRatio;
4872 USHORT numRecs, numRatios;
4873 DWORD result, offset = -1;
4874 LONG ppem = 0;
4875 int i;
4877 result = get_font_data(font, MS_VDMX_TAG, 0, &hdr, sizeof(hdr));
4879 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4880 return ppem;
4882 /* FIXME: need the real device aspect ratio */
4883 devXRatio = 1;
4884 devYRatio = 1;
4886 numRecs = GET_BE_WORD(hdr.numRecs);
4887 numRatios = GET_BE_WORD(hdr.numRatios);
4889 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr.version), numRecs, numRatios);
4890 for(i = 0; i < numRatios; i++) {
4891 Ratios ratio;
4893 offset = sizeof(hdr) + (i * sizeof(Ratios));
4894 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4895 offset = -1;
4897 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4899 if (!ratio.bCharSet) continue;
4901 if((ratio.xRatio == 0 &&
4902 ratio.yStartRatio == 0 &&
4903 ratio.yEndRatio == 0) ||
4904 (devXRatio == ratio.xRatio &&
4905 devYRatio >= ratio.yStartRatio &&
4906 devYRatio <= ratio.yEndRatio))
4908 WORD group_offset;
4910 offset = sizeof(hdr) + numRatios * sizeof(ratio) + i * sizeof(group_offset);
4911 get_font_data(font, MS_VDMX_TAG, offset, &group_offset, sizeof(group_offset));
4912 offset = GET_BE_WORD(group_offset);
4913 break;
4917 if(offset == -1) return 0;
4919 if(get_font_data(font, MS_VDMX_TAG, offset, &group, sizeof(group)) != GDI_ERROR) {
4920 USHORT recs;
4921 BYTE startsz, endsz;
4922 WORD *vTable;
4924 recs = GET_BE_WORD(group.recs);
4925 startsz = group.startsz;
4926 endsz = group.endsz;
4928 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4930 vTable = HeapAlloc(GetProcessHeap(), 0, recs * sizeof(VDMX_vTable));
4931 result = get_font_data(font, MS_VDMX_TAG, offset + sizeof(group), vTable, recs * sizeof(VDMX_vTable));
4932 if(result == GDI_ERROR) {
4933 FIXME("Failed to retrieve vTable\n");
4934 goto end;
4937 if(height > 0) {
4938 for(i = 0; i < recs; i++) {
4939 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4940 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4941 ppem = GET_BE_WORD(vTable[i * 3]);
4943 if(yMax + -yMin == height) {
4944 font->yMax = yMax;
4945 font->yMin = yMin;
4946 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4947 break;
4949 if(yMax + -yMin > height) {
4950 if(--i < 0) {
4951 ppem = 0;
4952 goto end; /* failed */
4954 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4955 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4956 ppem = GET_BE_WORD(vTable[i * 3]);
4957 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4958 break;
4961 if(!font->yMax) {
4962 ppem = 0;
4963 TRACE("ppem not found for height %d\n", height);
4965 } else {
4966 ppem = -height;
4967 if(ppem < startsz || ppem > endsz)
4969 ppem = 0;
4970 goto end;
4973 for(i = 0; i < recs; i++) {
4974 USHORT yPelHeight;
4975 yPelHeight = GET_BE_WORD(vTable[i * 3]);
4977 if(yPelHeight > ppem)
4979 ppem = 0;
4980 break; /* failed */
4983 if(yPelHeight == ppem) {
4984 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4985 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4986 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
4987 break;
4991 end:
4992 HeapFree(GetProcessHeap(), 0, vTable);
4995 return ppem;
4998 static void dump_gdi_font_list(void)
5000 GdiFont *font;
5002 TRACE("---------- Font Cache ----------\n");
5003 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct tagGdiFont, entry )
5004 TRACE("font=%p ref=%u %s %d\n", font, font->refcount,
5005 debugstr_w(font->font_desc.lf.lfFaceName), font->font_desc.lf.lfHeight);
5008 static void grab_font( GdiFont *font )
5010 if (!font->refcount++)
5012 list_remove( &font->unused_entry );
5013 unused_font_count--;
5017 static void release_font( GdiFont *font )
5019 if (!font) return;
5020 if (!--font->refcount)
5022 TRACE( "font %p\n", font );
5024 /* add it to the unused list */
5025 list_add_head( &unused_gdi_font_list, &font->unused_entry );
5026 if (unused_font_count > UNUSED_CACHE_SIZE)
5028 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct tagGdiFont, unused_entry );
5029 TRACE( "freeing %p\n", font );
5030 list_remove( &font->entry );
5031 list_remove( &font->unused_entry );
5032 free_font( font );
5034 else unused_font_count++;
5036 if (TRACE_ON(font)) dump_gdi_font_list();
5040 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
5042 if(font->font_desc.hash != fd->hash) return TRUE;
5043 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
5044 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
5045 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
5046 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
5049 static void calc_hash(FONT_DESC *pfd)
5051 DWORD hash = 0, *ptr, two_chars;
5052 WORD *pwc;
5053 unsigned int i;
5055 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
5056 hash ^= *ptr;
5057 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
5058 hash ^= *ptr;
5059 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
5060 two_chars = *ptr;
5061 pwc = (WCHAR *)&two_chars;
5062 if(!*pwc) break;
5063 *pwc = toupperW(*pwc);
5064 pwc++;
5065 *pwc = toupperW(*pwc);
5066 hash ^= two_chars;
5067 if(!*pwc) break;
5069 hash ^= !pfd->can_use_bitmap;
5070 pfd->hash = hash;
5073 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
5075 GdiFont *ret;
5076 FONT_DESC fd;
5078 fd.lf = *plf;
5079 fd.matrix = *pmat;
5080 fd.can_use_bitmap = can_use_bitmap;
5081 calc_hash(&fd);
5083 /* try the in-use list */
5084 LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
5086 if(fontcmp(ret, &fd)) continue;
5087 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
5088 list_remove( &ret->entry );
5089 list_add_head( &gdi_font_list, &ret->entry );
5090 grab_font( ret );
5091 return ret;
5093 return NULL;
5096 static void add_to_cache(GdiFont *font)
5098 static DWORD cache_num = 1;
5100 font->cache_num = cache_num++;
5101 list_add_head(&gdi_font_list, &font->entry);
5102 TRACE( "font %p\n", font );
5105 /*************************************************************
5106 * create_child_font_list
5108 static BOOL create_child_font_list(GdiFont *font)
5110 BOOL ret = FALSE;
5111 SYSTEM_LINKS *font_link;
5112 CHILD_FONT *font_link_entry, *new_child;
5113 FontSubst *psub;
5114 WCHAR* font_name;
5116 psub = get_font_subst(&font_subst_list, font->name, -1);
5117 font_name = psub ? psub->to.name : font->name;
5118 font_link = find_font_link(font_name);
5119 if (font_link != NULL)
5121 TRACE("found entry in system list\n");
5122 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5124 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
5125 new_child->face = font_link_entry->face;
5126 new_child->font = NULL;
5127 new_child->face->refcount++;
5128 list_add_tail(&font->child_fonts, &new_child->entry);
5129 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
5131 ret = TRUE;
5134 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
5135 * Sans Serif. This is how asian windows get default fallbacks for fonts
5137 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
5138 font->charset != OEM_CHARSET &&
5139 strcmpiW(font_name,szDefaultFallbackLink) != 0)
5141 font_link = find_font_link(szDefaultFallbackLink);
5142 if (font_link != NULL)
5144 TRACE("found entry in default fallback list\n");
5145 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5147 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
5148 new_child->face = font_link_entry->face;
5149 new_child->font = NULL;
5150 new_child->face->refcount++;
5151 list_add_tail(&font->child_fonts, &new_child->entry);
5152 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
5154 ret = TRUE;
5158 return ret;
5161 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
5163 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
5164 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
5165 FT_Int i;
5167 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
5169 for (i = 0; i < ft_face->num_charmaps; i++)
5171 if (ft_face->charmaps[i]->encoding == encoding)
5173 TRACE("found cmap with platform_id %u, encoding_id %u\n",
5174 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
5176 switch (ft_face->charmaps[i]->platform_id)
5178 default:
5179 cmap_def = ft_face->charmaps[i];
5180 break;
5181 case 0: /* Apple Unicode */
5182 cmap0 = ft_face->charmaps[i];
5183 break;
5184 case 1: /* Macintosh */
5185 cmap1 = ft_face->charmaps[i];
5186 break;
5187 case 2: /* ISO */
5188 cmap2 = ft_face->charmaps[i];
5189 break;
5190 case 3: /* Microsoft */
5191 cmap3 = ft_face->charmaps[i];
5192 break;
5196 if (cmap3) /* prefer Microsoft cmap table */
5197 ft_err = pFT_Set_Charmap(ft_face, cmap3);
5198 else if (cmap1)
5199 ft_err = pFT_Set_Charmap(ft_face, cmap1);
5200 else if (cmap2)
5201 ft_err = pFT_Set_Charmap(ft_face, cmap2);
5202 else if (cmap0)
5203 ft_err = pFT_Set_Charmap(ft_face, cmap0);
5204 else if (cmap_def)
5205 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
5208 return ft_err == FT_Err_Ok;
5212 /*************************************************************
5213 * freetype_CreateDC
5215 static BOOL CDECL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
5216 LPCWSTR output, const DEVMODEW *devmode )
5218 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
5220 if (!physdev) return FALSE;
5221 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
5222 return TRUE;
5226 /*************************************************************
5227 * freetype_DeleteDC
5229 static BOOL CDECL freetype_DeleteDC( PHYSDEV dev )
5231 struct freetype_physdev *physdev = get_freetype_dev( dev );
5232 release_font( physdev->font );
5233 HeapFree( GetProcessHeap(), 0, physdev );
5234 return TRUE;
5237 static FT_Encoding pick_charmap( FT_Face face, int charset )
5239 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
5240 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
5241 const FT_Encoding *encs = regular_order;
5243 if (charset == SYMBOL_CHARSET) encs = symbol_order;
5245 while (*encs != 0)
5247 if (select_charmap( face, *encs )) break;
5248 encs++;
5251 if (!face->charmap && face->num_charmaps)
5253 if (!pFT_Set_Charmap(face, face->charmaps[0]))
5254 return face->charmap->encoding;
5257 return *encs;
5260 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
5262 DWORD size;
5263 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
5264 WORD *alloced = NULL, *ptr = buf;
5265 WORD num_recs, version;
5266 BOOL ret = FALSE;
5268 *flags = 0;
5269 size = get_font_data( font, MS_GASP_TAG, 0, NULL, 0 );
5270 if (size == GDI_ERROR) return FALSE;
5271 if (size < 4 * sizeof(WORD)) return FALSE;
5272 if (size > sizeof(buf))
5274 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
5275 if (!ptr) return FALSE;
5278 get_font_data( font, MS_GASP_TAG, 0, ptr, size );
5280 version = GET_BE_WORD( *ptr++ );
5281 num_recs = GET_BE_WORD( *ptr++ );
5283 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
5285 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
5286 goto done;
5289 while (num_recs--)
5291 *flags = GET_BE_WORD( *(ptr + 1) );
5292 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
5293 ptr += 2;
5295 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
5296 ret = TRUE;
5298 done:
5299 HeapFree( GetProcessHeap(), 0, alloced );
5300 return ret;
5303 #ifdef SONAME_LIBFONTCONFIG
5304 static Family* get_fontconfig_family(DWORD pitch_and_family, const CHARSETINFO *csi)
5306 const char *name;
5307 WCHAR nameW[LF_FACESIZE];
5308 FcChar8 *str;
5309 FcPattern *pat = NULL, *best = NULL;
5310 FcResult result;
5311 FcBool r;
5312 int ret, i;
5313 Family *family = NULL;
5315 if (!csi->fs.fsCsb[0]) return NULL;
5317 if((pitch_and_family & FIXED_PITCH) ||
5318 (pitch_and_family & 0xF0) == FF_MODERN)
5319 name = "monospace";
5320 else if((pitch_and_family & 0xF0) == FF_ROMAN)
5321 name = "serif";
5322 else
5323 name = "sans-serif";
5325 pat = pFcPatternCreate();
5326 if (!pat) return NULL;
5327 r = pFcPatternAddString(pat, FC_FAMILY, (const FcChar8 *)name);
5328 if (!r) goto end;
5329 r = pFcPatternAddString(pat, FC_NAMELANG, (const FcChar8 *)"en-us");
5330 if (!r) goto end;
5331 r = pFcPatternAddString(pat, FC_PRGNAME, (const FcChar8 *)"wine");
5332 if (!r) goto end;
5333 r = pFcConfigSubstitute(NULL, pat, FcMatchPattern);
5334 if (!r) goto end;
5335 pFcDefaultSubstitute(pat);
5337 best = pFcFontMatch(NULL, pat, &result);
5338 if (!best || result != FcResultMatch) goto end;
5340 for (i = 0;
5341 !family && pFcPatternGetString(best, FC_FAMILY, i, &str) == FcResultMatch;
5342 i++)
5344 Face *face;
5345 const SYSTEM_LINKS *font_link;
5346 const struct list *face_list;
5348 ret = MultiByteToWideChar(CP_UTF8, 0, (const char*)str, -1,
5349 nameW, ARRAY_SIZE(nameW));
5350 if (!ret) continue;
5351 family = find_family_from_any_name(nameW);
5352 if (!family) continue;
5354 font_link = find_font_link(family->FamilyName);
5355 face_list = get_face_list_from_family(family);
5356 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5357 if (!face->scalable)
5358 continue;
5359 if (csi->fs.fsCsb[0] & face->fs.fsCsb[0])
5360 goto found;
5361 if (font_link != NULL &&
5362 csi->fs.fsCsb[0] & font_link->fs.fsCsb[0])
5363 goto found;
5365 family = NULL;
5368 found:
5369 if (family)
5370 TRACE("got %s\n", wine_dbgstr_w(nameW));
5372 end:
5373 pFcPatternDestroy(pat);
5374 pFcPatternDestroy(best);
5375 return family;
5377 #endif
5379 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5381 const GSUB_ScriptList *script;
5382 const GSUB_Script *deflt = NULL;
5383 int i;
5384 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5386 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5387 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5389 const GSUB_Script *scr;
5390 int offset;
5392 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5393 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5395 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5396 return scr;
5397 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5398 deflt = scr;
5400 return deflt;
5403 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5405 int i;
5406 int offset;
5407 const GSUB_LangSys *Lang;
5409 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5411 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5413 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5414 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5416 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5417 return Lang;
5419 offset = GET_BE_WORD(script->DefaultLangSys);
5420 if (offset)
5422 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5423 return Lang;
5425 return NULL;
5428 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5430 int i;
5431 const GSUB_FeatureList *feature;
5432 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5434 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5435 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5437 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5438 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5440 const GSUB_Feature *feat;
5441 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5442 return feat;
5445 return NULL;
5448 static const char* get_opentype_script(const GdiFont *font)
5451 * I am not sure if this is the correct way to generate our script tag
5454 switch (font->charset)
5456 case ANSI_CHARSET: return "latn";
5457 case BALTIC_CHARSET: return "latn"; /* ?? */
5458 case CHINESEBIG5_CHARSET: return "hani";
5459 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5460 case GB2312_CHARSET: return "hani";
5461 case GREEK_CHARSET: return "grek";
5462 case HANGUL_CHARSET: return "hang";
5463 case RUSSIAN_CHARSET: return "cyrl";
5464 case SHIFTJIS_CHARSET: return "kana";
5465 case TURKISH_CHARSET: return "latn"; /* ?? */
5466 case VIETNAMESE_CHARSET: return "latn";
5467 case JOHAB_CHARSET: return "latn"; /* ?? */
5468 case ARABIC_CHARSET: return "arab";
5469 case HEBREW_CHARSET: return "hebr";
5470 case THAI_CHARSET: return "thai";
5471 default: return "latn";
5475 static const VOID * get_GSUB_vert_feature(const GdiFont *font)
5477 const GSUB_Header *header;
5478 const GSUB_Script *script;
5479 const GSUB_LangSys *language;
5480 const GSUB_Feature *feature;
5482 if (!font->GSUB_Table)
5483 return NULL;
5485 header = font->GSUB_Table;
5487 script = GSUB_get_script_table(header, get_opentype_script(font));
5488 if (!script)
5490 TRACE("Script not found\n");
5491 return NULL;
5493 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5494 if (!language)
5496 TRACE("Language not found\n");
5497 return NULL;
5499 feature = GSUB_get_feature(header, language, "vrt2");
5500 if (!feature)
5501 feature = GSUB_get_feature(header, language, "vert");
5502 if (!feature)
5504 TRACE("vrt2/vert feature not found\n");
5505 return NULL;
5507 return feature;
5510 static void fill_fileinfo_from_face( GdiFont *font, Face *face )
5512 WIN32_FILE_ATTRIBUTE_DATA info;
5513 int len;
5515 if (!face->file)
5517 font->fileinfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*font->fileinfo));
5518 font->fileinfo->size.QuadPart = face->font_data_size;
5519 return;
5522 len = strlenW(face->file);
5523 font->fileinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*font->fileinfo) + len * sizeof(WCHAR));
5524 if (GetFileAttributesExW(face->file, GetFileExInfoStandard, &info))
5526 font->fileinfo->writetime = info.ftLastWriteTime;
5527 font->fileinfo->size.QuadPart = (LONGLONG)info.nFileSizeHigh << 32 | info.nFileSizeLow;
5528 strcpyW(font->fileinfo->path, face->file);
5530 else
5531 memset(font->fileinfo, 0, sizeof(*font->fileinfo) + len * sizeof(WCHAR));
5534 /*************************************************************
5535 * freetype_SelectFont
5537 static HFONT CDECL freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
5539 struct freetype_physdev *physdev = get_freetype_dev( dev );
5540 GdiFont *ret;
5541 Face *face, *best, *best_bitmap;
5542 Family *family, *last_resort_family;
5543 const struct list *face_list;
5544 INT height, width = 0;
5545 unsigned int score = 0, new_score;
5546 signed int diff = 0, newdiff;
5547 BOOL bd, it, can_use_bitmap, want_vertical;
5548 LOGFONTW lf;
5549 CHARSETINFO csi;
5550 FMAT2 dcmat;
5551 FontSubst *psub = NULL;
5552 DC *dc = get_physdev_dc( dev );
5553 const SYSTEM_LINKS *font_link;
5555 if (!hfont) /* notification that the font has been changed by another driver */
5557 release_font( physdev->font );
5558 physdev->font = NULL;
5559 return 0;
5562 GetObjectW( hfont, sizeof(lf), &lf );
5563 lf.lfWidth = abs(lf.lfWidth);
5565 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
5567 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
5568 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
5569 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
5570 lf.lfEscapement);
5572 if(dc->GraphicsMode == GM_ADVANCED)
5574 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
5575 /* Try to avoid not necessary glyph transformations */
5576 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
5578 lf.lfHeight *= fabs(dcmat.eM11);
5579 lf.lfWidth *= fabs(dcmat.eM11);
5580 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
5583 else
5585 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
5586 font scaling abilities. */
5587 dcmat.eM11 = dcmat.eM22 = 1.0;
5588 dcmat.eM21 = dcmat.eM12 = 0;
5589 lf.lfOrientation = lf.lfEscapement;
5590 if (dc->vport2WorldValid)
5592 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
5593 lf.lfOrientation = -lf.lfOrientation;
5594 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
5595 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
5599 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
5600 dcmat.eM21, dcmat.eM22);
5602 GDI_CheckNotLock();
5603 EnterCriticalSection( &freetype_cs );
5605 /* check the cache first */
5606 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5607 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
5608 goto done;
5611 TRACE("not in cache\n");
5612 ret = alloc_font();
5614 ret->font_desc.matrix = dcmat;
5615 ret->font_desc.lf = lf;
5616 ret->font_desc.can_use_bitmap = can_use_bitmap;
5617 calc_hash(&ret->font_desc);
5619 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
5620 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
5621 original value lfCharSet. Note this is a special case for
5622 Symbol and doesn't happen at least for "Wingdings*" */
5624 if(!strcmpiW(lf.lfFaceName, SymbolW))
5625 lf.lfCharSet = SYMBOL_CHARSET;
5627 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
5628 switch(lf.lfCharSet) {
5629 case DEFAULT_CHARSET:
5630 csi.fs.fsCsb[0] = 0;
5631 break;
5632 default:
5633 FIXME("Untranslated charset %d\n", lf.lfCharSet);
5634 csi.fs.fsCsb[0] = 0;
5635 break;
5639 family = NULL;
5640 if(lf.lfFaceName[0] != '\0') {
5641 CHILD_FONT *font_link_entry;
5642 LPWSTR FaceName = lf.lfFaceName;
5644 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
5646 if(psub) {
5647 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
5648 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
5649 if (psub->to.charset != -1)
5650 lf.lfCharSet = psub->to.charset;
5653 /* We want a match on name and charset or just name if
5654 charset was DEFAULT_CHARSET. If the latter then
5655 we fixup the returned charset later in get_nearest_charset
5656 where we'll either use the charset of the current ansi codepage
5657 or if that's unavailable the first charset that the font supports.
5659 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5660 if (!strncmpiW(family->FamilyName, FaceName, LF_FACESIZE - 1) ||
5661 (psub && !strncmpiW(family->FamilyName, psub->to.name, LF_FACESIZE - 1)))
5663 font_link = find_font_link(family->FamilyName);
5664 face_list = get_face_list_from_family(family);
5665 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5666 if (!(face->scalable || can_use_bitmap))
5667 continue;
5668 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5669 goto found;
5670 if (font_link != NULL &&
5671 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5672 goto found;
5673 if (!csi.fs.fsCsb[0])
5674 goto found;
5679 /* Search by full face name. */
5680 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5681 face_list = get_face_list_from_family(family);
5682 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5683 if(face->FullName && !strncmpiW(face->FullName, FaceName, LF_FACESIZE - 1) &&
5684 (face->scalable || can_use_bitmap))
5686 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5687 goto found_face;
5688 font_link = find_font_link(family->FamilyName);
5689 if (font_link != NULL &&
5690 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5691 goto found_face;
5697 * Try check the SystemLink list first for a replacement font.
5698 * We may find good replacements there.
5700 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
5702 if(!strncmpiW(font_link->font_name, FaceName, LF_FACESIZE - 1) ||
5703 (psub && !strncmpiW(font_link->font_name,psub->to.name, LF_FACESIZE - 1)))
5705 TRACE("found entry in system list\n");
5706 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5708 const SYSTEM_LINKS *links;
5710 face = font_link_entry->face;
5711 if (!(face->scalable || can_use_bitmap))
5712 continue;
5713 family = face->family;
5714 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5715 goto found;
5716 links = find_font_link(family->FamilyName);
5717 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
5718 goto found;
5724 psub = NULL; /* substitution is no more relevant */
5726 /* If requested charset was DEFAULT_CHARSET then try using charset
5727 corresponding to the current ansi codepage */
5728 if (!csi.fs.fsCsb[0])
5730 INT acp = GetACP();
5731 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
5732 FIXME("TCI failed on codepage %d\n", acp);
5733 csi.fs.fsCsb[0] = 0;
5734 } else
5735 lf.lfCharSet = csi.ciCharset;
5738 want_vertical = (lf.lfFaceName[0] == '@');
5740 /* Face families are in the top 4 bits of lfPitchAndFamily,
5741 so mask with 0xF0 before testing */
5743 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
5744 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
5745 strcpyW(lf.lfFaceName, default_fixed);
5746 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
5747 strcpyW(lf.lfFaceName, default_serif);
5748 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
5749 strcpyW(lf.lfFaceName, default_sans);
5750 else
5751 strcpyW(lf.lfFaceName, default_sans);
5752 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5753 if(!strncmpiW(family->FamilyName, lf.lfFaceName, LF_FACESIZE - 1)) {
5754 font_link = find_font_link(family->FamilyName);
5755 face_list = get_face_list_from_family(family);
5756 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5757 if (!(face->scalable || can_use_bitmap))
5758 continue;
5759 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5760 goto found;
5761 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5762 goto found;
5767 #ifdef SONAME_LIBFONTCONFIG
5768 /* Try FontConfig substitutions if the face isn't found */
5769 family = get_fontconfig_family(lf.lfPitchAndFamily, &csi);
5770 if (family) goto found;
5771 #endif
5773 last_resort_family = NULL;
5774 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5775 font_link = find_font_link(family->FamilyName);
5776 face_list = get_face_list_from_family(family);
5777 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5778 if(!(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical &&
5779 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5780 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
5781 if(face->scalable)
5782 goto found;
5783 if(can_use_bitmap && !last_resort_family)
5784 last_resort_family = family;
5789 if(last_resort_family) {
5790 family = last_resort_family;
5791 csi.fs.fsCsb[0] = 0;
5792 goto found;
5795 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5796 face_list = get_face_list_from_family(family);
5797 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5798 if(face->scalable && !(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical) {
5799 csi.fs.fsCsb[0] = 0;
5800 WARN("just using first face for now\n");
5801 goto found;
5803 if(can_use_bitmap && !last_resort_family)
5804 last_resort_family = family;
5807 if(!last_resort_family) {
5808 FIXME("can't find a single appropriate font - bailing\n");
5809 free_font(ret);
5810 ret = NULL;
5811 goto done;
5814 WARN("could only find a bitmap font - this will probably look awful!\n");
5815 family = last_resort_family;
5816 csi.fs.fsCsb[0] = 0;
5818 found:
5819 it = lf.lfItalic ? 1 : 0;
5820 bd = lf.lfWeight > 550 ? 1 : 0;
5822 height = lf.lfHeight;
5824 face = best = best_bitmap = NULL;
5825 font_link = find_font_link(family->FamilyName);
5826 face_list = get_face_list_from_family(family);
5827 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5829 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5830 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
5831 !csi.fs.fsCsb[0])
5833 BOOL italic, bold;
5835 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
5836 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
5837 new_score = (italic ^ it) + (bold ^ bd);
5838 if(!best || new_score <= score)
5840 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5841 italic, bold, it, bd);
5842 score = new_score;
5843 best = face;
5844 if(best->scalable && score == 0) break;
5845 if(!best->scalable)
5847 if(height > 0)
5848 newdiff = height - (signed int)(best->size.height);
5849 else
5850 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
5851 if(!best_bitmap || new_score < score ||
5852 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
5854 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
5855 diff = newdiff;
5856 best_bitmap = best;
5857 if(score == 0 && diff == 0) break;
5863 if(best)
5864 face = best->scalable ? best : best_bitmap;
5865 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
5866 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
5868 found_face:
5869 height = lf.lfHeight;
5871 ret->fs = face->fs;
5873 if(csi.fs.fsCsb[0]) {
5874 ret->charset = lf.lfCharSet;
5875 ret->codepage = csi.ciACP;
5877 else
5878 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
5880 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
5881 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
5883 ret->aveWidth = height ? lf.lfWidth : 0;
5885 if(!face->scalable) {
5886 /* Windows uses integer scaling factors for bitmap fonts */
5887 INT scale, scaled_height;
5888 GdiFont *cachedfont;
5890 /* FIXME: rotation of bitmap fonts is ignored */
5891 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
5892 if (ret->aveWidth)
5893 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
5894 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
5895 dcmat.eM11 = dcmat.eM22 = 1.0;
5896 /* As we changed the matrix, we need to search the cache for the font again,
5897 * otherwise we might explode the cache. */
5898 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5899 TRACE("Found cached font after non-scalable matrix rescale!\n");
5900 free_font( ret );
5901 ret = cachedfont;
5902 goto done;
5904 calc_hash(&ret->font_desc);
5906 if (height != 0) height = diff;
5907 height += face->size.height;
5909 scale = (height + face->size.height - 1) / face->size.height;
5910 scaled_height = scale * face->size.height;
5911 /* Only jump to the next height if the difference <= 25% original height */
5912 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
5913 /* The jump between unscaled and doubled is delayed by 1 */
5914 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
5915 ret->scale_y = scale;
5917 width = face->size.x_ppem >> 6;
5918 height = face->size.y_ppem >> 6;
5920 else
5921 ret->scale_y = 1.0;
5922 TRACE("font scale y: %f\n", ret->scale_y);
5924 ret->ft_face = OpenFontFace(ret, face, width, height);
5926 if (!ret->ft_face)
5928 free_font( ret );
5929 ret = NULL;
5930 goto done;
5933 fill_fileinfo_from_face( ret, face );
5934 ret->ntmFlags = face->ntmFlags;
5936 pick_charmap( ret->ft_face, ret->charset );
5938 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
5939 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
5940 ret->underline = lf.lfUnderline ? 0xff : 0;
5941 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
5942 create_child_font_list(ret);
5944 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
5946 int length = get_font_data(ret, MS_GSUB_TAG , 0, NULL, 0);
5947 if (length != GDI_ERROR)
5949 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
5950 get_font_data(ret, MS_GSUB_TAG , 0, ret->GSUB_Table, length);
5951 TRACE("Loaded GSUB table of %i bytes\n",length);
5952 ret->vert_feature = get_GSUB_vert_feature(ret);
5953 if (!ret->vert_feature)
5955 TRACE("Vertical feature not found\n");
5956 HeapFree(GetProcessHeap(), 0, ret->GSUB_Table);
5957 ret->GSUB_Table = NULL;
5961 ret->aa_flags = HIWORD( face->flags );
5963 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
5965 add_to_cache(ret);
5966 done:
5967 if (ret)
5969 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
5971 switch (lf.lfQuality)
5973 case NONANTIALIASED_QUALITY:
5974 case ANTIALIASED_QUALITY:
5975 next->funcs->pSelectFont( dev, hfont, aa_flags );
5976 break;
5977 case CLEARTYPE_QUALITY:
5978 case CLEARTYPE_NATURAL_QUALITY:
5979 default:
5980 if (!*aa_flags) *aa_flags = ret->aa_flags;
5981 next->funcs->pSelectFont( dev, hfont, aa_flags );
5983 /* fixup the antialiasing flags for that font */
5984 switch (*aa_flags)
5986 case WINE_GGO_HRGB_BITMAP:
5987 case WINE_GGO_HBGR_BITMAP:
5988 case WINE_GGO_VRGB_BITMAP:
5989 case WINE_GGO_VBGR_BITMAP:
5990 if (is_subpixel_rendering_enabled()) break;
5991 *aa_flags = GGO_GRAY4_BITMAP;
5992 /* fall through */
5993 case GGO_GRAY2_BITMAP:
5994 case GGO_GRAY4_BITMAP:
5995 case GGO_GRAY8_BITMAP:
5996 case WINE_GGO_GRAY16_BITMAP:
5997 if ((!antialias_fakes || (!ret->fake_bold && !ret->fake_italic)) && is_hinting_enabled())
5999 WORD gasp_flags;
6000 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
6002 TRACE( "font %s %d aa disabled by GASP\n",
6003 debugstr_w(lf.lfFaceName), lf.lfHeight );
6004 *aa_flags = GGO_BITMAP;
6009 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
6010 release_font( physdev->font );
6011 physdev->font = ret;
6013 LeaveCriticalSection( &freetype_cs );
6014 return ret ? hfont : 0;
6017 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
6019 HRSRC rsrc;
6020 HGLOBAL hMem;
6021 WCHAR *p;
6022 int i;
6024 id += IDS_FIRST_SCRIPT;
6025 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
6026 if (!rsrc) return 0;
6027 hMem = LoadResource( gdi32_module, rsrc );
6028 if (!hMem) return 0;
6030 p = LockResource( hMem );
6031 id &= 0x000f;
6032 while (id--) p += *p + 1;
6034 i = min(LF_FACESIZE - 1, *p);
6035 memcpy(buffer, p + 1, i * sizeof(WCHAR));
6036 buffer[i] = 0;
6037 return i;
6040 static inline BOOL is_complex_script_ansi_cp(UINT ansi_cp)
6042 return (ansi_cp == 874 /* Thai */
6043 || ansi_cp == 1255 /* Hebrew */
6044 || ansi_cp == 1256 /* Arabic */
6048 /***************************************************
6049 * create_enum_charset_list
6051 * This function creates charset enumeration list because in DEFAULT_CHARSET
6052 * case, the ANSI codepage's charset takes precedence over other charsets.
6053 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
6054 * This function works as a filter other than DEFAULT_CHARSET case.
6056 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
6058 CHARSETINFO csi;
6059 DWORD n = 0;
6061 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
6062 csi.fs.fsCsb[0] != 0) {
6063 list->element[n].mask = csi.fs.fsCsb[0];
6064 list->element[n].charset = csi.ciCharset;
6065 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
6066 n++;
6068 else { /* charset is DEFAULT_CHARSET or invalid. */
6069 INT acp, i;
6070 DWORD mask = 0;
6072 /* Set the current codepage's charset as the first element. */
6073 acp = GetACP();
6074 if (!is_complex_script_ansi_cp(acp) &&
6075 TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
6076 csi.fs.fsCsb[0] != 0) {
6077 list->element[n].mask = csi.fs.fsCsb[0];
6078 list->element[n].charset = csi.ciCharset;
6079 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
6080 mask |= csi.fs.fsCsb[0];
6081 n++;
6084 /* Fill out left elements. */
6085 for (i = 0; i < 32; i++) {
6086 FONTSIGNATURE fs;
6087 fs.fsCsb[0] = 1L << i;
6088 fs.fsCsb[1] = 0;
6089 if (fs.fsCsb[0] & mask)
6090 continue; /* skip, already added. */
6091 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
6092 continue; /* skip, this is an invalid fsCsb bit. */
6094 list->element[n].mask = fs.fsCsb[0];
6095 list->element[n].charset = csi.ciCharset;
6096 load_script_name( i, list->element[n].name );
6097 mask |= fs.fsCsb[0];
6098 n++;
6101 /* add catch all mask for remaining bits */
6102 if (~mask)
6104 list->element[n].mask = ~mask;
6105 list->element[n].charset = DEFAULT_CHARSET;
6106 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
6107 n++;
6110 list->total = n;
6112 return n;
6115 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
6116 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
6118 GdiFont *font;
6119 LONG width, height;
6121 if (face->cached_enum_data)
6123 TRACE("Cached\n");
6124 *pelf = face->cached_enum_data->elf;
6125 *pntm = face->cached_enum_data->ntm;
6126 *ptype = face->cached_enum_data->type;
6127 return;
6130 font = alloc_font();
6132 if(face->scalable) {
6133 height = 100;
6134 width = 0;
6135 } else {
6136 height = face->size.y_ppem >> 6;
6137 width = face->size.x_ppem >> 6;
6139 font->scale_y = 1.0;
6141 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
6143 free_font(font);
6144 return;
6147 font->name = strdupW( family_name );
6148 font->ntmFlags = face->ntmFlags;
6150 if (get_outline_text_metrics(font))
6152 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
6154 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
6155 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
6156 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
6158 lstrcpynW(pelf->elfLogFont.lfFaceName,
6159 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
6160 LF_FACESIZE);
6161 lstrcpynW(pelf->elfFullName,
6162 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
6163 LF_FULLFACESIZE);
6164 lstrcpynW(pelf->elfStyle,
6165 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
6166 LF_FACESIZE);
6168 else
6170 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
6172 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
6173 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
6174 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
6176 lstrcpynW(pelf->elfLogFont.lfFaceName, family_name, LF_FACESIZE);
6177 if (face->FullName)
6178 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
6179 else
6180 lstrcpynW(pelf->elfFullName, family_name, LF_FULLFACESIZE);
6181 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
6184 pntm->ntmTm.ntmFlags = face->ntmFlags;
6185 pntm->ntmFontSig = face->fs;
6187 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
6189 pelf->elfLogFont.lfEscapement = 0;
6190 pelf->elfLogFont.lfOrientation = 0;
6191 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
6192 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
6193 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
6194 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
6195 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
6196 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
6197 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
6198 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
6199 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
6200 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
6201 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
6203 *ptype = 0;
6204 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
6205 *ptype |= TRUETYPE_FONTTYPE;
6206 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
6207 *ptype |= DEVICE_FONTTYPE;
6208 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
6209 *ptype |= RASTER_FONTTYPE;
6211 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
6212 if (face->cached_enum_data)
6214 face->cached_enum_data->elf = *pelf;
6215 face->cached_enum_data->ntm = *pntm;
6216 face->cached_enum_data->type = *ptype;
6219 free_font(font);
6222 static BOOL family_matches(Family *family, const WCHAR *face_name)
6224 Face *face;
6225 const struct list *face_list;
6227 if (!strncmpiW(face_name, family->FamilyName, LF_FACESIZE - 1)) return TRUE;
6229 face_list = get_face_list_from_family(family);
6230 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
6231 if (face->FullName && !strncmpiW(face_name, face->FullName, LF_FACESIZE - 1)) return TRUE;
6233 return FALSE;
6236 static BOOL face_matches(const WCHAR *family_name, Face *face, const WCHAR *face_name)
6238 if (!strncmpiW(face_name, family_name, LF_FACESIZE - 1)) return TRUE;
6240 return (face->FullName && !strncmpiW(face_name, face->FullName, LF_FACESIZE - 1));
6243 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
6244 FONTENUMPROCW proc, LPARAM lparam, const WCHAR *subst)
6246 ENUMLOGFONTEXW elf;
6247 NEWTEXTMETRICEXW ntm;
6248 DWORD type = 0;
6249 DWORD i;
6251 GetEnumStructs(face, face->family->FamilyName, &elf, &ntm, &type);
6252 for(i = 0; i < list->total; i++) {
6253 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
6254 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
6255 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
6256 i = list->total; /* break out of loop after enumeration */
6258 else
6260 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
6261 /* use the DEFAULT_CHARSET case only if no other charset is present */
6262 if (list->element[i].charset == DEFAULT_CHARSET &&
6263 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
6264 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
6265 strcpyW(elf.elfScript, list->element[i].name);
6266 if (!elf.elfScript[0])
6267 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
6269 /* Font Replacement */
6270 if (family != face->family)
6272 lstrcpynW(elf.elfLogFont.lfFaceName, family->FamilyName, LF_FACESIZE);
6273 if (face->FullName)
6274 lstrcpynW(elf.elfFullName, face->FullName, LF_FULLFACESIZE);
6275 else
6276 lstrcpynW(elf.elfFullName, family->FamilyName, LF_FULLFACESIZE);
6278 if (subst)
6279 strcpyW(elf.elfLogFont.lfFaceName, subst);
6280 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
6281 debugstr_w(elf.elfLogFont.lfFaceName),
6282 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
6283 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
6284 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
6285 ntm.ntmTm.ntmFlags);
6286 /* release section before callback (FIXME) */
6287 LeaveCriticalSection( &freetype_cs );
6288 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
6289 EnterCriticalSection( &freetype_cs );
6291 return TRUE;
6294 /*************************************************************
6295 * freetype_EnumFonts
6297 static BOOL CDECL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
6299 Family *family;
6300 Face *face;
6301 const struct list *face_list;
6302 LOGFONTW lf;
6303 struct enum_charset_list enum_charsets;
6305 if (!plf)
6307 lf.lfCharSet = DEFAULT_CHARSET;
6308 lf.lfPitchAndFamily = 0;
6309 lf.lfFaceName[0] = 0;
6310 plf = &lf;
6313 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
6315 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
6317 GDI_CheckNotLock();
6318 EnterCriticalSection( &freetype_cs );
6319 if(plf->lfFaceName[0]) {
6320 WCHAR *face_name = plf->lfFaceName;
6321 FontSubst *psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
6323 if(psub) {
6324 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
6325 debugstr_w(psub->to.name));
6326 face_name = psub->to.name;
6329 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
6330 if (!family_matches(family, face_name)) continue;
6331 face_list = get_face_list_from_family(family);
6332 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
6333 if (!face_matches(family->FamilyName, face, face_name)) continue;
6334 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam, psub ? psub->from.name : NULL)) return FALSE;
6337 } else {
6338 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
6339 face_list = get_face_list_from_family(family);
6340 face = LIST_ENTRY(list_head(face_list), Face, entry);
6341 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam, NULL)) return FALSE;
6344 LeaveCriticalSection( &freetype_cs );
6345 return TRUE;
6348 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
6350 pt->x.value = vec->x >> 6;
6351 pt->x.fract = (vec->x & 0x3f) << 10;
6352 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
6353 pt->y.value = vec->y >> 6;
6354 pt->y.fract = (vec->y & 0x3f) << 10;
6355 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
6358 /***************************************************
6359 * According to the MSDN documentation on WideCharToMultiByte,
6360 * certain codepages cannot set the default_used parameter.
6361 * This returns TRUE if the codepage can set that parameter, false else
6362 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
6364 static BOOL codepage_sets_default_used(UINT codepage)
6366 switch (codepage)
6368 case CP_UTF7:
6369 case CP_UTF8:
6370 case CP_SYMBOL:
6371 return FALSE;
6372 default:
6373 return TRUE;
6378 * GSUB Table handling functions
6381 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
6383 const GSUB_CoverageFormat1* cf1;
6385 cf1 = table;
6387 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
6389 int count = GET_BE_WORD(cf1->GlyphCount);
6390 int i;
6391 TRACE("Coverage Format 1, %i glyphs\n",count);
6392 for (i = 0; i < count; i++)
6393 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
6394 return i;
6395 return -1;
6397 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
6399 const GSUB_CoverageFormat2* cf2;
6400 int i;
6401 int count;
6402 cf2 = (const GSUB_CoverageFormat2*)cf1;
6404 count = GET_BE_WORD(cf2->RangeCount);
6405 TRACE("Coverage Format 2, %i ranges\n",count);
6406 for (i = 0; i < count; i++)
6408 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
6409 return -1;
6410 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
6411 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
6413 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
6414 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
6417 return -1;
6419 else
6420 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
6422 return -1;
6425 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
6427 int i;
6428 int offset;
6429 const GSUB_LookupList *lookup;
6430 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
6432 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
6433 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
6435 const GSUB_LookupTable *look;
6436 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
6437 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
6438 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
6439 if (GET_BE_WORD(look->LookupType) != 1)
6440 FIXME("We only handle SubType 1\n");
6441 else
6443 int j;
6445 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
6447 const GSUB_SingleSubstFormat1 *ssf1;
6448 offset = GET_BE_WORD(look->SubTable[j]);
6449 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
6450 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
6452 int offset = GET_BE_WORD(ssf1->Coverage);
6453 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
6454 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
6456 TRACE(" Glyph 0x%x ->",glyph);
6457 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
6458 TRACE(" 0x%x\n",glyph);
6461 else
6463 const GSUB_SingleSubstFormat2 *ssf2;
6464 INT index;
6465 INT offset;
6467 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
6468 offset = GET_BE_WORD(ssf1->Coverage);
6469 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
6470 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
6471 TRACE(" Coverage index %i\n",index);
6472 if (index != -1)
6474 TRACE(" Glyph is 0x%x ->",glyph);
6475 glyph = GET_BE_WORD(ssf2->Substitute[index]);
6476 TRACE("0x%x\n",glyph);
6482 return glyph;
6486 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
6488 const GSUB_Header *header;
6489 const GSUB_Feature *feature;
6491 if (!font->GSUB_Table)
6492 return glyph;
6494 header = font->GSUB_Table;
6495 feature = font->vert_feature;
6497 return GSUB_apply_feature(header, feature, glyph);
6500 static FT_UInt get_glyph_index_symbol(const GdiFont *font, UINT glyph)
6502 FT_UInt ret;
6504 if (glyph < 0x100) glyph += 0xf000;
6505 /* there are a number of old pre-Unicode "broken" TTFs, which
6506 do have symbols at U+00XX instead of U+f0XX */
6507 if (!(ret = pFT_Get_Char_Index(font->ft_face, glyph)))
6508 ret = pFT_Get_Char_Index(font->ft_face, glyph - 0xf000);
6510 return ret;
6513 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
6515 FT_UInt ret;
6516 WCHAR wc;
6517 char buf;
6519 if (font->ft_face->charmap->encoding == FT_ENCODING_NONE)
6521 BOOL default_used;
6522 BOOL *default_used_pointer;
6524 default_used_pointer = NULL;
6525 default_used = FALSE;
6526 if (codepage_sets_default_used(font->codepage))
6527 default_used_pointer = &default_used;
6528 wc = (WCHAR)glyph;
6529 if (!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) ||
6530 default_used)
6532 if (font->codepage == CP_SYMBOL)
6534 ret = get_glyph_index_symbol(font, glyph);
6535 if (!ret)
6537 if (WideCharToMultiByte(CP_ACP, 0, &wc, 1, &buf, 1, NULL, NULL))
6538 ret = get_glyph_index_symbol(font, buf);
6541 else
6542 ret = 0;
6544 else
6545 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
6546 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6547 return ret;
6550 if (font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
6552 ret = get_glyph_index_symbol(font, glyph);
6553 if (!ret)
6555 wc = (WCHAR)glyph;
6556 if (WideCharToMultiByte(CP_ACP, 0, &wc, 1, &buf, 1, NULL, NULL))
6557 ret = get_glyph_index_symbol(font, (unsigned char)buf);
6559 return ret;
6562 return pFT_Get_Char_Index(font->ft_face, glyph);
6565 /* helper for freetype_GetGlyphIndices */
6566 static FT_UInt get_gdi_glyph_index(const GdiFont *font, UINT glyph)
6568 WCHAR wc = (WCHAR)glyph;
6569 BOOL default_used = FALSE;
6570 BOOL *default_used_pointer = NULL;
6571 FT_UInt ret;
6572 char buf;
6574 if(font->ft_face->charmap->encoding != FT_ENCODING_NONE)
6575 return get_glyph_index(font, glyph);
6577 if (codepage_sets_default_used(font->codepage))
6578 default_used_pointer = &default_used;
6579 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer)
6580 || default_used)
6582 if (font->codepage == CP_SYMBOL && wc < 0x100)
6583 ret = (unsigned char)wc;
6584 else
6585 ret = 0;
6587 else
6588 ret = (unsigned char)buf;
6589 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6590 return ret;
6593 static FT_UInt get_default_char_index(GdiFont *font)
6595 FT_UInt default_char;
6597 if (FT_IS_SFNT(font->ft_face))
6599 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
6600 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
6602 else
6604 TEXTMETRICW textm;
6605 get_text_metrics(font, &textm);
6606 default_char = textm.tmDefaultChar;
6609 return default_char;
6612 /*************************************************************
6613 * freetype_GetGlyphIndices
6615 static DWORD CDECL freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
6617 struct freetype_physdev *physdev = get_freetype_dev( dev );
6618 int i;
6619 WORD default_char;
6620 BOOL got_default = FALSE;
6622 if (!physdev->font)
6624 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
6625 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
6628 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
6630 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
6631 got_default = TRUE;
6634 GDI_CheckNotLock();
6635 EnterCriticalSection( &freetype_cs );
6637 for(i = 0; i < count; i++)
6639 pgi[i] = get_gdi_glyph_index(physdev->font, lpstr[i]);
6640 if (pgi[i] == 0)
6642 if (!got_default)
6644 default_char = get_default_char_index(physdev->font);
6645 got_default = TRUE;
6647 pgi[i] = default_char;
6649 else
6650 pgi[i] = get_GSUB_vert_glyph(physdev->font, pgi[i]);
6652 LeaveCriticalSection( &freetype_cs );
6653 return count;
6656 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
6658 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
6659 return !memcmp(matrix, &identity, sizeof(FMAT2));
6662 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
6664 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
6665 return !memcmp(matrix, &identity, sizeof(MAT2));
6668 static inline FT_Vector normalize_vector(FT_Vector *vec)
6670 FT_Vector out;
6671 FT_Fixed len;
6672 len = pFT_Vector_Length(vec);
6673 if (len) {
6674 out.x = (vec->x << 6) / len;
6675 out.y = (vec->y << 6) / len;
6677 else
6678 out.x = out.y = 0;
6679 return out;
6682 /* get_glyph_outline() glyph transform matrices index */
6683 enum matrices_index
6685 matrix_hori,
6686 matrix_vert,
6687 matrix_unrotated
6690 static BOOL get_transform_matrices( GdiFont *font, BOOL vertical, const MAT2 *user_transform,
6691 FT_Matrix matrices[3] )
6693 static const FT_Matrix identity_mat = { (1 << 16), 0, 0, (1 << 16) };
6694 BOOL needs_transform = FALSE;
6695 double width_ratio;
6696 int i;
6698 matrices[matrix_unrotated] = identity_mat;
6700 /* Scaling factor */
6701 if (font->aveWidth)
6703 TEXTMETRICW tm;
6704 get_text_metrics( font, &tm );
6706 width_ratio = (double)font->aveWidth;
6707 width_ratio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6709 else
6710 width_ratio = font->scale_y;
6712 /* Scaling transform */
6713 if (width_ratio != 1.0 || font->scale_y != 1.0)
6715 FT_Matrix scale_mat;
6716 scale_mat.xx = FT_FixedFromFloat( width_ratio );
6717 scale_mat.xy = 0;
6718 scale_mat.yx = 0;
6719 scale_mat.yy = FT_FixedFromFloat( font->scale_y );
6721 pFT_Matrix_Multiply( &scale_mat, &matrices[matrix_unrotated] );
6722 needs_transform = TRUE;
6725 /* Slant transform */
6726 if (font->fake_italic)
6728 FT_Matrix slant_mat;
6729 slant_mat.xx = (1 << 16);
6730 slant_mat.xy = (1 << 16) >> 2;
6731 slant_mat.yx = 0;
6732 slant_mat.yy = (1 << 16);
6734 pFT_Matrix_Multiply( &slant_mat, &matrices[matrix_unrotated] );
6735 needs_transform = TRUE;
6738 /* Rotation transform */
6739 matrices[matrix_hori] = matrices[matrix_unrotated];
6740 if (font->orientation % 3600)
6742 FT_Matrix rotation_mat;
6743 FT_Vector angle;
6745 pFT_Vector_Unit( &angle, MulDiv( 1 << 16, font->orientation, 10 ) );
6746 rotation_mat.xx = angle.x;
6747 rotation_mat.xy = -angle.y;
6748 rotation_mat.yx = angle.y;
6749 rotation_mat.yy = angle.x;
6750 pFT_Matrix_Multiply( &rotation_mat, &matrices[matrix_hori] );
6751 needs_transform = TRUE;
6754 /* Vertical transform */
6755 matrices[matrix_vert] = matrices[matrix_hori];
6756 if (vertical)
6758 FT_Matrix vertical_mat = { 0, -(1 << 16), 1 << 16, 0 }; /* 90 degrees rotation */
6760 pFT_Matrix_Multiply( &vertical_mat, &matrices[matrix_vert] );
6761 needs_transform = TRUE;
6764 /* World transform */
6765 if (!is_identity_FMAT2( &font->font_desc.matrix ))
6767 FT_Matrix world_mat;
6768 world_mat.xx = FT_FixedFromFloat( font->font_desc.matrix.eM11 );
6769 world_mat.xy = -FT_FixedFromFloat( font->font_desc.matrix.eM21 );
6770 world_mat.yx = -FT_FixedFromFloat( font->font_desc.matrix.eM12 );
6771 world_mat.yy = FT_FixedFromFloat( font->font_desc.matrix.eM22 );
6773 for (i = 0; i < 3; i++)
6774 pFT_Matrix_Multiply( &world_mat, &matrices[i] );
6775 needs_transform = TRUE;
6778 /* Extra transformation specified by caller */
6779 if (!is_identity_MAT2( user_transform ))
6781 FT_Matrix user_mat;
6782 user_mat.xx = FT_FixedFromFIXED( user_transform->eM11 );
6783 user_mat.xy = FT_FixedFromFIXED( user_transform->eM21 );
6784 user_mat.yx = FT_FixedFromFIXED( user_transform->eM12 );
6785 user_mat.yy = FT_FixedFromFIXED( user_transform->eM22 );
6787 for (i = 0; i < 3; i++)
6788 pFT_Matrix_Multiply( &user_mat, &matrices[i] );
6789 needs_transform = TRUE;
6792 return needs_transform;
6795 static BOOL get_bold_glyph_outline(FT_GlyphSlot glyph, LONG ppem, FT_Glyph_Metrics *metrics)
6797 FT_Error err;
6798 FT_Pos strength;
6799 FT_BBox bbox;
6801 if(glyph->format != FT_GLYPH_FORMAT_OUTLINE)
6802 return FALSE;
6803 if(!pFT_Outline_Embolden)
6804 return FALSE;
6806 strength = MulDiv(ppem, 1 << 6, 24);
6807 err = pFT_Outline_Embolden(&glyph->outline, strength);
6808 if(err) {
6809 TRACE("FT_Ouline_Embolden returns %d\n", err);
6810 return FALSE;
6813 pFT_Outline_Get_CBox(&glyph->outline, &bbox);
6814 metrics->width = bbox.xMax - bbox.xMin;
6815 metrics->height = bbox.yMax - bbox.yMin;
6816 metrics->horiBearingX = bbox.xMin;
6817 metrics->horiBearingY = bbox.yMax;
6818 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
6819 metrics->vertBearingY = (metrics->vertAdvance - metrics->height) / 2;
6820 return TRUE;
6823 static inline BYTE get_max_level( UINT format )
6825 switch( format )
6827 case GGO_GRAY2_BITMAP: return 4;
6828 case GGO_GRAY4_BITMAP: return 16;
6829 case GGO_GRAY8_BITMAP: return 64;
6831 return 255;
6834 extern const unsigned short vertical_orientation_table[] DECLSPEC_HIDDEN;
6836 static BOOL check_unicode_tategaki(WCHAR uchar)
6838 unsigned short orientation = vertical_orientation_table[vertical_orientation_table[vertical_orientation_table[uchar >> 8]+((uchar >> 4) & 0x0f)]+ (uchar & 0xf)];
6840 /* We only reach this code if typographical substitution did not occur */
6841 /* Type: U or Type: Tu */
6842 return (orientation == 1 || orientation == 3);
6845 static FT_Vector get_advance_metric(GdiFont *incoming_font, GdiFont *font,
6846 const FT_Glyph_Metrics *metrics,
6847 const FT_Matrix *transMat, BOOL vertical_metrics)
6849 FT_Vector adv;
6850 FT_Fixed base_advance, em_scale = 0;
6851 BOOL fixed_pitch_full = FALSE;
6853 if (vertical_metrics)
6854 base_advance = metrics->vertAdvance;
6855 else
6856 base_advance = metrics->horiAdvance;
6858 adv.x = base_advance;
6859 adv.y = 0;
6861 /* In fixed-pitch font, we adjust the fullwidth character advance so that
6862 they have double halfwidth character width. E.g. if the font is 19 ppem,
6863 we return 20 (not 19) for fullwidth characters as we return 10 for
6864 halfwidth characters. */
6865 if(FT_IS_SCALABLE(incoming_font->ft_face) &&
6866 (incoming_font->potm || get_outline_text_metrics(incoming_font)) &&
6867 !(incoming_font->potm->otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
6868 UINT avg_advance;
6869 em_scale = MulDiv(incoming_font->ppem, 1 << 16,
6870 incoming_font->ft_face->units_per_EM);
6871 avg_advance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
6872 fixed_pitch_full = (avg_advance > 0 &&
6873 (base_advance + 63) >> 6 ==
6874 pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale));
6875 if (fixed_pitch_full && !transMat)
6876 adv.x = (avg_advance * 2) << 6;
6879 if (transMat) {
6880 pFT_Vector_Transform(&adv, transMat);
6881 if (fixed_pitch_full && adv.y == 0) {
6882 FT_Vector vec;
6883 vec.x = incoming_font->ntmAvgWidth;
6884 vec.y = 0;
6885 pFT_Vector_Transform(&vec, transMat);
6886 adv.x = (pFT_MulFix(vec.x, em_scale) * 2) << 6;
6890 if (font->fake_bold) {
6891 if (!transMat)
6892 adv.x += 1 << 6;
6893 else {
6894 FT_Vector fake_bold_adv, vec = { 1 << 6, 0 };
6895 pFT_Vector_Transform(&vec, transMat);
6896 fake_bold_adv = normalize_vector(&vec);
6897 adv.x += fake_bold_adv.x;
6898 adv.y += fake_bold_adv.y;
6902 adv.x = (adv.x + 63) & -64;
6903 adv.y = -((adv.y + 63) & -64);
6904 return adv;
6907 static FT_BBox get_transformed_bbox( const FT_Glyph_Metrics *metrics,
6908 BOOL needs_transform, const FT_Matrix metrices[3] )
6910 FT_BBox bbox = { 0, 0, 0, 0 };
6912 if (!needs_transform)
6914 bbox.xMin = (metrics->horiBearingX) & -64;
6915 bbox.xMax = (metrics->horiBearingX + metrics->width + 63) & -64;
6916 bbox.yMax = (metrics->horiBearingY + 63) & -64;
6917 bbox.yMin = (metrics->horiBearingY - metrics->height) & -64;
6919 else
6921 FT_Vector vec;
6922 INT xc, yc;
6924 for (xc = 0; xc < 2; xc++)
6926 for (yc = 0; yc < 2; yc++)
6928 vec.x = metrics->horiBearingX + xc * metrics->width;
6929 vec.y = metrics->horiBearingY - yc * metrics->height;
6930 TRACE( "Vec %ld,i %ld\n", vec.x, vec.y );
6931 pFT_Vector_Transform( &vec, &metrices[matrix_vert] );
6932 if (xc == 0 && yc == 0)
6934 bbox.xMin = bbox.xMax = vec.x;
6935 bbox.yMin = bbox.yMax = vec.y;
6937 else
6939 if (vec.x < bbox.xMin) bbox.xMin = vec.x;
6940 else if (vec.x > bbox.xMax) bbox.xMax = vec.x;
6941 if (vec.y < bbox.yMin) bbox.yMin = vec.y;
6942 else if (vec.y > bbox.yMax) bbox.yMax = vec.y;
6946 bbox.xMin = bbox.xMin & -64;
6947 bbox.xMax = (bbox.xMax + 63) & -64;
6948 bbox.yMin = bbox.yMin & -64;
6949 bbox.yMax = (bbox.yMax + 63) & -64;
6950 TRACE( "transformed box: (%ld, %ld - %ld, %ld)\n", bbox.xMin, bbox.yMax, bbox.xMax, bbox.yMin );
6953 return bbox;
6956 static void compute_metrics( GdiFont *incoming_font, GdiFont *font,
6957 FT_BBox bbox, const FT_Glyph_Metrics *metrics,
6958 BOOL vertical, BOOL vertical_metrics,
6959 BOOL needs_transform, const FT_Matrix matrices[3],
6960 GLYPHMETRICS *gm, ABC *abc )
6962 FT_Vector adv, vec, origin;
6964 if (!needs_transform)
6966 adv = get_advance_metric( incoming_font, font, metrics, NULL, vertical_metrics );
6967 gm->gmCellIncX = adv.x >> 6;
6968 gm->gmCellIncY = 0;
6969 origin.x = bbox.xMin;
6970 origin.y = bbox.yMax;
6971 abc->abcA = origin.x >> 6;
6972 abc->abcB = (metrics->width + 63) >> 6;
6974 else
6976 FT_Pos lsb;
6978 if (vertical && (font->potm || get_outline_text_metrics( font )))
6980 if (vertical_metrics)
6981 lsb = metrics->horiBearingY + metrics->vertBearingY;
6982 else
6983 lsb = metrics->vertAdvance + (font->potm->otmDescent << 6);
6984 vec.x = lsb;
6985 vec.y = font->potm->otmDescent << 6;
6986 TRACE( "Vec %ld,%ld\n", vec.x>>6, vec.y>>6 );
6987 pFT_Vector_Transform( &vec, &matrices[matrix_hori] );
6988 origin.x = (vec.x + bbox.xMin) & -64;
6989 origin.y = (vec.y + bbox.yMax + 63) & -64;
6990 lsb -= metrics->horiBearingY;
6992 else
6994 origin.x = bbox.xMin;
6995 origin.y = bbox.yMax;
6996 lsb = metrics->horiBearingX;
6999 adv = get_advance_metric( incoming_font, font, metrics, &matrices[matrix_hori],
7000 vertical_metrics );
7001 gm->gmCellIncX = adv.x >> 6;
7002 gm->gmCellIncY = adv.y >> 6;
7004 adv = get_advance_metric( incoming_font, font, metrics, &matrices[matrix_unrotated],
7005 vertical_metrics );
7006 adv.x = pFT_Vector_Length( &adv );
7007 adv.y = 0;
7009 vec.x = lsb;
7010 vec.y = 0;
7011 pFT_Vector_Transform( &vec, &matrices[matrix_unrotated] );
7012 if (lsb > 0) abc->abcA = pFT_Vector_Length( &vec ) >> 6;
7013 else abc->abcA = -((pFT_Vector_Length( &vec ) + 63) >> 6);
7015 /* We use lsb again to avoid rounding errors */
7016 vec.x = lsb + (vertical ? metrics->height : metrics->width);
7017 vec.y = 0;
7018 pFT_Vector_Transform( &vec, &matrices[matrix_unrotated] );
7019 abc->abcB = ((pFT_Vector_Length( &vec ) + 63) >> 6) - abc->abcA;
7021 if (!abc->abcB) abc->abcB = 1;
7022 abc->abcC = (adv.x >> 6) - abc->abcA - abc->abcB;
7024 gm->gmptGlyphOrigin.x = origin.x >> 6;
7025 gm->gmptGlyphOrigin.y = origin.y >> 6;
7026 gm->gmBlackBoxX = (bbox.xMax - bbox.xMin) >> 6;
7027 gm->gmBlackBoxY = (bbox.yMax - bbox.yMin) >> 6;
7028 if (!gm->gmBlackBoxX) gm->gmBlackBoxX = 1;
7029 if (!gm->gmBlackBoxY) gm->gmBlackBoxY = 1;
7031 TRACE( "gm: %u, %u, %s, %d, %d abc %d, %u, %d\n",
7032 gm->gmBlackBoxX, gm->gmBlackBoxY, wine_dbgstr_point(&gm->gmptGlyphOrigin),
7033 gm->gmCellIncX, gm->gmCellIncY, abc->abcA, abc->abcB, abc->abcC );
7037 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
7039 static DWORD get_mono_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox,
7040 BOOL fake_bold, BOOL needs_transform, FT_Matrix matrices[3],
7041 DWORD buflen, BYTE *buf )
7043 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
7044 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
7045 DWORD pitch = ((width + 31) >> 5) << 2;
7046 DWORD needed = pitch * height;
7047 FT_Bitmap ft_bitmap;
7048 BYTE *src, *dst;
7049 INT w, h, x;
7051 if (!buf || !buflen) return needed;
7052 if (!needed) return GDI_ERROR; /* empty glyph */
7053 if (needed > buflen) return GDI_ERROR;
7055 switch (glyph->format)
7057 case FT_GLYPH_FORMAT_BITMAP:
7058 src = glyph->bitmap.buffer;
7059 dst = buf;
7060 w = min( pitch, (glyph->bitmap.width + 7) >> 3 );
7061 h = min( height, glyph->bitmap.rows );
7062 while (h--)
7064 if (!fake_bold)
7065 memcpy( dst, src, w );
7066 else
7068 dst[0] = 0;
7069 for (x = 0; x < w; x++)
7071 dst[x] = (dst[x] & 0x80) | (src[x] >> 1) | src[x];
7072 if (x + 1 < pitch)
7073 dst[x + 1] = (src[x] & 0x01) << 7;
7076 src += glyph->bitmap.pitch;
7077 dst += pitch;
7079 break;
7081 case FT_GLYPH_FORMAT_OUTLINE:
7082 ft_bitmap.width = width;
7083 ft_bitmap.rows = height;
7084 ft_bitmap.pitch = pitch;
7085 ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
7086 ft_bitmap.buffer = buf;
7088 if (needs_transform)
7089 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
7090 pFT_Outline_Translate( &glyph->outline, -bbox.xMin, -bbox.yMin );
7092 /* Note: FreeType will only set 'black' bits for us. */
7093 memset( buf, 0, buflen );
7094 pFT_Outline_Get_Bitmap( library, &glyph->outline, &ft_bitmap );
7095 break;
7097 default:
7098 FIXME( "loaded glyph format %x\n", glyph->format );
7099 return GDI_ERROR;
7102 return needed;
7105 static DWORD get_antialias_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox, UINT format,
7106 BOOL fake_bold, BOOL needs_transform, FT_Matrix matrices[3],
7107 DWORD buflen, BYTE *buf )
7109 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
7110 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
7111 DWORD pitch = (width + 3) / 4 * 4;
7112 DWORD needed = pitch * height;
7113 FT_Bitmap ft_bitmap;
7114 INT w, h, x, max_level;
7115 BYTE *src, *dst;
7117 if (!buf || !buflen) return needed;
7118 if (!needed) return GDI_ERROR; /* empty glyph */
7119 if (needed > buflen) return GDI_ERROR;
7121 max_level = get_max_level( format );
7123 switch (glyph->format)
7125 case FT_GLYPH_FORMAT_BITMAP:
7126 src = glyph->bitmap.buffer;
7127 dst = buf;
7128 memset( buf, 0, buflen );
7130 w = min( pitch, glyph->bitmap.width );
7131 h = min( height, glyph->bitmap.rows );
7132 while (h--)
7134 for (x = 0; x < w; x++)
7136 if (src[x / 8] & masks[x % 8])
7138 dst[x] = max_level;
7139 if (fake_bold && x + 1 < pitch) dst[x + 1] = max_level;
7142 src += glyph->bitmap.pitch;
7143 dst += pitch;
7145 break;
7147 case FT_GLYPH_FORMAT_OUTLINE:
7148 ft_bitmap.width = width;
7149 ft_bitmap.rows = height;
7150 ft_bitmap.pitch = pitch;
7151 ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
7152 ft_bitmap.buffer = buf;
7154 if (needs_transform)
7155 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
7156 pFT_Outline_Translate( &glyph->outline, -bbox.xMin, -bbox.yMin );
7158 memset( buf, 0, buflen );
7159 pFT_Outline_Get_Bitmap( library, &glyph->outline, &ft_bitmap );
7161 if (max_level != 255)
7163 INT row, col;
7164 BYTE *ptr, *start;
7166 for (row = 0, start = buf; row < height; row++)
7168 for (col = 0, ptr = start; col < width; col++, ptr++)
7169 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
7170 start += pitch;
7173 break;
7175 default:
7176 FIXME("loaded glyph format %x\n", glyph->format);
7177 return GDI_ERROR;
7180 return needed;
7183 static DWORD get_subpixel_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox, UINT format,
7184 BOOL fake_bold, BOOL needs_transform, FT_Matrix matrices[3],
7185 GLYPHMETRICS *gm, DWORD buflen, BYTE *buf )
7187 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
7188 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
7189 DWORD pitch, needed = 0;
7190 BYTE *src, *dst;
7191 INT w, h, x;
7193 switch (glyph->format)
7195 case FT_GLYPH_FORMAT_BITMAP:
7196 pitch = width * 4;
7197 needed = pitch * height;
7199 if (!buf || !buflen) break;
7200 if (!needed) return GDI_ERROR; /* empty glyph */
7201 if (needed > buflen) return GDI_ERROR;
7203 src = glyph->bitmap.buffer;
7204 dst = buf;
7205 memset( buf, 0, buflen );
7207 w = min( width, glyph->bitmap.width );
7208 h = min( height, glyph->bitmap.rows );
7209 while (h--)
7211 for (x = 0; x < w; x++)
7213 if ( src[x / 8] & masks[x % 8] )
7215 ((unsigned int *)dst)[x] = ~0u;
7216 if (fake_bold && x + 1 < width) ((unsigned int *)dst)[x + 1] = ~0u;
7219 src += glyph->bitmap.pitch;
7220 dst += pitch;
7222 break;
7224 case FT_GLYPH_FORMAT_OUTLINE:
7226 INT src_pitch, src_width, src_height, x_shift, y_shift;
7227 INT sub_stride, hmul, vmul;
7228 const INT *sub_order;
7229 const INT rgb_order[3] = { 0, 1, 2 };
7230 const INT bgr_order[3] = { 2, 1, 0 };
7231 FT_Render_Mode render_mode =
7232 (format == WINE_GGO_HRGB_BITMAP ||
7233 format == WINE_GGO_HBGR_BITMAP) ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V;
7235 if (!width || !height) /* empty glyph */
7237 if (!buf || !buflen) break;
7238 return GDI_ERROR;
7241 if ( render_mode == FT_RENDER_MODE_LCD)
7243 gm->gmBlackBoxX += 2;
7244 gm->gmptGlyphOrigin.x -= 1;
7245 bbox.xMin -= (1 << 6);
7247 else
7249 gm->gmBlackBoxY += 2;
7250 gm->gmptGlyphOrigin.y += 1;
7251 bbox.yMax += (1 << 6);
7254 width = gm->gmBlackBoxX;
7255 height = gm->gmBlackBoxY;
7256 pitch = width * 4;
7257 needed = pitch * height;
7259 if (!buf || !buflen) return needed;
7260 if (needed > buflen) return GDI_ERROR;
7262 if (needs_transform)
7263 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
7265 #ifdef FT_LCD_FILTER_H
7266 if (pFT_Library_SetLcdFilter)
7267 pFT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT );
7268 #endif
7269 pFT_Render_Glyph( glyph, render_mode );
7271 src_pitch = glyph->bitmap.pitch;
7272 src_width = glyph->bitmap.width;
7273 src_height = glyph->bitmap.rows;
7274 src = glyph->bitmap.buffer;
7275 dst = buf;
7276 memset( buf, 0, buflen );
7278 sub_order = (format == WINE_GGO_HRGB_BITMAP ||
7279 format == WINE_GGO_VRGB_BITMAP) ? rgb_order : bgr_order;
7280 sub_stride = render_mode == FT_RENDER_MODE_LCD ? 1 : src_pitch;
7281 hmul = render_mode == FT_RENDER_MODE_LCD ? 3 : 1;
7282 vmul = render_mode == FT_RENDER_MODE_LCD ? 1 : 3;
7284 x_shift = glyph->bitmap_left - (bbox.xMin >> 6);
7285 if ( x_shift < 0 )
7287 src += hmul * -x_shift;
7288 src_width -= hmul * -x_shift;
7290 else if ( x_shift > 0 )
7292 dst += x_shift * sizeof(unsigned int);
7293 width -= x_shift;
7296 y_shift = (bbox.yMax >> 6) - glyph->bitmap_top;
7297 if ( y_shift < 0 )
7299 src += src_pitch * vmul * -y_shift;
7300 src_height -= vmul * -y_shift;
7302 else if ( y_shift > 0 )
7304 dst += y_shift * pitch;
7305 height -= y_shift;
7308 w = min( width, src_width / hmul );
7309 h = min( height, src_height / vmul );
7310 while (h--)
7312 for (x = 0; x < w; x++)
7314 ((unsigned int *)dst)[x] =
7315 ((unsigned int)src[hmul * x + sub_stride * sub_order[0]] << 16) |
7316 ((unsigned int)src[hmul * x + sub_stride * sub_order[1]] << 8) |
7317 ((unsigned int)src[hmul * x + sub_stride * sub_order[2]]);
7319 src += src_pitch * vmul;
7320 dst += pitch;
7322 break;
7324 default:
7325 FIXME ( "loaded glyph format %x\n", glyph->format );
7326 return GDI_ERROR;
7329 return needed;
7332 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
7334 TTPOLYGONHEADER *pph;
7335 TTPOLYCURVE *ppc;
7336 unsigned int needed = 0, point = 0, contour, first_pt;
7337 unsigned int pph_start, cpfx;
7338 DWORD type;
7340 for (contour = 0; contour < outline->n_contours; contour++)
7342 /* Ignore contours containing one point */
7343 if (point == outline->contours[contour])
7345 point++;
7346 continue;
7349 pph_start = needed;
7350 pph = (TTPOLYGONHEADER *)(buf + needed);
7351 first_pt = point;
7352 if (buf)
7354 pph->dwType = TT_POLYGON_TYPE;
7355 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
7357 needed += sizeof(*pph);
7358 point++;
7359 while (point <= outline->contours[contour])
7361 ppc = (TTPOLYCURVE *)(buf + needed);
7362 type = outline->tags[point] & FT_Curve_Tag_On ?
7363 TT_PRIM_LINE : TT_PRIM_QSPLINE;
7364 cpfx = 0;
7367 if (buf)
7368 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
7369 cpfx++;
7370 point++;
7371 } while (point <= outline->contours[contour] &&
7372 (outline->tags[point] & FT_Curve_Tag_On) ==
7373 (outline->tags[point-1] & FT_Curve_Tag_On));
7374 /* At the end of a contour Windows adds the start point, but
7375 only for Beziers */
7376 if (point > outline->contours[contour] &&
7377 !(outline->tags[point-1] & FT_Curve_Tag_On))
7379 if (buf)
7380 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
7381 cpfx++;
7383 else if (point <= outline->contours[contour] &&
7384 outline->tags[point] & FT_Curve_Tag_On)
7386 /* add closing pt for bezier */
7387 if (buf)
7388 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
7389 cpfx++;
7390 point++;
7392 if (buf)
7394 ppc->wType = type;
7395 ppc->cpfx = cpfx;
7397 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
7399 if (buf)
7400 pph->cb = needed - pph_start;
7402 return needed;
7405 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
7407 /* Convert the quadratic Beziers to cubic Beziers.
7408 The parametric eqn for a cubic Bezier is, from PLRM:
7409 r(t) = at^3 + bt^2 + ct + r0
7410 with the control points:
7411 r1 = r0 + c/3
7412 r2 = r1 + (c + b)/3
7413 r3 = r0 + c + b + a
7415 A quadratic Bezier has the form:
7416 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
7418 So equating powers of t leads to:
7419 r1 = 2/3 p1 + 1/3 p0
7420 r2 = 2/3 p1 + 1/3 p2
7421 and of course r0 = p0, r3 = p2
7423 int contour, point = 0, first_pt;
7424 TTPOLYGONHEADER *pph;
7425 TTPOLYCURVE *ppc;
7426 DWORD pph_start, cpfx, type;
7427 FT_Vector cubic_control[4];
7428 unsigned int needed = 0;
7430 for (contour = 0; contour < outline->n_contours; contour++)
7432 pph_start = needed;
7433 pph = (TTPOLYGONHEADER *)(buf + needed);
7434 first_pt = point;
7435 if (buf)
7437 pph->dwType = TT_POLYGON_TYPE;
7438 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
7440 needed += sizeof(*pph);
7441 point++;
7442 while (point <= outline->contours[contour])
7444 ppc = (TTPOLYCURVE *)(buf + needed);
7445 type = outline->tags[point] & FT_Curve_Tag_On ?
7446 TT_PRIM_LINE : TT_PRIM_CSPLINE;
7447 cpfx = 0;
7450 if (type == TT_PRIM_LINE)
7452 if (buf)
7453 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
7454 cpfx++;
7455 point++;
7457 else
7459 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
7460 so cpfx = 3n */
7462 /* FIXME: Possible optimization in endpoint calculation
7463 if there are two consecutive curves */
7464 cubic_control[0] = outline->points[point-1];
7465 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
7467 cubic_control[0].x += outline->points[point].x + 1;
7468 cubic_control[0].y += outline->points[point].y + 1;
7469 cubic_control[0].x >>= 1;
7470 cubic_control[0].y >>= 1;
7472 if (point+1 > outline->contours[contour])
7473 cubic_control[3] = outline->points[first_pt];
7474 else
7476 cubic_control[3] = outline->points[point+1];
7477 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
7479 cubic_control[3].x += outline->points[point].x + 1;
7480 cubic_control[3].y += outline->points[point].y + 1;
7481 cubic_control[3].x >>= 1;
7482 cubic_control[3].y >>= 1;
7485 /* r1 = 1/3 p0 + 2/3 p1
7486 r2 = 1/3 p2 + 2/3 p1 */
7487 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
7488 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
7489 cubic_control[2] = cubic_control[1];
7490 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
7491 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
7492 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
7493 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
7494 if (buf)
7496 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
7497 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
7498 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
7500 cpfx += 3;
7501 point++;
7503 } while (point <= outline->contours[contour] &&
7504 (outline->tags[point] & FT_Curve_Tag_On) ==
7505 (outline->tags[point-1] & FT_Curve_Tag_On));
7506 /* At the end of a contour Windows adds the start point,
7507 but only for Beziers and we've already done that.
7509 if (point <= outline->contours[contour] &&
7510 outline->tags[point] & FT_Curve_Tag_On)
7512 /* This is the closing pt of a bezier, but we've already
7513 added it, so just inc point and carry on */
7514 point++;
7516 if (buf)
7518 ppc->wType = type;
7519 ppc->cpfx = cpfx;
7521 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
7523 if (buf)
7524 pph->cb = needed - pph_start;
7526 return needed;
7529 static FT_Int get_load_flags( UINT format )
7531 FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
7533 if (format & GGO_UNHINTED)
7534 return load_flags | FT_LOAD_NO_HINTING;
7536 switch (format & ~GGO_GLYPH_INDEX)
7538 case GGO_BITMAP:
7539 load_flags |= FT_LOAD_TARGET_MONO;
7540 break;
7541 case GGO_GRAY2_BITMAP:
7542 case GGO_GRAY4_BITMAP:
7543 case GGO_GRAY8_BITMAP:
7544 case WINE_GGO_GRAY16_BITMAP:
7545 load_flags |= FT_LOAD_TARGET_NORMAL;
7546 break;
7547 case WINE_GGO_HRGB_BITMAP:
7548 case WINE_GGO_HBGR_BITMAP:
7549 load_flags |= FT_LOAD_TARGET_LCD;
7550 break;
7551 case WINE_GGO_VRGB_BITMAP:
7552 case WINE_GGO_VBGR_BITMAP:
7553 load_flags |= FT_LOAD_TARGET_LCD_V;
7554 break;
7557 return load_flags;
7560 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
7561 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
7562 const MAT2* lpmat)
7564 GLYPHMETRICS gm;
7565 FT_Face ft_face = incoming_font->ft_face;
7566 GdiFont *font = incoming_font;
7567 FT_Glyph_Metrics metrics;
7568 FT_UInt glyph_index;
7569 DWORD needed = 0;
7570 FT_Error err;
7571 FT_BBox bbox;
7572 FT_Int load_flags = get_load_flags(format);
7573 FT_Matrix matrices[3];
7574 BOOL needsTransform = FALSE;
7575 BOOL tategaki = (font->name[0] == '@');
7576 BOOL vertical_metrics;
7578 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
7579 buflen, buf, lpmat);
7581 TRACE("font transform %f %f %f %f\n",
7582 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
7583 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
7585 if(format & GGO_GLYPH_INDEX) {
7586 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
7587 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
7588 as glyph index. "Treasure Adventure Game" depends on this. */
7589 glyph_index = pFT_Get_Char_Index(font->ft_face, glyph);
7590 TRACE("translate glyph index %04x -> %04x\n", glyph, glyph_index);
7591 } else
7592 glyph_index = glyph;
7593 format &= ~GGO_GLYPH_INDEX;
7594 /* TODO: Window also turns off tategaki for glyphs passed in by index
7595 if their unicode code points fall outside of the range that is
7596 rotated. */
7597 } else {
7598 BOOL vert;
7599 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index, &vert);
7600 ft_face = font->ft_face;
7601 if (!vert && tategaki)
7602 tategaki = check_unicode_tategaki(glyph);
7605 format &= ~GGO_UNHINTED;
7607 if (format == GGO_METRICS && is_identity_MAT2(lpmat) &&
7608 get_cached_metrics( font, glyph_index, lpgm, abc ))
7609 return 1; /* FIXME */
7611 needsTransform = get_transform_matrices( font, tategaki, lpmat, matrices );
7613 vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face));
7614 /* there is a freetype bug where vertical metrics are only
7615 properly scaled and correct in 2.4.0 or greater */
7616 if (vertical_metrics && FT_SimpleVersion < FT_VERSION_VALUE(2, 4, 0))
7617 vertical_metrics = FALSE;
7619 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
7620 if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
7622 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
7624 if(err) {
7625 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
7626 return GDI_ERROR;
7629 metrics = ft_face->glyph->metrics;
7630 if(font->fake_bold) {
7631 if (!get_bold_glyph_outline(ft_face->glyph, font->ppem, &metrics) && metrics.width)
7632 metrics.width += 1 << 6;
7635 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
7636 * by the text metrics. The proper behavior is to clip the glyph metrics to
7637 * fit within the maximums specified in the text metrics. */
7638 if(incoming_font->potm || get_outline_text_metrics(incoming_font) ||
7639 get_bitmap_text_metrics(incoming_font)) {
7640 TEXTMETRICW *ptm = &incoming_font->potm->otmTextMetrics;
7641 INT top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
7642 INT bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
7643 metrics.horiBearingY = top;
7644 metrics.height = top - bottom;
7646 /* TODO: Are we supposed to clip the width as well...? */
7647 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
7650 bbox = get_transformed_bbox( &metrics, needsTransform, matrices );
7651 compute_metrics( incoming_font, font, bbox, &metrics,
7652 tategaki, vertical_metrics, needsTransform, matrices,
7653 &gm, abc );
7655 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
7656 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
7657 set_cached_metrics( font, glyph_index, &gm, abc );
7659 if(format == GGO_METRICS)
7661 *lpgm = gm;
7662 return 1; /* FIXME */
7665 if(ft_face->glyph->format != ft_glyph_format_outline &&
7666 (format == GGO_NATIVE || format == GGO_BEZIER))
7668 TRACE("loaded a bitmap\n");
7669 return GDI_ERROR;
7672 switch (format)
7674 case GGO_BITMAP:
7675 needed = get_mono_glyph_bitmap( ft_face->glyph, bbox, font->fake_bold,
7676 needsTransform, matrices, buflen, buf );
7677 break;
7679 case GGO_GRAY2_BITMAP:
7680 case GGO_GRAY4_BITMAP:
7681 case GGO_GRAY8_BITMAP:
7682 case WINE_GGO_GRAY16_BITMAP:
7683 needed = get_antialias_glyph_bitmap( ft_face->glyph, bbox, format, font->fake_bold,
7684 needsTransform, matrices, buflen, buf );
7685 break;
7687 case WINE_GGO_HRGB_BITMAP:
7688 case WINE_GGO_HBGR_BITMAP:
7689 case WINE_GGO_VRGB_BITMAP:
7690 case WINE_GGO_VBGR_BITMAP:
7691 needed = get_subpixel_glyph_bitmap( ft_face->glyph, bbox, format, font->fake_bold,
7692 needsTransform, matrices, &gm, buflen, buf );
7693 break;
7695 case GGO_NATIVE:
7697 FT_Outline *outline = &ft_face->glyph->outline;
7699 if(buflen == 0) buf = NULL;
7701 if (needsTransform && buf)
7702 pFT_Outline_Transform( outline, &matrices[matrix_vert] );
7704 needed = get_native_glyph_outline(outline, buflen, NULL);
7706 if (!buf || !buflen)
7707 break;
7708 if (needed > buflen)
7709 return GDI_ERROR;
7711 get_native_glyph_outline(outline, buflen, buf);
7712 break;
7714 case GGO_BEZIER:
7716 FT_Outline *outline = &ft_face->glyph->outline;
7717 if(buflen == 0) buf = NULL;
7719 if (needsTransform && buf)
7720 pFT_Outline_Transform( outline, &matrices[matrix_vert] );
7722 needed = get_bezier_glyph_outline(outline, buflen, NULL);
7724 if (!buf || !buflen)
7725 break;
7726 if (needed > buflen)
7727 return GDI_ERROR;
7729 get_bezier_glyph_outline(outline, buflen, buf);
7730 break;
7733 default:
7734 FIXME("Unsupported format %d\n", format);
7735 return GDI_ERROR;
7737 if (needed != GDI_ERROR)
7738 *lpgm = gm;
7740 return needed;
7743 static BOOL get_bitmap_text_metrics(GdiFont *font)
7745 FT_Face ft_face = font->ft_face;
7746 FT_WinFNT_HeaderRec winfnt_header;
7747 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
7748 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
7749 font->potm->otmSize = size;
7751 #define TM font->potm->otmTextMetrics
7752 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
7754 TM.tmHeight = winfnt_header.pixel_height;
7755 TM.tmAscent = winfnt_header.ascent;
7756 TM.tmDescent = TM.tmHeight - TM.tmAscent;
7757 TM.tmInternalLeading = winfnt_header.internal_leading;
7758 TM.tmExternalLeading = winfnt_header.external_leading;
7759 TM.tmAveCharWidth = winfnt_header.avg_width;
7760 TM.tmMaxCharWidth = winfnt_header.max_width;
7761 TM.tmWeight = winfnt_header.weight;
7762 TM.tmOverhang = 0;
7763 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
7764 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
7765 TM.tmFirstChar = winfnt_header.first_char;
7766 TM.tmLastChar = winfnt_header.last_char;
7767 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
7768 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
7769 TM.tmItalic = winfnt_header.italic;
7770 TM.tmUnderlined = font->underline;
7771 TM.tmStruckOut = font->strikeout;
7772 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
7773 TM.tmCharSet = winfnt_header.charset;
7775 else
7777 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
7778 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
7779 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7780 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
7781 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
7782 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
7783 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
7784 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
7785 TM.tmOverhang = 0;
7786 TM.tmDigitizedAspectX = 96; /* FIXME */
7787 TM.tmDigitizedAspectY = 96; /* FIXME */
7788 TM.tmFirstChar = 1;
7789 TM.tmLastChar = 255;
7790 TM.tmDefaultChar = 32;
7791 TM.tmBreakChar = 32;
7792 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
7793 TM.tmUnderlined = font->underline;
7794 TM.tmStruckOut = font->strikeout;
7795 /* NB inverted meaning of TMPF_FIXED_PITCH */
7796 TM.tmPitchAndFamily = FT_IS_FIXED_WIDTH(ft_face) ? 0 : TMPF_FIXED_PITCH;
7797 TM.tmCharSet = font->charset;
7800 if(font->fake_bold)
7801 TM.tmWeight = FW_BOLD;
7802 #undef TM
7804 return TRUE;
7808 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
7810 double scale_x, scale_y;
7812 if (font->aveWidth)
7814 scale_x = (double)font->aveWidth;
7815 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7817 else
7818 scale_x = font->scale_y;
7820 scale_x *= fabs(font->font_desc.matrix.eM11);
7821 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7823 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7824 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7826 SCALE_Y(ptm->tmHeight);
7827 SCALE_Y(ptm->tmAscent);
7828 SCALE_Y(ptm->tmDescent);
7829 SCALE_Y(ptm->tmInternalLeading);
7830 SCALE_Y(ptm->tmExternalLeading);
7832 SCALE_X(ptm->tmOverhang);
7833 if(font->fake_bold)
7835 if(!FT_IS_SCALABLE(font->ft_face))
7836 ptm->tmOverhang++;
7837 ptm->tmAveCharWidth++;
7838 ptm->tmMaxCharWidth++;
7840 SCALE_X(ptm->tmAveCharWidth);
7841 SCALE_X(ptm->tmMaxCharWidth);
7843 #undef SCALE_X
7844 #undef SCALE_Y
7847 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
7849 double scale_x, scale_y;
7851 if (font->aveWidth)
7853 scale_x = (double)font->aveWidth;
7854 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7856 else
7857 scale_x = font->scale_y;
7859 scale_x *= fabs(font->font_desc.matrix.eM11);
7860 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7862 scale_font_metrics(font, &potm->otmTextMetrics);
7864 /* Windows scales these values as signed integers even if they are unsigned */
7865 #define SCALE_X(x) (x) = GDI_ROUND((int)(x) * (scale_x))
7866 #define SCALE_Y(y) (y) = GDI_ROUND((int)(y) * (scale_y))
7868 SCALE_Y(potm->otmAscent);
7869 SCALE_Y(potm->otmDescent);
7870 SCALE_Y(potm->otmLineGap);
7871 SCALE_Y(potm->otmsCapEmHeight);
7872 SCALE_Y(potm->otmsXHeight);
7873 SCALE_Y(potm->otmrcFontBox.top);
7874 SCALE_Y(potm->otmrcFontBox.bottom);
7875 SCALE_X(potm->otmrcFontBox.left);
7876 SCALE_X(potm->otmrcFontBox.right);
7877 SCALE_Y(potm->otmMacAscent);
7878 SCALE_Y(potm->otmMacDescent);
7879 SCALE_Y(potm->otmMacLineGap);
7880 SCALE_X(potm->otmptSubscriptSize.x);
7881 SCALE_Y(potm->otmptSubscriptSize.y);
7882 SCALE_X(potm->otmptSubscriptOffset.x);
7883 SCALE_Y(potm->otmptSubscriptOffset.y);
7884 SCALE_X(potm->otmptSuperscriptSize.x);
7885 SCALE_Y(potm->otmptSuperscriptSize.y);
7886 SCALE_X(potm->otmptSuperscriptOffset.x);
7887 SCALE_Y(potm->otmptSuperscriptOffset.y);
7888 SCALE_Y(potm->otmsStrikeoutSize);
7889 SCALE_Y(potm->otmsStrikeoutPosition);
7890 SCALE_Y(potm->otmsUnderscoreSize);
7891 SCALE_Y(potm->otmsUnderscorePosition);
7893 #undef SCALE_X
7894 #undef SCALE_Y
7897 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
7899 if(!font->potm)
7901 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
7903 /* Make sure that the font has sane width/height ratio */
7904 if (font->aveWidth)
7906 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
7908 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
7909 font->aveWidth = 0;
7913 *ptm = font->potm->otmTextMetrics;
7914 scale_font_metrics(font, ptm);
7915 return TRUE;
7918 static BOOL face_has_symbol_charmap(FT_Face ft_face)
7920 int i;
7922 for(i = 0; i < ft_face->num_charmaps; i++)
7924 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
7925 return TRUE;
7927 return FALSE;
7930 static BOOL get_outline_text_metrics(GdiFont *font)
7932 BOOL ret = FALSE;
7933 FT_Face ft_face = font->ft_face;
7934 UINT needed, lenfam, lensty, lenface, lenfull;
7935 TT_OS2 *pOS2;
7936 TT_HoriHeader *pHori;
7937 TT_Postscript *pPost;
7938 FT_Fixed em_scale;
7939 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
7940 char *cp;
7941 INT ascent, descent;
7942 USHORT windescent;
7944 TRACE("font=%p\n", font);
7946 if(!FT_IS_SCALABLE(ft_face))
7947 return FALSE;
7949 needed = sizeof(*font->potm);
7951 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
7952 family_nameW = strdupW(font->name);
7954 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
7955 if (!style_nameW)
7957 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
7958 style_nameW = towstr( CP_ACP, ft_face->style_name );
7960 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
7962 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
7963 if (!face_nameW)
7965 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
7966 face_nameW = strdupW(font->name);
7968 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
7969 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
7971 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
7972 if (!full_nameW)
7974 static const WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
7975 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
7976 full_nameW = strdupW(fake_nameW);
7978 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
7980 /* These names should be read from the TT name table */
7982 /* length of otmpFamilyName */
7983 needed += lenfam;
7985 /* length of otmpFaceName */
7986 needed += lenface;
7988 /* length of otmpStyleName */
7989 needed += lensty;
7991 /* length of otmpFullName */
7992 needed += lenfull;
7995 em_scale = (FT_Fixed)MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
7997 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
7998 if(!pOS2) {
7999 FIXME("Can't find OS/2 table - not TT font?\n");
8000 goto end;
8003 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
8004 if(!pHori) {
8005 FIXME("Can't find HHEA table - not TT font?\n");
8006 goto end;
8009 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
8011 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",
8012 pOS2->usWinAscent, pOS2->usWinDescent,
8013 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
8014 pOS2->xAvgCharWidth,
8015 ft_face->ascender, ft_face->descender, ft_face->height,
8016 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
8017 ft_face->bbox.yMax, ft_face->bbox.yMin);
8019 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
8020 font->potm->otmSize = needed;
8022 #define TM font->potm->otmTextMetrics
8024 windescent = get_fixed_windescent(pOS2->usWinDescent);
8025 if(pOS2->usWinAscent + windescent == 0) {
8026 ascent = pHori->Ascender;
8027 descent = -pHori->Descender;
8028 } else {
8029 ascent = pOS2->usWinAscent;
8030 descent = windescent;
8033 font->ntmCellHeight = ascent + descent;
8034 font->ntmAvgWidth = pOS2->xAvgCharWidth;
8036 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
8037 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
8039 if(font->yMax) {
8040 TM.tmAscent = font->yMax;
8041 TM.tmDescent = -font->yMin;
8042 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
8043 } else {
8044 TM.tmAscent = SCALE_Y(ascent);
8045 TM.tmDescent = SCALE_Y(descent);
8046 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
8049 TM.tmHeight = TM.tmAscent + TM.tmDescent;
8051 /* MSDN says:
8052 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
8054 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
8055 ((ascent + descent) -
8056 (pHori->Ascender - pHori->Descender))));
8058 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
8059 if (TM.tmAveCharWidth == 0) {
8060 TM.tmAveCharWidth = 1;
8062 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
8063 TM.tmWeight = FW_REGULAR;
8064 if (font->fake_bold)
8065 TM.tmWeight = FW_BOLD;
8066 else
8068 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
8070 if (pOS2->usWeightClass > FW_MEDIUM)
8071 TM.tmWeight = pOS2->usWeightClass;
8073 else if (pOS2->usWeightClass <= FW_MEDIUM)
8074 TM.tmWeight = pOS2->usWeightClass;
8076 TM.tmOverhang = 0;
8077 TM.tmDigitizedAspectX = 96; /* FIXME */
8078 TM.tmDigitizedAspectY = 96; /* FIXME */
8079 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
8080 * symbol range to 0 - f0ff
8083 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
8085 TM.tmFirstChar = 0;
8086 switch(GetACP())
8088 case 1255: /* Hebrew */
8089 TM.tmLastChar = 0xf896;
8090 break;
8091 case 1257: /* Baltic */
8092 TM.tmLastChar = 0xf8fd;
8093 break;
8094 default:
8095 TM.tmLastChar = 0xf0ff;
8097 TM.tmBreakChar = 0x20;
8098 TM.tmDefaultChar = 0x1f;
8100 else
8102 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
8103 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
8105 if(pOS2->usFirstCharIndex <= 1)
8106 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
8107 else if (pOS2->usFirstCharIndex > 0xff)
8108 TM.tmBreakChar = 0x20;
8109 else
8110 TM.tmBreakChar = pOS2->usFirstCharIndex;
8111 TM.tmDefaultChar = TM.tmBreakChar - 1;
8113 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
8114 TM.tmUnderlined = font->underline;
8115 TM.tmStruckOut = font->strikeout;
8117 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
8118 if(!FT_IS_FIXED_WIDTH(ft_face) &&
8119 (pOS2->version == 0xFFFFU ||
8120 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
8121 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
8122 else
8123 TM.tmPitchAndFamily = 0;
8125 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
8127 case PAN_FAMILY_SCRIPT:
8128 TM.tmPitchAndFamily |= FF_SCRIPT;
8129 break;
8131 case PAN_FAMILY_DECORATIVE:
8132 TM.tmPitchAndFamily |= FF_DECORATIVE;
8133 break;
8135 case PAN_ANY:
8136 case PAN_NO_FIT:
8137 case PAN_FAMILY_TEXT_DISPLAY:
8138 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
8139 /* which is clearly not what the panose spec says. */
8140 default:
8141 if(TM.tmPitchAndFamily == 0 || /* fixed */
8142 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
8143 TM.tmPitchAndFamily = FF_MODERN;
8144 else
8146 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
8148 case PAN_ANY:
8149 case PAN_NO_FIT:
8150 default:
8151 TM.tmPitchAndFamily |= FF_DONTCARE;
8152 break;
8154 case PAN_SERIF_COVE:
8155 case PAN_SERIF_OBTUSE_COVE:
8156 case PAN_SERIF_SQUARE_COVE:
8157 case PAN_SERIF_OBTUSE_SQUARE_COVE:
8158 case PAN_SERIF_SQUARE:
8159 case PAN_SERIF_THIN:
8160 case PAN_SERIF_BONE:
8161 case PAN_SERIF_EXAGGERATED:
8162 case PAN_SERIF_TRIANGLE:
8163 TM.tmPitchAndFamily |= FF_ROMAN;
8164 break;
8166 case PAN_SERIF_NORMAL_SANS:
8167 case PAN_SERIF_OBTUSE_SANS:
8168 case PAN_SERIF_PERP_SANS:
8169 case PAN_SERIF_FLARED:
8170 case PAN_SERIF_ROUNDED:
8171 TM.tmPitchAndFamily |= FF_SWISS;
8172 break;
8175 break;
8178 if(FT_IS_SCALABLE(ft_face))
8179 TM.tmPitchAndFamily |= TMPF_VECTOR;
8181 if(FT_IS_SFNT(ft_face))
8183 if (font->ntmFlags & NTM_PS_OPENTYPE)
8184 TM.tmPitchAndFamily |= TMPF_DEVICE;
8185 else
8186 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
8189 TM.tmCharSet = font->charset;
8191 font->potm->otmFiller = 0;
8192 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
8193 font->potm->otmfsSelection = pOS2->fsSelection;
8194 if (font->fake_italic)
8195 font->potm->otmfsSelection |= 1;
8196 if (font->fake_bold)
8197 font->potm->otmfsSelection |= 1 << 5;
8198 /* Only return valid bits that define embedding and subsetting restrictions */
8199 font->potm->otmfsType = pOS2->fsType & 0x30e;
8200 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
8201 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
8202 font->potm->otmItalicAngle = 0; /* POST table */
8203 font->potm->otmEMSquare = ft_face->units_per_EM;
8204 font->potm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
8205 font->potm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
8206 font->potm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
8207 font->potm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
8208 font->potm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
8209 font->potm->otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
8210 font->potm->otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
8211 font->potm->otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
8212 font->potm->otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
8213 font->potm->otmMacAscent = TM.tmAscent;
8214 font->potm->otmMacDescent = -TM.tmDescent;
8215 font->potm->otmMacLineGap = SCALE_Y(pHori->Line_Gap);
8216 font->potm->otmusMinimumPPEM = 0; /* TT Header */
8217 font->potm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
8218 font->potm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
8219 font->potm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
8220 font->potm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
8221 font->potm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
8222 font->potm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
8223 font->potm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
8224 font->potm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
8225 font->potm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
8226 font->potm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
8227 if(!pPost) {
8228 font->potm->otmsUnderscoreSize = 0;
8229 font->potm->otmsUnderscorePosition = 0;
8230 } else {
8231 font->potm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
8232 font->potm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
8234 #undef SCALE_X
8235 #undef SCALE_Y
8236 #undef TM
8238 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
8239 cp = (char*)font->potm + sizeof(*font->potm);
8240 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
8241 strcpyW((WCHAR*)cp, family_nameW);
8242 cp += lenfam;
8243 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
8244 strcpyW((WCHAR*)cp, style_nameW);
8245 cp += lensty;
8246 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
8247 strcpyW((WCHAR*)cp, face_nameW);
8248 cp += lenface;
8249 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
8250 strcpyW((WCHAR*)cp, full_nameW);
8251 ret = TRUE;
8253 end:
8254 HeapFree(GetProcessHeap(), 0, style_nameW);
8255 HeapFree(GetProcessHeap(), 0, family_nameW);
8256 HeapFree(GetProcessHeap(), 0, face_nameW);
8257 HeapFree(GetProcessHeap(), 0, full_nameW);
8258 return ret;
8261 /*************************************************************
8262 * freetype_GetGlyphOutline
8264 static DWORD CDECL freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
8265 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
8267 struct freetype_physdev *physdev = get_freetype_dev( dev );
8268 DWORD ret;
8269 ABC abc;
8271 if (!physdev->font)
8273 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
8274 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
8277 GDI_CheckNotLock();
8278 EnterCriticalSection( &freetype_cs );
8279 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
8280 LeaveCriticalSection( &freetype_cs );
8281 return ret;
8284 /*************************************************************
8285 * freetype_GetTextMetrics
8287 static BOOL CDECL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
8289 struct freetype_physdev *physdev = get_freetype_dev( dev );
8290 BOOL ret;
8292 if (!physdev->font)
8294 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
8295 return dev->funcs->pGetTextMetrics( dev, metrics );
8298 GDI_CheckNotLock();
8299 EnterCriticalSection( &freetype_cs );
8300 ret = get_text_metrics( physdev->font, metrics );
8301 LeaveCriticalSection( &freetype_cs );
8302 return ret;
8305 /*************************************************************
8306 * freetype_GetOutlineTextMetrics
8308 static UINT CDECL freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
8310 struct freetype_physdev *physdev = get_freetype_dev( dev );
8311 UINT ret = 0;
8313 if (!physdev->font)
8315 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
8316 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
8319 TRACE("font=%p\n", physdev->font);
8321 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
8323 GDI_CheckNotLock();
8324 EnterCriticalSection( &freetype_cs );
8326 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
8328 if(potm && cbSize >= physdev->font->potm->otmSize)
8330 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
8331 scale_outline_font_metrics(physdev->font, potm);
8333 ret = physdev->font->potm->otmSize;
8335 LeaveCriticalSection( &freetype_cs );
8336 return ret;
8339 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
8341 const struct list *face_list;
8342 Face *child_face = NULL, *best_face = NULL;
8343 UINT penalty = 0, new_penalty = 0;
8344 BOOL bold, italic, bd, it;
8346 italic = !!font->font_desc.lf.lfItalic;
8347 bold = font->font_desc.lf.lfWeight > FW_MEDIUM;
8349 face_list = get_face_list_from_family( child->face->family );
8350 LIST_FOR_EACH_ENTRY( child_face, face_list, Face, entry )
8352 it = !!(child_face->ntmFlags & NTM_ITALIC);
8353 bd = !!(child_face->ntmFlags & NTM_BOLD);
8354 new_penalty = ( it ^ italic ) + ( bd ^ bold );
8355 if (!best_face || new_penalty < penalty)
8357 penalty = new_penalty;
8358 best_face = child_face;
8361 child_face = best_face ? best_face : child->face;
8363 child->font = alloc_font();
8364 child->font->ft_face = OpenFontFace( child->font, child_face, 0, -font->ppem );
8365 if(!child->font->ft_face)
8367 free_font(child->font);
8368 child->font = NULL;
8369 return FALSE;
8372 child->font->fake_italic = italic && !( child_face->ntmFlags & NTM_ITALIC );
8373 child->font->fake_bold = bold && !( child_face->ntmFlags & NTM_BOLD );
8374 child->font->font_desc = font->font_desc;
8375 child->font->ntmFlags = child_face->ntmFlags;
8376 child->font->orientation = font->orientation;
8377 child->font->scale_y = font->scale_y;
8378 child->font->name = strdupW( child_face->family->FamilyName );
8379 child->font->base_font = font;
8380 TRACE("created child font %p for base %p\n", child->font, font);
8381 return TRUE;
8384 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL* vert)
8386 FT_UInt g,o;
8387 CHILD_FONT *child_font;
8389 if(font->base_font)
8390 font = font->base_font;
8392 *linked_font = font;
8394 if((*glyph = get_glyph_index(font, c)))
8396 o = *glyph;
8397 *glyph = get_GSUB_vert_glyph(font, *glyph);
8398 *vert = (o != *glyph);
8399 return TRUE;
8402 if (c < 32) goto done; /* don't check linked fonts for control characters */
8404 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
8406 if(!child_font->font)
8407 if(!load_child_font(font, child_font))
8408 continue;
8410 if(!child_font->font->ft_face)
8411 continue;
8412 g = get_glyph_index(child_font->font, c);
8413 o = g;
8414 g = get_GSUB_vert_glyph(child_font->font, g);
8415 if(g)
8417 *glyph = g;
8418 *linked_font = child_font->font;
8419 *vert = (o != g);
8420 return TRUE;
8424 done:
8425 *vert = FALSE;
8426 return FALSE;
8429 /*************************************************************
8430 * freetype_GetCharWidth
8432 static BOOL CDECL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
8434 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8435 UINT c;
8436 GLYPHMETRICS gm;
8437 ABC abc;
8438 struct freetype_physdev *physdev = get_freetype_dev( dev );
8440 if (!physdev->font)
8442 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
8443 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
8446 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
8448 GDI_CheckNotLock();
8449 EnterCriticalSection( &freetype_cs );
8450 for(c = firstChar; c <= lastChar; c++) {
8451 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
8452 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
8454 LeaveCriticalSection( &freetype_cs );
8455 return TRUE;
8458 /*************************************************************
8459 * freetype_GetCharWidthInfo
8461 static BOOL CDECL freetype_GetCharWidthInfo( PHYSDEV dev, void* ptr )
8463 struct freetype_physdev *physdev = get_freetype_dev( dev );
8464 struct char_width_info *info = ptr;
8465 TT_HoriHeader *pHori;
8467 if (!physdev->font)
8469 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidthInfo );
8470 return dev->funcs->pGetCharWidthInfo( dev, ptr );
8473 TRACE("%p, %p\n", physdev->font, info);
8475 if (FT_IS_SCALABLE(physdev->font->ft_face) &&
8476 (pHori = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_hhea)))
8478 FT_Fixed em_scale;
8479 em_scale = MulDiv(physdev->font->ppem, 1 << 16,
8480 physdev->font->ft_face->units_per_EM);
8481 info->lsb = (SHORT)pFT_MulFix(pHori->min_Left_Side_Bearing, em_scale);
8482 info->rsb = (SHORT)pFT_MulFix(pHori->min_Right_Side_Bearing, em_scale);
8484 else
8485 info->lsb = info->rsb = 0;
8487 info->unk = 0;
8489 return TRUE;
8492 /*************************************************************
8493 * freetype_GetCharABCWidths
8495 static BOOL CDECL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
8497 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8498 UINT c;
8499 GLYPHMETRICS gm;
8500 struct freetype_physdev *physdev = get_freetype_dev( dev );
8502 if (!physdev->font)
8504 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
8505 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
8508 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
8510 GDI_CheckNotLock();
8511 EnterCriticalSection( &freetype_cs );
8513 for(c = firstChar; c <= lastChar; c++, buffer++)
8514 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
8516 LeaveCriticalSection( &freetype_cs );
8517 return TRUE;
8520 /*************************************************************
8521 * freetype_GetCharABCWidthsI
8523 static BOOL CDECL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
8525 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8526 UINT c;
8527 GLYPHMETRICS gm;
8528 struct freetype_physdev *physdev = get_freetype_dev( dev );
8530 if (!physdev->font)
8532 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
8533 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
8536 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
8537 return FALSE;
8539 GDI_CheckNotLock();
8540 EnterCriticalSection( &freetype_cs );
8542 for(c = 0; c < count; c++, buffer++)
8543 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
8544 &gm, buffer, 0, NULL, &identity );
8546 LeaveCriticalSection( &freetype_cs );
8547 return TRUE;
8550 /*************************************************************
8551 * freetype_GetTextExtentExPoint
8553 static BOOL CDECL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
8555 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8556 INT idx, pos;
8557 ABC abc;
8558 GLYPHMETRICS gm;
8559 struct freetype_physdev *physdev = get_freetype_dev( dev );
8561 if (!physdev->font)
8563 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
8564 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
8567 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
8569 GDI_CheckNotLock();
8570 EnterCriticalSection( &freetype_cs );
8572 for (idx = pos = 0; idx < count; idx++)
8574 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
8575 pos += abc.abcA + abc.abcB + abc.abcC;
8576 dxs[idx] = pos;
8579 LeaveCriticalSection( &freetype_cs );
8580 return TRUE;
8583 /*************************************************************
8584 * freetype_GetTextExtentExPointI
8586 static BOOL CDECL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
8588 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8589 INT idx, pos;
8590 ABC abc;
8591 GLYPHMETRICS gm;
8592 struct freetype_physdev *physdev = get_freetype_dev( dev );
8594 if (!physdev->font)
8596 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
8597 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
8600 TRACE("%p, %p, %d\n", physdev->font, indices, count);
8602 GDI_CheckNotLock();
8603 EnterCriticalSection( &freetype_cs );
8605 for (idx = pos = 0; idx < count; idx++)
8607 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
8608 &gm, &abc, 0, NULL, &identity );
8609 pos += abc.abcA + abc.abcB + abc.abcC;
8610 dxs[idx] = pos;
8613 LeaveCriticalSection( &freetype_cs );
8614 return TRUE;
8617 /*************************************************************
8618 * freetype_GetFontData
8620 static DWORD CDECL freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
8622 struct freetype_physdev *physdev = get_freetype_dev( dev );
8624 if (!physdev->font)
8626 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
8627 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
8630 TRACE("font=%p, table=%s, offset=0x%x, buf=%p, cbData=0x%x\n",
8631 physdev->font, debugstr_an((char*)&table, 4), offset, buf, cbData);
8633 return get_font_data( physdev->font, table, offset, buf, cbData );
8636 /*************************************************************
8637 * freetype_GetTextFace
8639 static INT CDECL freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
8641 INT n;
8642 struct freetype_physdev *physdev = get_freetype_dev( dev );
8644 if (!physdev->font)
8646 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
8647 return dev->funcs->pGetTextFace( dev, count, str );
8650 n = strlenW(physdev->font->name) + 1;
8651 if (str)
8653 lstrcpynW(str, physdev->font->name, count);
8654 n = min(count, n);
8656 return n;
8659 /*************************************************************
8660 * freetype_GetTextCharsetInfo
8662 static UINT CDECL freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
8664 struct freetype_physdev *physdev = get_freetype_dev( dev );
8666 if (!physdev->font)
8668 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
8669 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
8671 if (fs) *fs = physdev->font->fs;
8672 return physdev->font->charset;
8675 /* Retrieve a list of supported Unicode ranges for a given font.
8676 * Can be called with NULL gs to calculate the buffer size. Returns
8677 * the number of ranges found.
8679 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
8681 DWORD num_ranges = 0;
8683 if (face->charmap->encoding == FT_ENCODING_UNICODE)
8685 FT_UInt glyph_code;
8686 FT_ULong char_code, char_code_prev;
8688 glyph_code = 0;
8689 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
8691 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
8692 face->num_glyphs, glyph_code, char_code);
8694 if (!glyph_code) return 0;
8696 if (gs)
8698 gs->ranges[0].wcLow = (USHORT)char_code;
8699 gs->ranges[0].cGlyphs = 0;
8700 gs->cGlyphsSupported = 0;
8703 num_ranges = 1;
8704 while (glyph_code)
8706 if (char_code < char_code_prev)
8708 ERR("expected increasing char code from FT_Get_Next_Char\n");
8709 return 0;
8711 if (char_code - char_code_prev > 1)
8713 num_ranges++;
8714 if (gs)
8716 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
8717 gs->ranges[num_ranges - 1].cGlyphs = 1;
8718 gs->cGlyphsSupported++;
8721 else if (gs)
8723 gs->ranges[num_ranges - 1].cGlyphs++;
8724 gs->cGlyphsSupported++;
8726 char_code_prev = char_code;
8727 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
8730 else
8732 DWORD encoding = RtlUlongByteSwap(face->charmap->encoding);
8733 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding, 4));
8736 return num_ranges;
8739 /*************************************************************
8740 * freetype_GetFontUnicodeRanges
8742 static DWORD CDECL freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
8744 struct freetype_physdev *physdev = get_freetype_dev( dev );
8745 DWORD size, num_ranges;
8747 if (!physdev->font)
8749 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
8750 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
8753 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
8754 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
8755 if (glyphset)
8757 glyphset->cbThis = size;
8758 glyphset->cRanges = num_ranges;
8759 glyphset->flAccel = 0;
8761 return size;
8764 /*************************************************************
8765 * freetype_FontIsLinked
8767 static BOOL CDECL freetype_FontIsLinked( PHYSDEV dev )
8769 struct freetype_physdev *physdev = get_freetype_dev( dev );
8770 BOOL ret;
8772 if (!physdev->font)
8774 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
8775 return dev->funcs->pFontIsLinked( dev );
8778 GDI_CheckNotLock();
8779 EnterCriticalSection( &freetype_cs );
8780 ret = !list_empty(&physdev->font->child_fonts);
8781 LeaveCriticalSection( &freetype_cs );
8782 return ret;
8785 /*************************************************************************
8786 * GetRasterizerCaps (GDI32.@)
8788 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8790 lprs->nSize = sizeof(RASTERIZER_STATUS);
8791 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
8792 lprs->nLanguageID = 0;
8793 return TRUE;
8796 /*************************************************************
8797 * freetype_GetFontRealizationInfo
8799 static BOOL CDECL freetype_GetFontRealizationInfo( PHYSDEV dev, void *ptr )
8801 struct freetype_physdev *physdev = get_freetype_dev( dev );
8802 struct font_realization_info *info = ptr;
8804 if (!physdev->font)
8806 dev = GET_NEXT_PHYSDEV( dev, pGetFontRealizationInfo );
8807 return dev->funcs->pGetFontRealizationInfo( dev, ptr );
8810 TRACE("(%p, %p)\n", physdev->font, info);
8812 info->flags = 1;
8813 if(FT_IS_SCALABLE(physdev->font->ft_face))
8814 info->flags |= 2;
8816 info->cache_num = physdev->font->cache_num;
8817 info->instance_id = physdev->font->instance_id;
8818 if (info->size == sizeof(*info))
8820 info->unk = 0;
8821 info->face_index = physdev->font->ft_face->face_index;
8822 info->simulations = 0;
8823 if (physdev->font->fake_bold)
8824 info->simulations |= 0x1;
8825 if (physdev->font->fake_italic)
8826 info->simulations |= 0x2;
8829 return TRUE;
8832 /*************************************************************************
8833 * GetFontFileData (GDI32.@)
8835 BOOL WINAPI GetFontFileData( DWORD instance_id, DWORD unknown, UINT64 offset, void *buff, DWORD buff_size )
8837 struct font_handle_entry *entry = handle_entry( instance_id );
8838 DWORD tag = 0, size;
8839 GdiFont *font;
8841 if (!entry)
8843 SetLastError(ERROR_INVALID_PARAMETER);
8844 return FALSE;
8847 font = entry->obj;
8848 if (font->ttc_item_offset)
8849 tag = MS_TTCF_TAG;
8851 size = get_font_data( font, tag, 0, NULL, 0 );
8852 if (size < buff_size || offset > size - buff_size)
8854 SetLastError(ERROR_INVALID_PARAMETER);
8855 return FALSE;
8858 /* For now this only works for SFNT case. */
8859 return get_font_data( font, tag, offset, buff, buff_size ) != 0;
8862 /*************************************************************************
8863 * GetFontFileInfo (GDI32.@)
8865 BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_fileinfo *info, SIZE_T size, SIZE_T *needed )
8867 struct font_handle_entry *entry = handle_entry( instance_id );
8868 SIZE_T required_size;
8869 const GdiFont *font;
8871 if (!entry)
8873 SetLastError(ERROR_INVALID_PARAMETER);
8874 return FALSE;
8877 if (!needed)
8878 needed = &required_size;
8880 font = entry->obj;
8881 *needed = sizeof(*info) + strlenW(font->fileinfo->path) * sizeof(WCHAR);
8882 if (*needed > size)
8884 SetLastError(ERROR_INSUFFICIENT_BUFFER);
8885 return FALSE;
8888 /* path is included too */
8889 memcpy(info, font->fileinfo, *needed);
8890 return TRUE;
8893 /*************************************************************************
8894 * Kerning support for TrueType fonts
8897 struct TT_kern_table
8899 USHORT version;
8900 USHORT nTables;
8903 struct TT_kern_subtable
8905 USHORT version;
8906 USHORT length;
8907 union
8909 USHORT word;
8910 struct
8912 USHORT horizontal : 1;
8913 USHORT minimum : 1;
8914 USHORT cross_stream: 1;
8915 USHORT override : 1;
8916 USHORT reserved1 : 4;
8917 USHORT format : 8;
8918 } bits;
8919 } coverage;
8922 struct TT_format0_kern_subtable
8924 USHORT nPairs;
8925 USHORT searchRange;
8926 USHORT entrySelector;
8927 USHORT rangeShift;
8930 struct TT_kern_pair
8932 USHORT left;
8933 USHORT right;
8934 short value;
8937 static DWORD parse_format0_kern_subtable(GdiFont *font,
8938 const struct TT_format0_kern_subtable *tt_f0_ks,
8939 const USHORT *glyph_to_char,
8940 KERNINGPAIR *kern_pair, DWORD cPairs)
8942 USHORT i, nPairs;
8943 const struct TT_kern_pair *tt_kern_pair;
8945 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
8947 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
8949 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8950 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
8951 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
8953 if (!kern_pair || !cPairs)
8954 return nPairs;
8956 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
8958 nPairs = min(nPairs, cPairs);
8960 for (i = 0; i < nPairs; i++)
8962 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
8963 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
8964 /* this algorithm appears to better match what Windows does */
8965 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
8966 if (kern_pair->iKernAmount < 0)
8968 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
8969 kern_pair->iKernAmount -= font->ppem;
8971 else if (kern_pair->iKernAmount > 0)
8973 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
8974 kern_pair->iKernAmount += font->ppem;
8976 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
8978 TRACE("left %u right %u value %d\n",
8979 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
8981 kern_pair++;
8983 TRACE("copied %u entries\n", nPairs);
8984 return nPairs;
8987 /*************************************************************
8988 * freetype_GetKerningPairs
8990 static DWORD CDECL freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
8992 DWORD length;
8993 void *buf;
8994 const struct TT_kern_table *tt_kern_table;
8995 const struct TT_kern_subtable *tt_kern_subtable;
8996 USHORT i, nTables;
8997 USHORT *glyph_to_char;
8998 GdiFont *font;
8999 struct freetype_physdev *physdev = get_freetype_dev( dev );
9001 if (!(font = physdev->font))
9003 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
9004 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
9007 GDI_CheckNotLock();
9008 EnterCriticalSection( &freetype_cs );
9009 if (font->total_kern_pairs != (DWORD)-1)
9011 if (cPairs && kern_pair)
9013 cPairs = min(cPairs, font->total_kern_pairs);
9014 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
9016 else cPairs = font->total_kern_pairs;
9018 LeaveCriticalSection( &freetype_cs );
9019 return cPairs;
9022 font->total_kern_pairs = 0;
9024 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
9026 if (length == GDI_ERROR)
9028 TRACE("no kerning data in the font\n");
9029 LeaveCriticalSection( &freetype_cs );
9030 return 0;
9033 buf = HeapAlloc(GetProcessHeap(), 0, length);
9034 if (!buf)
9036 WARN("Out of memory\n");
9037 LeaveCriticalSection( &freetype_cs );
9038 return 0;
9041 get_font_data(font, MS_KERN_TAG, 0, buf, length);
9043 /* build a glyph index to char code map */
9044 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
9045 if (!glyph_to_char)
9047 WARN("Out of memory allocating a glyph index to char code map\n");
9048 HeapFree(GetProcessHeap(), 0, buf);
9049 LeaveCriticalSection( &freetype_cs );
9050 return 0;
9053 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
9055 FT_UInt glyph_code;
9056 FT_ULong char_code;
9058 glyph_code = 0;
9059 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
9061 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
9062 font->ft_face->num_glyphs, glyph_code, char_code);
9064 while (glyph_code)
9066 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
9068 /* FIXME: This doesn't match what Windows does: it does some fancy
9069 * things with duplicate glyph index to char code mappings, while
9070 * we just avoid overriding existing entries.
9072 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
9073 glyph_to_char[glyph_code] = (USHORT)char_code;
9075 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
9078 else
9080 DWORD encoding = RtlUlongByteSwap(font->ft_face->charmap->encoding);
9081 ULONG n;
9083 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding, 4));
9084 for (n = 0; n <= 65535; n++)
9085 glyph_to_char[n] = (USHORT)n;
9088 tt_kern_table = buf;
9089 nTables = GET_BE_WORD(tt_kern_table->nTables);
9090 TRACE("version %u, nTables %u\n",
9091 GET_BE_WORD(tt_kern_table->version), nTables);
9093 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
9095 for (i = 0; i < nTables; i++)
9097 struct TT_kern_subtable tt_kern_subtable_copy;
9099 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
9100 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
9101 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
9103 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
9104 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
9105 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
9107 /* According to the TrueType specification this is the only format
9108 * that will be properly interpreted by Windows and OS/2
9110 if (tt_kern_subtable_copy.coverage.bits.format == 0)
9112 DWORD new_chunk, old_total = font->total_kern_pairs;
9114 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
9115 glyph_to_char, NULL, 0);
9116 font->total_kern_pairs += new_chunk;
9118 if (!font->kern_pairs)
9119 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
9120 font->total_kern_pairs * sizeof(*font->kern_pairs));
9121 else
9122 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
9123 font->total_kern_pairs * sizeof(*font->kern_pairs));
9125 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
9126 glyph_to_char, font->kern_pairs + old_total, new_chunk);
9128 else
9129 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
9131 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
9134 HeapFree(GetProcessHeap(), 0, glyph_to_char);
9135 HeapFree(GetProcessHeap(), 0, buf);
9137 if (cPairs && kern_pair)
9139 cPairs = min(cPairs, font->total_kern_pairs);
9140 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
9142 else cPairs = font->total_kern_pairs;
9144 LeaveCriticalSection( &freetype_cs );
9145 return cPairs;
9148 static const struct gdi_dc_funcs freetype_funcs =
9150 NULL, /* pAbortDoc */
9151 NULL, /* pAbortPath */
9152 NULL, /* pAlphaBlend */
9153 NULL, /* pAngleArc */
9154 NULL, /* pArc */
9155 NULL, /* pArcTo */
9156 NULL, /* pBeginPath */
9157 NULL, /* pBlendImage */
9158 NULL, /* pChord */
9159 NULL, /* pCloseFigure */
9160 NULL, /* pCreateCompatibleDC */
9161 freetype_CreateDC, /* pCreateDC */
9162 freetype_DeleteDC, /* pDeleteDC */
9163 NULL, /* pDeleteObject */
9164 NULL, /* pDeviceCapabilities */
9165 NULL, /* pEllipse */
9166 NULL, /* pEndDoc */
9167 NULL, /* pEndPage */
9168 NULL, /* pEndPath */
9169 freetype_EnumFonts, /* pEnumFonts */
9170 NULL, /* pEnumICMProfiles */
9171 NULL, /* pExcludeClipRect */
9172 NULL, /* pExtDeviceMode */
9173 NULL, /* pExtEscape */
9174 NULL, /* pExtFloodFill */
9175 NULL, /* pExtSelectClipRgn */
9176 NULL, /* pExtTextOut */
9177 NULL, /* pFillPath */
9178 NULL, /* pFillRgn */
9179 NULL, /* pFlattenPath */
9180 freetype_FontIsLinked, /* pFontIsLinked */
9181 NULL, /* pFrameRgn */
9182 NULL, /* pGdiComment */
9183 NULL, /* pGetBoundsRect */
9184 freetype_GetCharABCWidths, /* pGetCharABCWidths */
9185 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
9186 freetype_GetCharWidth, /* pGetCharWidth */
9187 freetype_GetCharWidthInfo, /* pGetCharWidthInfo */
9188 NULL, /* pGetDeviceCaps */
9189 NULL, /* pGetDeviceGammaRamp */
9190 freetype_GetFontData, /* pGetFontData */
9191 freetype_GetFontRealizationInfo, /* pGetFontRealizationInfo */
9192 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
9193 freetype_GetGlyphIndices, /* pGetGlyphIndices */
9194 freetype_GetGlyphOutline, /* pGetGlyphOutline */
9195 NULL, /* pGetICMProfile */
9196 NULL, /* pGetImage */
9197 freetype_GetKerningPairs, /* pGetKerningPairs */
9198 NULL, /* pGetNearestColor */
9199 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
9200 NULL, /* pGetPixel */
9201 NULL, /* pGetSystemPaletteEntries */
9202 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
9203 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
9204 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
9205 freetype_GetTextFace, /* pGetTextFace */
9206 freetype_GetTextMetrics, /* pGetTextMetrics */
9207 NULL, /* pGradientFill */
9208 NULL, /* pIntersectClipRect */
9209 NULL, /* pInvertRgn */
9210 NULL, /* pLineTo */
9211 NULL, /* pModifyWorldTransform */
9212 NULL, /* pMoveTo */
9213 NULL, /* pOffsetClipRgn */
9214 NULL, /* pOffsetViewportOrg */
9215 NULL, /* pOffsetWindowOrg */
9216 NULL, /* pPaintRgn */
9217 NULL, /* pPatBlt */
9218 NULL, /* pPie */
9219 NULL, /* pPolyBezier */
9220 NULL, /* pPolyBezierTo */
9221 NULL, /* pPolyDraw */
9222 NULL, /* pPolyPolygon */
9223 NULL, /* pPolyPolyline */
9224 NULL, /* pPolygon */
9225 NULL, /* pPolyline */
9226 NULL, /* pPolylineTo */
9227 NULL, /* pPutImage */
9228 NULL, /* pRealizeDefaultPalette */
9229 NULL, /* pRealizePalette */
9230 NULL, /* pRectangle */
9231 NULL, /* pResetDC */
9232 NULL, /* pRestoreDC */
9233 NULL, /* pRoundRect */
9234 NULL, /* pSaveDC */
9235 NULL, /* pScaleViewportExt */
9236 NULL, /* pScaleWindowExt */
9237 NULL, /* pSelectBitmap */
9238 NULL, /* pSelectBrush */
9239 NULL, /* pSelectClipPath */
9240 freetype_SelectFont, /* pSelectFont */
9241 NULL, /* pSelectPalette */
9242 NULL, /* pSelectPen */
9243 NULL, /* pSetArcDirection */
9244 NULL, /* pSetBkColor */
9245 NULL, /* pSetBkMode */
9246 NULL, /* pSetDCBrushColor */
9247 NULL, /* pSetDCPenColor */
9248 NULL, /* pSetDIBColorTable */
9249 NULL, /* pSetDIBitsToDevice */
9250 NULL, /* pSetDeviceClipping */
9251 NULL, /* pSetDeviceGammaRamp */
9252 NULL, /* pSetLayout */
9253 NULL, /* pSetMapMode */
9254 NULL, /* pSetMapperFlags */
9255 NULL, /* pSetPixel */
9256 NULL, /* pSetPolyFillMode */
9257 NULL, /* pSetROP2 */
9258 NULL, /* pSetRelAbs */
9259 NULL, /* pSetStretchBltMode */
9260 NULL, /* pSetTextAlign */
9261 NULL, /* pSetTextCharacterExtra */
9262 NULL, /* pSetTextColor */
9263 NULL, /* pSetTextJustification */
9264 NULL, /* pSetViewportExt */
9265 NULL, /* pSetViewportOrg */
9266 NULL, /* pSetWindowExt */
9267 NULL, /* pSetWindowOrg */
9268 NULL, /* pSetWorldTransform */
9269 NULL, /* pStartDoc */
9270 NULL, /* pStartPage */
9271 NULL, /* pStretchBlt */
9272 NULL, /* pStretchDIBits */
9273 NULL, /* pStrokeAndFillPath */
9274 NULL, /* pStrokePath */
9275 NULL, /* pUnrealizePalette */
9276 NULL, /* pWidenPath */
9277 NULL, /* pD3DKMTCheckVidPnExclusiveOwnership */
9278 NULL, /* pD3DKMTSetVidPnSourceOwner */
9279 NULL, /* wine_get_wgl_driver */
9280 NULL, /* wine_get_vulkan_driver */
9281 GDI_PRIORITY_FONT_DRV /* priority */
9284 #else /* HAVE_FREETYPE */
9286 struct font_fileinfo;
9288 /*************************************************************************/
9290 BOOL WineEngInit(void)
9292 return FALSE;
9295 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
9297 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
9298 return 1;
9301 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
9303 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
9304 return TRUE;
9307 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
9309 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
9310 return NULL;
9313 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
9314 LPCWSTR font_file, LPCWSTR font_path )
9316 FIXME("stub\n");
9317 return FALSE;
9320 /*************************************************************************
9321 * GetRasterizerCaps (GDI32.@)
9323 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
9325 lprs->nSize = sizeof(RASTERIZER_STATUS);
9326 lprs->wFlags = 0;
9327 lprs->nLanguageID = 0;
9328 return TRUE;
9331 /*************************************************************************
9332 * GetFontFileData (GDI32.@)
9334 BOOL WINAPI GetFontFileData( DWORD instance_id, DWORD unknown, UINT64 offset, void *buff, DWORD buff_size )
9336 return FALSE;
9339 /*************************************************************************
9340 * GetFontFileInfo (GDI32.@)
9342 BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_fileinfo *info, SIZE_T size, SIZE_T *needed)
9344 *needed = 0;
9345 return FALSE;
9348 #endif /* HAVE_FREETYPE */