msvcp120: Implement concurrent_vector::_Segment_index_of.
[wine.git] / dlls / gdi32 / freetype.c
blob346e21dc21aa84602f0211bd8be345fb7c329aa0
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
35 #include <string.h>
36 #ifdef HAVE_DIRENT_H
37 # include <dirent.h>
38 #endif
39 #include <stdio.h>
40 #include <assert.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
60 #undef LoadResource
61 #undef CompareString
62 #undef GetCurrentThread
63 #undef _CDECL
64 #undef DPRINTF
65 #undef GetCurrentProcess
66 #undef AnimatePalette
67 #undef EqualRgn
68 #undef FillRgn
69 #undef FrameRgn
70 #undef GetPixel
71 #undef InvertRgn
72 #undef LineTo
73 #undef OffsetRgn
74 #undef PaintRgn
75 #undef Polygon
76 #undef ResizePalette
77 #undef SetRectRgn
78 #endif /* HAVE_CARBON_CARBON_H */
80 #ifdef HAVE_FT2BUILD_H
81 #include <ft2build.h>
82 #include FT_FREETYPE_H
83 #include FT_GLYPH_H
84 #include FT_TYPES_H
85 #include FT_TRUETYPE_TABLES_H
86 #include FT_SFNT_NAMES_H
87 #include FT_TRUETYPE_IDS_H
88 #include FT_OUTLINE_H
89 #include FT_TRIGONOMETRY_H
90 #include FT_MODULE_H
91 #include FT_WINFONTS_H
92 #ifdef FT_LCD_FILTER_H
93 #include FT_LCD_FILTER_H
94 #endif
95 #endif /* HAVE_FT2BUILD_H */
97 #include "windef.h"
98 #include "winbase.h"
99 #include "winternl.h"
100 #include "winerror.h"
101 #include "winreg.h"
102 #include "wingdi.h"
103 #include "gdi_private.h"
104 #include "wine/library.h"
105 #include "wine/unicode.h"
106 #include "wine/debug.h"
107 #include "wine/list.h"
109 #include "resource.h"
111 WINE_DEFAULT_DEBUG_CHANNEL(font);
113 #ifdef HAVE_FREETYPE
115 #ifndef HAVE_FT_TRUETYPEENGINETYPE
116 typedef enum
118 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
119 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
120 FT_TRUETYPE_ENGINE_TYPE_PATENTED
121 } FT_TrueTypeEngineType;
122 #endif
124 static FT_Library library = 0;
125 typedef struct
127 FT_Int major;
128 FT_Int minor;
129 FT_Int patch;
130 } FT_Version_t;
131 static FT_Version_t FT_Version;
132 static DWORD FT_SimpleVersion;
134 static void *ft_handle = NULL;
136 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
137 MAKE_FUNCPTR(FT_Done_Face);
138 MAKE_FUNCPTR(FT_Get_Char_Index);
139 MAKE_FUNCPTR(FT_Get_First_Char);
140 MAKE_FUNCPTR(FT_Get_Next_Char);
141 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
142 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
143 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
144 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
145 MAKE_FUNCPTR(FT_Init_FreeType);
146 MAKE_FUNCPTR(FT_Library_Version);
147 MAKE_FUNCPTR(FT_Load_Glyph);
148 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
149 MAKE_FUNCPTR(FT_Matrix_Multiply);
150 #ifdef FT_MULFIX_INLINED
151 #define pFT_MulFix FT_MULFIX_INLINED
152 #else
153 MAKE_FUNCPTR(FT_MulFix);
154 #endif
155 MAKE_FUNCPTR(FT_New_Face);
156 MAKE_FUNCPTR(FT_New_Memory_Face);
157 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
158 MAKE_FUNCPTR(FT_Outline_Get_CBox);
159 MAKE_FUNCPTR(FT_Outline_Transform);
160 MAKE_FUNCPTR(FT_Outline_Translate);
161 MAKE_FUNCPTR(FT_Render_Glyph);
162 MAKE_FUNCPTR(FT_Set_Charmap);
163 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
164 MAKE_FUNCPTR(FT_Vector_Length);
165 MAKE_FUNCPTR(FT_Vector_Transform);
166 MAKE_FUNCPTR(FT_Vector_Unit);
167 static FT_Error (*pFT_Outline_Embolden)(FT_Outline *, FT_Pos);
168 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
169 #ifdef FT_LCD_FILTER_H
170 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
171 #endif
173 #ifdef SONAME_LIBFONTCONFIG
174 #include <fontconfig/fontconfig.h>
175 MAKE_FUNCPTR(FcConfigSubstitute);
176 MAKE_FUNCPTR(FcFontList);
177 MAKE_FUNCPTR(FcFontSetDestroy);
178 MAKE_FUNCPTR(FcInit);
179 MAKE_FUNCPTR(FcObjectSetAdd);
180 MAKE_FUNCPTR(FcObjectSetCreate);
181 MAKE_FUNCPTR(FcObjectSetDestroy);
182 MAKE_FUNCPTR(FcPatternCreate);
183 MAKE_FUNCPTR(FcPatternDestroy);
184 MAKE_FUNCPTR(FcPatternGetBool);
185 MAKE_FUNCPTR(FcPatternGetInteger);
186 MAKE_FUNCPTR(FcPatternGetString);
187 #endif
189 #undef MAKE_FUNCPTR
191 #ifndef FT_MAKE_TAG
192 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
193 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
194 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
195 #endif
197 #ifndef ft_encoding_none
198 #define FT_ENCODING_NONE ft_encoding_none
199 #endif
200 #ifndef ft_encoding_ms_symbol
201 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
202 #endif
203 #ifndef ft_encoding_unicode
204 #define FT_ENCODING_UNICODE ft_encoding_unicode
205 #endif
206 #ifndef ft_encoding_apple_roman
207 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
208 #endif
210 #ifdef WORDS_BIGENDIAN
211 #define GET_BE_WORD(x) (x)
212 #define GET_BE_DWORD(x) (x)
213 #else
214 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
215 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
216 #endif
218 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
219 ( ( (FT_ULong)_x4 << 24 ) | \
220 ( (FT_ULong)_x3 << 16 ) | \
221 ( (FT_ULong)_x2 << 8 ) | \
222 (FT_ULong)_x1 )
224 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
225 #define MS_GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
226 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
227 #define MS_TTCF_TAG MS_MAKE_TAG('t', 't', 'c', 'f')
228 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
230 /* 'gasp' flags */
231 #define GASP_GRIDFIT 0x01
232 #define GASP_DOGRAY 0x02
234 #ifndef WINE_FONT_DIR
235 #define WINE_FONT_DIR "fonts"
236 #endif
238 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
239 typedef struct {
240 FT_Short height;
241 FT_Short width;
242 FT_Pos size;
243 FT_Pos x_ppem;
244 FT_Pos y_ppem;
245 FT_Short internal_leading;
246 } Bitmap_Size;
248 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
249 So to let this compile on older versions of FreeType we'll define the
250 new structure here. */
251 typedef struct {
252 FT_Short height, width;
253 FT_Pos size, x_ppem, y_ppem;
254 } My_FT_Bitmap_Size;
256 struct enum_data
258 ENUMLOGFONTEXW elf;
259 NEWTEXTMETRICEXW ntm;
260 DWORD type;
263 typedef struct tagFace {
264 struct list entry;
265 unsigned int refcount;
266 WCHAR *StyleName;
267 WCHAR *FullName;
268 WCHAR *file;
269 dev_t dev;
270 ino_t ino;
271 void *font_data_ptr;
272 DWORD font_data_size;
273 FT_Long face_index;
274 FONTSIGNATURE fs;
275 DWORD ntmFlags;
276 FT_Fixed font_version;
277 BOOL scalable;
278 Bitmap_Size size; /* set if face is a bitmap */
279 DWORD flags; /* ADDFONT flags */
280 struct tagFamily *family;
281 /* Cached data for Enum */
282 struct enum_data *cached_enum_data;
283 } Face;
285 #define ADDFONT_EXTERNAL_FONT 0x01
286 #define ADDFONT_ALLOW_BITMAP 0x02
287 #define ADDFONT_ADD_TO_CACHE 0x04
288 #define ADDFONT_ADD_RESOURCE 0x08 /* added through AddFontResource */
289 #define ADDFONT_VERTICAL_FONT 0x10
290 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
292 typedef struct tagFamily {
293 struct list entry;
294 unsigned int refcount;
295 WCHAR *FamilyName;
296 WCHAR *EnglishName;
297 struct list faces;
298 struct list *replacement;
299 } Family;
301 typedef struct {
302 GLYPHMETRICS gm;
303 ABC abc; /* metrics of the unrotated char */
304 BOOL init;
305 } GM;
307 typedef struct {
308 FLOAT eM11, eM12;
309 FLOAT eM21, eM22;
310 } FMAT2;
312 typedef struct {
313 DWORD hash;
314 LOGFONTW lf;
315 FMAT2 matrix;
316 BOOL can_use_bitmap;
317 } FONT_DESC;
319 typedef struct tagGdiFont GdiFont;
321 #define FIRST_FONT_HANDLE 1
322 #define MAX_FONT_HANDLES 256
324 struct font_handle_entry
326 void *obj;
327 WORD generation; /* generation count for reusing handle values */
330 static struct font_handle_entry font_handles[MAX_FONT_HANDLES];
331 static struct font_handle_entry *next_free;
332 static struct font_handle_entry *next_unused = font_handles;
334 static inline DWORD entry_to_handle( struct font_handle_entry *entry )
336 unsigned int idx = entry - font_handles + FIRST_FONT_HANDLE;
337 return idx | (entry->generation << 16);
340 static inline struct font_handle_entry *handle_entry( DWORD handle )
342 unsigned int idx = LOWORD(handle) - FIRST_FONT_HANDLE;
344 if (idx < MAX_FONT_HANDLES)
346 if (!HIWORD( handle ) || HIWORD( handle ) == font_handles[idx].generation)
347 return &font_handles[idx];
349 if (handle) WARN( "invalid handle 0x%08x\n", handle );
350 return NULL;
353 static DWORD alloc_font_handle( void *obj )
355 struct font_handle_entry *entry;
357 entry = next_free;
358 if (entry)
359 next_free = entry->obj;
360 else if (next_unused < font_handles + MAX_FONT_HANDLES)
361 entry = next_unused++;
362 else
364 ERR( "out of realized font handles\n" );
365 return 0;
367 entry->obj = obj;
368 if (++entry->generation == 0xffff) entry->generation = 1;
369 return entry_to_handle( entry );
372 static void free_font_handle( DWORD handle )
374 struct font_handle_entry *entry;
376 if ((entry = handle_entry( handle )))
378 entry->obj = next_free;
379 next_free = entry;
383 typedef struct {
384 struct list entry;
385 Face *face;
386 GdiFont *font;
387 } CHILD_FONT;
389 struct font_fileinfo {
390 FILETIME writetime;
391 LARGE_INTEGER size;
392 WCHAR path[1];
395 struct tagGdiFont {
396 struct list entry;
397 struct list unused_entry;
398 unsigned int refcount;
399 GM **gm;
400 DWORD gmsize;
401 OUTLINETEXTMETRICW *potm;
402 DWORD total_kern_pairs;
403 KERNINGPAIR *kern_pairs;
404 struct list child_fonts;
406 /* the following members can be accessed without locking, they are never modified after creation */
407 FT_Face ft_face;
408 struct font_mapping *mapping;
409 LPWSTR name;
410 int charset;
411 int codepage;
412 BOOL fake_italic;
413 BOOL fake_bold;
414 BYTE underline;
415 BYTE strikeout;
416 INT orientation;
417 FONT_DESC font_desc;
418 LONG aveWidth, ppem;
419 double scale_y;
420 SHORT yMax;
421 SHORT yMin;
422 DWORD ntmFlags;
423 DWORD aa_flags;
424 UINT ntmCellHeight, ntmAvgWidth;
425 FONTSIGNATURE fs;
426 GdiFont *base_font;
427 VOID *GSUB_Table;
428 const VOID *vert_feature;
429 ULONG ttc_item_offset; /* 0 if font is not a part of TrueType collection */
430 DWORD cache_num;
431 DWORD instance_id;
432 struct font_fileinfo *fileinfo;
435 typedef struct {
436 struct list entry;
437 const WCHAR *font_name;
438 FONTSIGNATURE fs;
439 struct list links;
440 } SYSTEM_LINKS;
442 struct enum_charset_element {
443 DWORD mask;
444 DWORD charset;
445 WCHAR name[LF_FACESIZE];
448 struct enum_charset_list {
449 DWORD total;
450 struct enum_charset_element element[32];
453 #define GM_BLOCK_SIZE 128
454 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
456 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
457 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
458 static unsigned int unused_font_count;
459 #define UNUSED_CACHE_SIZE 10
460 static struct list system_links = LIST_INIT(system_links);
462 static struct list font_subst_list = LIST_INIT(font_subst_list);
464 static struct list font_list = LIST_INIT(font_list);
466 struct freetype_physdev
468 struct gdi_physdev dev;
469 GdiFont *font;
472 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
474 return (struct freetype_physdev *)dev;
477 static const struct gdi_dc_funcs freetype_funcs;
479 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
480 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
481 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
483 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
484 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
485 'W','i','n','d','o','w','s','\\',
486 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
487 'F','o','n','t','s','\0'};
489 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
490 'W','i','n','d','o','w','s',' ','N','T','\\',
491 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
492 'F','o','n','t','s','\0'};
494 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
495 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
496 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
497 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
499 static const WCHAR * const SystemFontValues[] = {
500 System_Value,
501 OEMFont_Value,
502 FixedSys_Value,
503 NULL
506 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
507 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
509 /* Interesting and well-known (frequently-assumed!) font names */
510 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
511 static const WCHAR Microsoft_Sans_Serif[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0 };
512 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
513 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
514 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
515 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
516 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
517 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
519 static const WCHAR arial[] = {'A','r','i','a','l',0};
520 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
521 static const WCHAR bitstream_vera_sans_mono[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',' ','M','o','n','o',0};
522 static const WCHAR bitstream_vera_serif[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','e','r','i','f',0};
523 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
524 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
525 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
526 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
527 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
528 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
530 static const WCHAR *default_serif_list[] =
532 times_new_roman,
533 liberation_serif,
534 bitstream_vera_serif,
535 NULL
538 static const WCHAR *default_fixed_list[] =
540 courier_new,
541 liberation_mono,
542 bitstream_vera_sans_mono,
543 NULL
546 static const WCHAR *default_sans_list[] =
548 arial,
549 liberation_sans,
550 bitstream_vera_sans,
551 NULL
554 typedef struct {
555 WCHAR *name;
556 INT charset;
557 } NameCs;
559 typedef struct tagFontSubst {
560 struct list entry;
561 NameCs from;
562 NameCs to;
563 } FontSubst;
565 /* Registry font cache key and value names */
566 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
567 'F','o','n','t','s',0};
568 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
569 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
570 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
571 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
572 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
573 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
574 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
575 static const WCHAR face_size_value[] = {'S','i','z','e',0};
576 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
577 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
578 static const WCHAR face_flags_value[] = {'F','l','a','g','s',0};
579 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
580 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
581 static const WCHAR face_file_name_value[] = {'F','i','l','e',' ','N','a','m','e','\0'};
582 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
585 struct font_mapping
587 struct list entry;
588 int refcount;
589 dev_t dev;
590 ino_t ino;
591 void *data;
592 size_t size;
595 static struct list mappings_list = LIST_INIT( mappings_list );
597 static UINT default_aa_flags;
598 static HKEY hkey_font_cache;
599 static BOOL antialias_fakes = TRUE;
601 static CRITICAL_SECTION freetype_cs;
602 static CRITICAL_SECTION_DEBUG critsect_debug =
604 0, 0, &freetype_cs,
605 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
606 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
608 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
610 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
612 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
613 static BOOL use_default_fallback = FALSE;
615 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL *vert);
616 static BOOL get_outline_text_metrics(GdiFont *font);
617 static BOOL get_bitmap_text_metrics(GdiFont *font);
618 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
619 static void remove_face_from_cache( Face *face );
621 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
622 'W','i','n','d','o','w','s',' ','N','T','\\',
623 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
624 'S','y','s','t','e','m','L','i','n','k',0};
626 /****************************************
627 * Notes on .fon files
629 * The fonts System, FixedSys and Terminal are special. There are typically multiple
630 * versions installed for different resolutions and codepages. Windows stores which one to use
631 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
632 * Key Meaning
633 * FIXEDFON.FON FixedSys
634 * FONTS.FON System
635 * OEMFONT.FON Terminal
636 * LogPixels Current dpi set by the display control panel applet
637 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
638 * also has a LogPixels value that appears to mirror this)
640 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
641 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
642 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
643 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
644 * so that makes sense.
646 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
647 * to be mapped into the registry on Windows 2000 at least).
648 * I have
649 * woafont=app850.fon
650 * ega80woa.fon=ega80850.fon
651 * ega40woa.fon=ega40850.fon
652 * cga80woa.fon=cga80850.fon
653 * cga40woa.fon=cga40850.fon
656 /* These are all structures needed for the GSUB table */
659 typedef struct {
660 DWORD version;
661 WORD ScriptList;
662 WORD FeatureList;
663 WORD LookupList;
664 } GSUB_Header;
666 typedef struct {
667 CHAR ScriptTag[4];
668 WORD Script;
669 } GSUB_ScriptRecord;
671 typedef struct {
672 WORD ScriptCount;
673 GSUB_ScriptRecord ScriptRecord[1];
674 } GSUB_ScriptList;
676 typedef struct {
677 CHAR LangSysTag[4];
678 WORD LangSys;
679 } GSUB_LangSysRecord;
681 typedef struct {
682 WORD DefaultLangSys;
683 WORD LangSysCount;
684 GSUB_LangSysRecord LangSysRecord[1];
685 } GSUB_Script;
687 typedef struct {
688 WORD LookupOrder; /* Reserved */
689 WORD ReqFeatureIndex;
690 WORD FeatureCount;
691 WORD FeatureIndex[1];
692 } GSUB_LangSys;
694 typedef struct {
695 CHAR FeatureTag[4];
696 WORD Feature;
697 } GSUB_FeatureRecord;
699 typedef struct {
700 WORD FeatureCount;
701 GSUB_FeatureRecord FeatureRecord[1];
702 } GSUB_FeatureList;
704 typedef struct {
705 WORD FeatureParams; /* Reserved */
706 WORD LookupCount;
707 WORD LookupListIndex[1];
708 } GSUB_Feature;
710 typedef struct {
711 WORD LookupCount;
712 WORD Lookup[1];
713 } GSUB_LookupList;
715 typedef struct {
716 WORD LookupType;
717 WORD LookupFlag;
718 WORD SubTableCount;
719 WORD SubTable[1];
720 } GSUB_LookupTable;
722 typedef struct {
723 WORD CoverageFormat;
724 WORD GlyphCount;
725 WORD GlyphArray[1];
726 } GSUB_CoverageFormat1;
728 typedef struct {
729 WORD Start;
730 WORD End;
731 WORD StartCoverageIndex;
732 } GSUB_RangeRecord;
734 typedef struct {
735 WORD CoverageFormat;
736 WORD RangeCount;
737 GSUB_RangeRecord RangeRecord[1];
738 } GSUB_CoverageFormat2;
740 typedef struct {
741 WORD SubstFormat; /* = 1 */
742 WORD Coverage;
743 WORD DeltaGlyphID;
744 } GSUB_SingleSubstFormat1;
746 typedef struct {
747 WORD SubstFormat; /* = 2 */
748 WORD Coverage;
749 WORD GlyphCount;
750 WORD Substitute[1];
751 }GSUB_SingleSubstFormat2;
753 #ifdef HAVE_CARBON_CARBON_H
754 static char *find_cache_dir(void)
756 FSRef ref;
757 OSErr err;
758 static char cached_path[MAX_PATH];
759 static const char *wine = "/Wine", *fonts = "/Fonts";
761 if(*cached_path) return cached_path;
763 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
764 if(err != noErr)
766 WARN("can't create cached data folder\n");
767 return NULL;
769 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
770 if(err != noErr)
772 WARN("can't create cached data path\n");
773 *cached_path = '\0';
774 return NULL;
776 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
778 ERR("Could not create full path\n");
779 *cached_path = '\0';
780 return NULL;
782 strcat(cached_path, wine);
784 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
786 WARN("Couldn't mkdir %s\n", cached_path);
787 *cached_path = '\0';
788 return NULL;
790 strcat(cached_path, fonts);
791 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
793 WARN("Couldn't mkdir %s\n", cached_path);
794 *cached_path = '\0';
795 return NULL;
797 return cached_path;
800 /******************************************************************
801 * expand_mac_font
803 * Extracts individual TrueType font files from a Mac suitcase font
804 * and saves them into the user's caches directory (see
805 * find_cache_dir()).
806 * Returns a NULL terminated array of filenames.
808 * We do this because they are apps that try to read ttf files
809 * themselves and they don't like Mac suitcase files.
811 static char **expand_mac_font(const char *path)
813 FSRef ref;
814 SInt16 res_ref;
815 OSStatus s;
816 unsigned int idx;
817 const char *out_dir;
818 const char *filename;
819 int output_len;
820 struct {
821 char **array;
822 unsigned int size, max_size;
823 } ret;
825 TRACE("path %s\n", path);
827 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
828 if(s != noErr)
830 WARN("failed to get ref\n");
831 return NULL;
834 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
835 if(s != noErr)
837 TRACE("no data fork, so trying resource fork\n");
838 res_ref = FSOpenResFile(&ref, fsRdPerm);
839 if(res_ref == -1)
841 TRACE("unable to open resource fork\n");
842 return NULL;
846 ret.size = 0;
847 ret.max_size = 10;
848 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
849 if(!ret.array)
851 CloseResFile(res_ref);
852 return NULL;
855 out_dir = find_cache_dir();
857 filename = strrchr(path, '/');
858 if(!filename) filename = path;
859 else filename++;
861 /* output filename has the form out_dir/filename_%04x.ttf */
862 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
864 UseResFile(res_ref);
865 idx = 1;
866 while(1)
868 FamRec *fam_rec;
869 unsigned short *num_faces_ptr, num_faces, face;
870 AsscEntry *assoc;
871 Handle fond;
872 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
874 fond = Get1IndResource(fond_res, idx);
875 if(!fond) break;
876 TRACE("got fond resource %d\n", idx);
877 HLock(fond);
879 fam_rec = *(FamRec**)fond;
880 num_faces_ptr = (unsigned short *)(fam_rec + 1);
881 num_faces = GET_BE_WORD(*num_faces_ptr);
882 num_faces++;
883 assoc = (AsscEntry*)(num_faces_ptr + 1);
884 TRACE("num faces %04x\n", num_faces);
885 for(face = 0; face < num_faces; face++, assoc++)
887 Handle sfnt;
888 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
889 unsigned short size, font_id;
890 char *output;
892 size = GET_BE_WORD(assoc->fontSize);
893 font_id = GET_BE_WORD(assoc->fontID);
894 if(size != 0)
896 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
897 continue;
900 TRACE("trying to load sfnt id %04x\n", font_id);
901 sfnt = GetResource(sfnt_res, font_id);
902 if(!sfnt)
904 TRACE("can't get sfnt resource %04x\n", font_id);
905 continue;
908 output = HeapAlloc(GetProcessHeap(), 0, output_len);
909 if(output)
911 int fd;
913 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
915 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
916 if(fd != -1 || errno == EEXIST)
918 if(fd != -1)
920 unsigned char *sfnt_data;
922 HLock(sfnt);
923 sfnt_data = *(unsigned char**)sfnt;
924 write(fd, sfnt_data, GetHandleSize(sfnt));
925 HUnlock(sfnt);
926 close(fd);
928 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
930 ret.max_size *= 2;
931 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
933 ret.array[ret.size++] = output;
935 else
937 WARN("unable to create %s\n", output);
938 HeapFree(GetProcessHeap(), 0, output);
941 ReleaseResource(sfnt);
943 HUnlock(fond);
944 ReleaseResource(fond);
945 idx++;
947 CloseResFile(res_ref);
949 return ret.array;
952 #endif /* HAVE_CARBON_CARBON_H */
954 static inline BOOL is_win9x(void)
956 return GetVersion() & 0x80000000;
959 This function builds an FT_Fixed from a double. It fails if the absolute
960 value of the float number is greater than 32768.
962 static inline FT_Fixed FT_FixedFromFloat(double f)
964 return f * 0x10000;
968 This function builds an FT_Fixed from a FIXED. It simply put f.value
969 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
971 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
973 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
976 static BOOL is_hinting_enabled(void)
978 static int enabled = -1;
980 if (enabled == -1)
982 /* Use the >= 2.2.0 function if available */
983 if (pFT_Get_TrueType_Engine_Type)
985 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
986 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
988 else enabled = FALSE;
989 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
991 return enabled;
994 static BOOL is_subpixel_rendering_enabled( void )
996 #ifdef FT_LCD_FILTER_H
997 static int enabled = -1;
998 if (enabled == -1)
1000 enabled = (pFT_Library_SetLcdFilter &&
1001 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature);
1002 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
1004 return enabled;
1005 #else
1006 return FALSE;
1007 #endif
1011 static const struct list *get_face_list_from_family(const Family *family)
1013 if (!list_empty(&family->faces))
1014 return &family->faces;
1015 else
1016 return family->replacement;
1019 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
1021 Family *family;
1022 Face *face;
1023 const WCHAR *file;
1025 TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
1027 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1029 const struct list *face_list;
1030 if(face_name && strcmpiW(face_name, family->FamilyName))
1031 continue;
1032 face_list = get_face_list_from_family(family);
1033 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
1035 if (!face->file)
1036 continue;
1037 file = strrchrW(face->file, '/');
1038 if(!file)
1039 file = face->file;
1040 else
1041 file++;
1042 if(strcmpiW(file, file_name)) continue;
1043 face->refcount++;
1044 return face;
1047 return NULL;
1050 static Family *find_family_from_name(const WCHAR *name)
1052 Family *family;
1054 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1056 if(!strcmpiW(family->FamilyName, name))
1057 return family;
1060 return NULL;
1063 static Family *find_family_from_any_name(const WCHAR *name)
1065 Family *family;
1067 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1069 if(!strcmpiW(family->FamilyName, name))
1070 return family;
1071 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
1072 return family;
1075 return NULL;
1078 static void DumpSubstList(void)
1080 FontSubst *psub;
1082 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
1084 if(psub->from.charset != -1 || psub->to.charset != -1)
1085 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
1086 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
1087 else
1088 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
1089 debugstr_w(psub->to.name));
1093 static LPWSTR strdupW(LPCWSTR p)
1095 LPWSTR ret;
1096 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
1097 ret = HeapAlloc(GetProcessHeap(), 0, len);
1098 memcpy(ret, p, len);
1099 return ret;
1102 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1103 INT from_charset)
1105 FontSubst *element;
1107 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1109 if(!strcmpiW(element->from.name, from_name) &&
1110 (element->from.charset == from_charset ||
1111 element->from.charset == -1))
1112 return element;
1115 return NULL;
1118 #define ADD_FONT_SUBST_FORCE 1
1120 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1122 FontSubst *from_exist, *to_exist;
1124 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1126 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1128 list_remove(&from_exist->entry);
1129 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
1130 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
1131 HeapFree(GetProcessHeap(), 0, from_exist);
1132 from_exist = NULL;
1135 if(!from_exist)
1137 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1139 if(to_exist)
1141 HeapFree(GetProcessHeap(), 0, subst->to.name);
1142 subst->to.name = strdupW(to_exist->to.name);
1145 list_add_tail(subst_list, &subst->entry);
1147 return TRUE;
1150 HeapFree(GetProcessHeap(), 0, subst->from.name);
1151 HeapFree(GetProcessHeap(), 0, subst->to.name);
1152 HeapFree(GetProcessHeap(), 0, subst);
1153 return FALSE;
1156 static WCHAR *towstr(UINT cp, const char *str)
1158 int len;
1159 WCHAR *wstr;
1161 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1162 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1163 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1164 return wstr;
1167 static char *strWtoA(UINT cp, const WCHAR *str)
1169 int len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL );
1170 char *ret = HeapAlloc( GetProcessHeap(), 0, len );
1171 WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL );
1172 return ret;
1175 static void split_subst_info(NameCs *nc, LPSTR str)
1177 CHAR *p = strrchr(str, ',');
1179 nc->charset = -1;
1180 if(p && *(p+1)) {
1181 nc->charset = strtol(p+1, NULL, 10);
1182 *p = '\0';
1184 nc->name = towstr(CP_ACP, str);
1187 static void LoadSubstList(void)
1189 FontSubst *psub;
1190 HKEY hkey;
1191 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1192 LPSTR value;
1193 LPVOID data;
1195 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1196 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1197 &hkey) == ERROR_SUCCESS) {
1199 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1200 &valuelen, &datalen, NULL, NULL);
1202 valuelen++; /* returned value doesn't include room for '\0' */
1203 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1204 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1206 dlen = datalen;
1207 vlen = valuelen;
1208 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1209 &dlen) == ERROR_SUCCESS) {
1210 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1212 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1213 split_subst_info(&psub->from, value);
1214 split_subst_info(&psub->to, data);
1216 /* Win 2000 doesn't allow mapping between different charsets
1217 or mapping of DEFAULT_CHARSET */
1218 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1219 psub->to.charset == DEFAULT_CHARSET) {
1220 HeapFree(GetProcessHeap(), 0, psub->to.name);
1221 HeapFree(GetProcessHeap(), 0, psub->from.name);
1222 HeapFree(GetProcessHeap(), 0, psub);
1223 } else {
1224 add_font_subst(&font_subst_list, psub, 0);
1226 /* reset dlen and vlen */
1227 dlen = datalen;
1228 vlen = valuelen;
1230 HeapFree(GetProcessHeap(), 0, data);
1231 HeapFree(GetProcessHeap(), 0, value);
1232 RegCloseKey(hkey);
1237 static const LANGID mac_langid_table[] =
1239 MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */
1240 MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */
1241 MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */
1242 MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */
1243 MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */
1244 MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */
1245 MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */
1246 MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */
1247 MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */
1248 MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */
1249 MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */
1250 MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */
1251 MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */
1252 MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */
1253 MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */
1254 MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */
1255 MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */
1256 MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */
1257 MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */
1258 MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
1259 MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */
1260 MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */
1261 MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */
1262 MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */
1263 MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */
1264 MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */
1265 MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */
1266 MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */
1267 MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */
1268 MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */
1269 MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */
1270 MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */
1271 MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */
1272 MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
1273 MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */
1274 MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */
1275 MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */
1276 MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */
1277 MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */
1278 MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */
1279 MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */
1280 0, /* TT_MAC_LANGID_YIDDISH */
1281 MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */
1282 MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */
1283 MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */
1284 MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */
1285 MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */
1286 MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */
1287 MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */
1288 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */
1289 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
1290 MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */
1291 MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */
1292 0, /* TT_MAC_LANGID_MOLDAVIAN */
1293 MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */
1294 MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */
1295 MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */
1296 MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */
1297 MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
1298 MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */
1299 0, /* TT_MAC_LANGID_KURDISH */
1300 MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */
1301 MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */
1302 MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */
1303 MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */
1304 MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */
1305 MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */
1306 MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */
1307 MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */
1308 MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */
1309 MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */
1310 MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */
1311 MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */
1312 MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */
1313 MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */
1314 MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */
1315 MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */
1316 0, /* TT_MAC_LANGID_BURMESE */
1317 MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */
1318 MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */
1319 MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */
1320 MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */
1321 0, /* TT_MAC_LANGID_TAGALOG */
1322 MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
1323 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
1324 MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */
1325 MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */
1326 0, /* TT_MAC_LANGID_GALLA */
1327 0, /* TT_MAC_LANGID_SOMALI */
1328 MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */
1329 0, /* TT_MAC_LANGID_RUANDA */
1330 0, /* TT_MAC_LANGID_RUNDI */
1331 0, /* TT_MAC_LANGID_CHEWA */
1332 MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */
1333 MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */
1334 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
1335 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
1336 MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */
1337 MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */
1338 MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */
1339 0, /* TT_MAC_LANGID_LATIN */
1340 MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */
1341 0, /* TT_MAC_LANGID_GUARANI */
1342 0, /* TT_MAC_LANGID_AYMARA */
1343 MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */
1344 MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */
1345 0, /* TT_MAC_LANGID_DZONGKHA */
1346 0, /* TT_MAC_LANGID_JAVANESE */
1347 0, /* TT_MAC_LANGID_SUNDANESE */
1348 MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */
1349 MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */
1350 MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */
1351 MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */
1352 MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
1353 MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */
1354 MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */
1355 0, /* TT_MAC_LANGID_TONGAN */
1356 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
1357 MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */
1358 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
1361 static inline WORD get_mac_code_page( const FT_SfntName *name )
1363 if (name->encoding_id == TT_MAC_ID_SIMPLIFIED_CHINESE) return 10008; /* special case */
1364 return 10000 + name->encoding_id;
1367 static int match_name_table_language( const FT_SfntName *name, LANGID lang )
1369 LANGID name_lang;
1370 int res = 0;
1372 switch (name->platform_id)
1374 case TT_PLATFORM_MICROSOFT:
1375 res += 5; /* prefer the Microsoft name */
1376 switch (name->encoding_id)
1378 case TT_MS_ID_UNICODE_CS:
1379 case TT_MS_ID_SYMBOL_CS:
1380 name_lang = name->language_id;
1381 break;
1382 default:
1383 return 0;
1385 break;
1386 case TT_PLATFORM_MACINTOSH:
1387 if (!IsValidCodePage( get_mac_code_page( name ))) return 0;
1388 if (name->language_id >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
1389 name_lang = mac_langid_table[name->language_id];
1390 break;
1391 case TT_PLATFORM_APPLE_UNICODE:
1392 res += 2; /* prefer Unicode encodings */
1393 switch (name->encoding_id)
1395 case TT_APPLE_ID_DEFAULT:
1396 case TT_APPLE_ID_ISO_10646:
1397 case TT_APPLE_ID_UNICODE_2_0:
1398 if (name->language_id >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
1399 name_lang = mac_langid_table[name->language_id];
1400 break;
1401 default:
1402 return 0;
1404 break;
1405 default:
1406 return 0;
1408 if (name_lang == lang) res += 30;
1409 else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20;
1410 else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10;
1411 return res;
1414 static WCHAR *copy_name_table_string( const FT_SfntName *name )
1416 WCHAR *ret;
1417 WORD codepage;
1418 int i;
1420 switch (name->platform_id)
1422 case TT_PLATFORM_APPLE_UNICODE:
1423 case TT_PLATFORM_MICROSOFT:
1424 ret = HeapAlloc( GetProcessHeap(), 0, name->string_len + sizeof(WCHAR) );
1425 for (i = 0; i < name->string_len / 2; i++)
1426 ret[i] = (name->string[i * 2] << 8) | name->string[i * 2 + 1];
1427 ret[i] = 0;
1428 return ret;
1429 case TT_PLATFORM_MACINTOSH:
1430 codepage = get_mac_code_page( name );
1431 i = MultiByteToWideChar( codepage, 0, (char *)name->string, name->string_len, NULL, 0 );
1432 ret = HeapAlloc( GetProcessHeap(), 0, (i + 1) * sizeof(WCHAR) );
1433 MultiByteToWideChar( codepage, 0, (char *)name->string, name->string_len, ret, i );
1434 ret[i] = 0;
1435 return ret;
1437 return NULL;
1440 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, LANGID language_id)
1442 FT_SfntName name;
1443 FT_UInt num_names, name_index;
1444 int res, best_lang = 0, best_index = -1;
1446 if (!FT_IS_SFNT(ft_face)) return NULL;
1448 num_names = pFT_Get_Sfnt_Name_Count( ft_face );
1450 for (name_index = 0; name_index < num_names; name_index++)
1452 if (pFT_Get_Sfnt_Name( ft_face, name_index, &name )) continue;
1453 if (name.name_id != name_id) continue;
1454 res = match_name_table_language( &name, language_id );
1455 if (res > best_lang)
1457 best_lang = res;
1458 best_index = name_index;
1462 if (best_index != -1 && !pFT_Get_Sfnt_Name( ft_face, best_index, &name ))
1464 WCHAR *ret = copy_name_table_string( &name );
1465 TRACE( "name %u found platform %u lang %04x %s\n",
1466 name_id, name.platform_id, name.language_id, debugstr_w( ret ));
1467 return ret;
1469 return NULL;
1472 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1474 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1475 if (f1->scalable) return TRUE;
1476 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1477 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1480 static void release_family( Family *family )
1482 if (--family->refcount) return;
1483 assert( list_empty( &family->faces ));
1484 list_remove( &family->entry );
1485 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1486 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1487 HeapFree( GetProcessHeap(), 0, family );
1490 static void release_face( Face *face )
1492 if (--face->refcount) return;
1493 if (face->family)
1495 if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
1496 list_remove( &face->entry );
1497 release_family( face->family );
1499 HeapFree( GetProcessHeap(), 0, face->file );
1500 HeapFree( GetProcessHeap(), 0, face->StyleName );
1501 HeapFree( GetProcessHeap(), 0, face->FullName );
1502 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1503 HeapFree( GetProcessHeap(), 0, face );
1506 static inline int style_order(const Face *face)
1508 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1510 case NTM_REGULAR:
1511 return 0;
1512 case NTM_BOLD:
1513 return 1;
1514 case NTM_ITALIC:
1515 return 2;
1516 case NTM_BOLD | NTM_ITALIC:
1517 return 3;
1518 default:
1519 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1520 debugstr_w(face->family->FamilyName),
1521 debugstr_w(face->StyleName),
1522 face->ntmFlags);
1523 return 9999;
1527 static BOOL insert_face_in_family_list( Face *face, Family *family )
1529 Face *cursor;
1531 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1533 if (faces_equal( face, cursor ))
1535 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1536 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1537 cursor->font_version, face->font_version);
1539 if (face->file && face->dev == cursor->dev && face->ino == cursor->ino)
1541 cursor->refcount++;
1542 TRACE("Font %s already in list, refcount now %d\n",
1543 debugstr_w(face->file), cursor->refcount);
1544 return FALSE;
1546 if (face->font_version <= cursor->font_version)
1548 TRACE("Original font %s is newer so skipping %s\n",
1549 debugstr_w(cursor->file), debugstr_w(face->file));
1550 return FALSE;
1552 else
1554 TRACE("Replacing original %s with %s\n",
1555 debugstr_w(cursor->file), debugstr_w(face->file));
1556 list_add_before( &cursor->entry, &face->entry );
1557 face->family = family;
1558 family->refcount++;
1559 face->refcount++;
1560 release_face( cursor );
1561 return TRUE;
1564 else
1565 TRACE("Adding new %s\n", debugstr_w(face->file));
1567 if (style_order( face ) < style_order( cursor )) break;
1570 list_add_before( &cursor->entry, &face->entry );
1571 face->family = family;
1572 family->refcount++;
1573 face->refcount++;
1574 return TRUE;
1577 /****************************************************************
1578 * NB This function stores the ptrs to the strings to save copying.
1579 * Don't free them after calling.
1581 static Family *create_family( WCHAR *name, WCHAR *english_name )
1583 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1584 family->refcount = 1;
1585 family->FamilyName = name;
1586 family->EnglishName = english_name;
1587 list_init( &family->faces );
1588 family->replacement = &family->faces;
1589 list_add_tail( &font_list, &family->entry );
1591 return family;
1594 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1596 DWORD type, size = sizeof(DWORD);
1598 if (RegQueryValueExW(hkey, value, NULL, &type, (BYTE *)data, &size) ||
1599 type != REG_DWORD || size != sizeof(DWORD))
1601 *data = 0;
1602 return ERROR_BAD_CONFIGURATION;
1604 return ERROR_SUCCESS;
1607 static inline LONG reg_load_ftlong(HKEY hkey, const WCHAR *value, FT_Long *data)
1609 DWORD dw;
1610 LONG ret = reg_load_dword(hkey, value, &dw);
1611 *data = dw;
1612 return ret;
1615 static inline LONG reg_load_ftshort(HKEY hkey, const WCHAR *value, FT_Short *data)
1617 DWORD dw;
1618 LONG ret = reg_load_dword(hkey, value, &dw);
1619 *data = dw;
1620 return ret;
1623 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1625 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1628 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1630 DWORD needed, strike_index = 0;
1631 HKEY hkey_strike;
1633 /* If we have a File Name key then this is a real font, not just the parent
1634 key of a bunch of non-scalable strikes */
1635 needed = buffer_size;
1636 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1638 Face *face;
1639 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1640 face->cached_enum_data = NULL;
1641 face->family = NULL;
1643 face->refcount = 1;
1644 face->file = strdupW( buffer );
1645 face->StyleName = strdupW(face_name);
1647 needed = buffer_size;
1648 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1649 face->FullName = strdupW( buffer );
1650 else
1651 face->FullName = NULL;
1653 reg_load_ftlong(hkey_face, face_index_value, &face->face_index);
1654 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1655 reg_load_ftlong(hkey_face, face_version_value, &face->font_version);
1656 reg_load_dword(hkey_face, face_flags_value, &face->flags);
1658 needed = sizeof(face->fs);
1659 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1661 if(reg_load_ftshort(hkey_face, face_height_value, &face->size.height) != ERROR_SUCCESS)
1663 face->scalable = TRUE;
1664 memset(&face->size, 0, sizeof(face->size));
1666 else
1668 face->scalable = FALSE;
1669 reg_load_ftshort(hkey_face, face_width_value, &face->size.width);
1670 reg_load_ftlong(hkey_face, face_size_value, &face->size.size);
1671 reg_load_ftlong(hkey_face, face_x_ppem_value, &face->size.x_ppem);
1672 reg_load_ftlong(hkey_face, face_y_ppem_value, &face->size.y_ppem);
1673 reg_load_ftshort(hkey_face, face_internal_leading_value, &face->size.internal_leading);
1675 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1676 face->size.height, face->size.width, face->size.size >> 6,
1677 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1680 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1681 face->fs.fsCsb[0], face->fs.fsCsb[1],
1682 face->fs.fsUsb[0], face->fs.fsUsb[1],
1683 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1685 if (insert_face_in_family_list(face, family))
1686 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1688 release_face( face );
1691 /* load bitmap strikes */
1693 needed = buffer_size;
1694 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1696 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1698 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1699 RegCloseKey(hkey_strike);
1701 needed = buffer_size;
1705 /* move vertical fonts after their horizontal counterpart */
1706 /* assumes that font_list is already sorted by family name */
1707 static void reorder_vertical_fonts(void)
1709 Family *family, *next, *vert_family;
1710 struct list *ptr, *vptr;
1711 struct list vertical_families = LIST_INIT( vertical_families );
1713 LIST_FOR_EACH_ENTRY_SAFE( family, next, &font_list, Family, entry )
1715 if (family->FamilyName[0] != '@') continue;
1716 list_remove( &family->entry );
1717 list_add_tail( &vertical_families, &family->entry );
1720 ptr = list_head( &font_list );
1721 vptr = list_head( &vertical_families );
1722 while (ptr && vptr)
1724 family = LIST_ENTRY( ptr, Family, entry );
1725 vert_family = LIST_ENTRY( vptr, Family, entry );
1726 if (strcmpiW( family->FamilyName, vert_family->FamilyName + 1 ) > 0)
1728 list_remove( vptr );
1729 list_add_before( ptr, vptr );
1730 vptr = list_head( &vertical_families );
1732 else ptr = list_next( &font_list, ptr );
1734 list_move_tail( &font_list, &vertical_families );
1737 static void load_font_list_from_cache(HKEY hkey_font_cache)
1739 DWORD size, family_index = 0;
1740 Family *family;
1741 HKEY hkey_family;
1742 WCHAR buffer[4096];
1744 size = sizeof(buffer);
1745 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1747 WCHAR *english_family = NULL;
1748 WCHAR *family_name = strdupW( buffer );
1749 DWORD face_index = 0;
1751 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1752 TRACE("opened family key %s\n", debugstr_w(family_name));
1753 size = sizeof(buffer);
1754 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1755 english_family = strdupW( buffer );
1757 family = create_family(family_name, english_family);
1759 if(english_family)
1761 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1762 subst->from.name = strdupW(english_family);
1763 subst->from.charset = -1;
1764 subst->to.name = strdupW(family_name);
1765 subst->to.charset = -1;
1766 add_font_subst(&font_subst_list, subst, 0);
1769 size = sizeof(buffer);
1770 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1772 WCHAR *face_name = strdupW( buffer );
1773 HKEY hkey_face;
1775 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1777 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1778 RegCloseKey(hkey_face);
1780 HeapFree( GetProcessHeap(), 0, face_name );
1781 size = sizeof(buffer);
1783 RegCloseKey(hkey_family);
1784 release_family( family );
1785 size = sizeof(buffer);
1788 reorder_vertical_fonts();
1791 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1793 LONG ret;
1794 HKEY hkey_wine_fonts;
1796 /* We don't want to create the fonts key as volatile, so open this first */
1797 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1798 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1799 if(ret != ERROR_SUCCESS)
1801 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1802 return ret;
1805 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1806 KEY_ALL_ACCESS, NULL, hkey, disposition);
1807 RegCloseKey(hkey_wine_fonts);
1808 return ret;
1811 static void add_face_to_cache(Face *face)
1813 HKEY hkey_family, hkey_face;
1814 WCHAR *face_key_name;
1816 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1817 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1818 if(face->family->EnglishName)
1819 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1820 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1822 if(face->scalable)
1823 face_key_name = face->StyleName;
1824 else
1826 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1827 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1828 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1830 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1831 &hkey_face, NULL);
1832 if(!face->scalable)
1833 HeapFree(GetProcessHeap(), 0, face_key_name);
1835 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1836 (strlenW(face->file) + 1) * sizeof(WCHAR));
1837 if (face->FullName)
1838 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1839 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1841 reg_save_dword(hkey_face, face_index_value, face->face_index);
1842 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1843 reg_save_dword(hkey_face, face_version_value, face->font_version);
1844 if (face->flags) reg_save_dword(hkey_face, face_flags_value, face->flags);
1846 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1848 if(!face->scalable)
1850 reg_save_dword(hkey_face, face_height_value, face->size.height);
1851 reg_save_dword(hkey_face, face_width_value, face->size.width);
1852 reg_save_dword(hkey_face, face_size_value, face->size.size);
1853 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1854 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1855 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1857 RegCloseKey(hkey_face);
1858 RegCloseKey(hkey_family);
1861 static void remove_face_from_cache( Face *face )
1863 HKEY hkey_family;
1865 RegOpenKeyExW( hkey_font_cache, face->family->FamilyName, 0, KEY_ALL_ACCESS, &hkey_family );
1867 if (face->scalable)
1869 RegDeleteKeyW( hkey_family, face->StyleName );
1871 else
1873 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1874 WCHAR *face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1875 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1876 RegDeleteKeyW( hkey_family, face_key_name );
1877 HeapFree(GetProcessHeap(), 0, face_key_name);
1879 RegCloseKey(hkey_family);
1882 static WCHAR *prepend_at(WCHAR *family)
1884 WCHAR *str;
1886 if (!family)
1887 return NULL;
1889 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1890 str[0] = '@';
1891 strcpyW(str + 1, family);
1892 HeapFree(GetProcessHeap(), 0, family);
1893 return str;
1896 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1898 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT) );
1899 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1901 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1902 if (!*name)
1904 *name = *english;
1905 *english = NULL;
1907 else if (!strcmpiW( *name, *english ))
1909 HeapFree( GetProcessHeap(), 0, *english );
1910 *english = NULL;
1913 if (vertical)
1915 *name = prepend_at( *name );
1916 *english = prepend_at( *english );
1920 static Family *get_family( FT_Face ft_face, BOOL vertical )
1922 Family *family;
1923 WCHAR *name, *english_name;
1925 get_family_names( ft_face, &name, &english_name, vertical );
1927 family = find_family_from_name( name );
1929 if (!family)
1931 family = create_family( name, english_name );
1932 if (english_name)
1934 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1935 subst->from.name = strdupW( english_name );
1936 subst->from.charset = -1;
1937 subst->to.name = strdupW( name );
1938 subst->to.charset = -1;
1939 add_font_subst( &font_subst_list, subst, 0 );
1942 else
1944 HeapFree( GetProcessHeap(), 0, name );
1945 HeapFree( GetProcessHeap(), 0, english_name );
1946 family->refcount++;
1949 return family;
1952 static inline FT_Fixed get_font_version( FT_Face ft_face )
1954 FT_Fixed version = 0;
1955 TT_Header *header;
1957 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1958 if (header) version = header->Font_Revision;
1960 return version;
1963 static inline DWORD get_ntm_flags( FT_Face ft_face )
1965 DWORD flags = 0;
1966 FT_ULong table_size = 0;
1967 FT_WinFNT_HeaderRec winfnt_header;
1969 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1970 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1972 /* fixup the flag for our fake-bold implementation. */
1973 if (!FT_IS_SCALABLE( ft_face ) &&
1974 !pFT_Get_WinFNT_Header( ft_face, &winfnt_header ) &&
1975 winfnt_header.weight > FW_NORMAL )
1976 flags |= NTM_BOLD;
1978 if (flags == 0) flags = NTM_REGULAR;
1980 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1981 flags |= NTM_PS_OPENTYPE;
1983 return flags;
1986 static inline void get_bitmap_size( FT_Face ft_face, Bitmap_Size *face_size )
1988 My_FT_Bitmap_Size *size;
1989 FT_WinFNT_HeaderRec winfnt_header;
1991 size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1992 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1993 size->height, size->width, size->size >> 6,
1994 size->x_ppem >> 6, size->y_ppem >> 6);
1995 face_size->height = size->height;
1996 face_size->width = size->width;
1997 face_size->size = size->size;
1998 face_size->x_ppem = size->x_ppem;
1999 face_size->y_ppem = size->y_ppem;
2001 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header )) {
2002 face_size->internal_leading = winfnt_header.internal_leading;
2003 if (winfnt_header.external_leading > 0 &&
2004 (face_size->height ==
2005 winfnt_header.pixel_height + winfnt_header.external_leading))
2006 face_size->height = winfnt_header.pixel_height;
2010 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
2012 TT_OS2 *os2;
2013 FT_UInt dummy;
2014 CHARSETINFO csi;
2015 FT_WinFNT_HeaderRec winfnt_header;
2016 int i;
2018 memset( fs, 0, sizeof(*fs) );
2020 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
2021 if (os2)
2023 fs->fsUsb[0] = os2->ulUnicodeRange1;
2024 fs->fsUsb[1] = os2->ulUnicodeRange2;
2025 fs->fsUsb[2] = os2->ulUnicodeRange3;
2026 fs->fsUsb[3] = os2->ulUnicodeRange4;
2028 if (os2->version == 0)
2030 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
2031 fs->fsCsb[0] = FS_LATIN1;
2032 else
2033 fs->fsCsb[0] = FS_SYMBOL;
2035 else
2037 fs->fsCsb[0] = os2->ulCodePageRange1;
2038 fs->fsCsb[1] = os2->ulCodePageRange2;
2041 else
2043 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
2045 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
2046 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
2047 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
2048 *fs = csi.fs;
2052 if (fs->fsCsb[0] == 0)
2054 /* let's see if we can find any interesting cmaps */
2055 for (i = 0; i < ft_face->num_charmaps; i++)
2057 switch (ft_face->charmaps[i]->encoding)
2059 case FT_ENCODING_UNICODE:
2060 case FT_ENCODING_APPLE_ROMAN:
2061 fs->fsCsb[0] |= FS_LATIN1;
2062 break;
2063 case FT_ENCODING_MS_SYMBOL:
2064 fs->fsCsb[0] |= FS_SYMBOL;
2065 break;
2066 default:
2067 break;
2073 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
2074 DWORD flags )
2076 struct stat st;
2077 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
2079 face->refcount = 1;
2080 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
2081 if (!face->StyleName) face->StyleName = towstr( CP_ACP, ft_face->style_name );
2083 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
2084 if (flags & ADDFONT_VERTICAL_FONT)
2085 face->FullName = prepend_at( face->FullName );
2087 face->dev = 0;
2088 face->ino = 0;
2089 if (file)
2091 face->file = towstr( CP_UNIXCP, file );
2092 face->font_data_ptr = NULL;
2093 face->font_data_size = 0;
2094 if (!stat( file, &st ))
2096 face->dev = st.st_dev;
2097 face->ino = st.st_ino;
2100 else
2102 face->file = NULL;
2103 face->font_data_ptr = font_data_ptr;
2104 face->font_data_size = font_data_size;
2107 face->face_index = face_index;
2108 get_fontsig( ft_face, &face->fs );
2109 face->ntmFlags = get_ntm_flags( ft_face );
2110 face->font_version = get_font_version( ft_face );
2112 if (FT_IS_SCALABLE( ft_face ))
2114 memset( &face->size, 0, sizeof(face->size) );
2115 face->scalable = TRUE;
2117 else
2119 get_bitmap_size( ft_face, &face->size );
2120 face->scalable = FALSE;
2123 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
2124 face->flags = flags;
2125 face->family = NULL;
2126 face->cached_enum_data = NULL;
2128 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
2129 face->fs.fsCsb[0], face->fs.fsCsb[1],
2130 face->fs.fsUsb[0], face->fs.fsUsb[1],
2131 face->fs.fsUsb[2], face->fs.fsUsb[3]);
2133 return face;
2136 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
2137 FT_Long face_index, DWORD flags )
2139 Face *face;
2140 Family *family;
2142 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags );
2143 family = get_family( ft_face, flags & ADDFONT_VERTICAL_FONT );
2144 if (strlenW(family->FamilyName) >= LF_FACESIZE)
2146 WARN("Ignoring %s because name is too long\n", debugstr_w(family->FamilyName));
2147 release_face( face );
2148 release_family( family );
2149 return;
2152 if (insert_face_in_family_list( face, family ))
2154 if (flags & ADDFONT_ADD_TO_CACHE)
2155 add_face_to_cache( face );
2157 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
2158 debugstr_w(face->StyleName));
2160 release_face( face );
2161 release_family( family );
2164 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
2165 FT_Long face_index, BOOL allow_bitmap )
2167 FT_Error err;
2168 TT_OS2 *pOS2;
2169 FT_Face ft_face;
2171 if (file)
2173 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
2174 err = pFT_New_Face(library, file, face_index, &ft_face);
2176 else
2178 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
2179 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
2182 if (err != 0)
2184 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
2185 return NULL;
2188 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
2189 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
2191 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
2192 goto fail;
2195 if (!FT_IS_SFNT( ft_face ))
2197 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
2199 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
2200 goto fail;
2203 else
2205 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
2206 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
2207 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
2209 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
2210 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
2211 goto fail;
2214 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
2215 we don't want to load these. */
2216 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
2218 FT_ULong len = 0;
2220 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
2222 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
2223 goto fail;
2228 if (!ft_face->family_name || !ft_face->style_name)
2230 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
2231 goto fail;
2234 return ft_face;
2235 fail:
2236 pFT_Done_Face( ft_face );
2237 return NULL;
2240 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
2242 FT_Face ft_face;
2243 FT_Long face_index = 0, num_faces;
2244 INT ret = 0;
2246 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
2247 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
2249 #ifdef HAVE_CARBON_CARBON_H
2250 if(file)
2252 char **mac_list = expand_mac_font(file);
2253 if(mac_list)
2255 BOOL had_one = FALSE;
2256 char **cursor;
2257 for(cursor = mac_list; *cursor; cursor++)
2259 had_one = TRUE;
2260 AddFontToList(*cursor, NULL, 0, flags);
2261 HeapFree(GetProcessHeap(), 0, *cursor);
2263 HeapFree(GetProcessHeap(), 0, mac_list);
2264 if(had_one)
2265 return 1;
2268 #endif /* HAVE_CARBON_CARBON_H */
2270 do {
2271 const DWORD FS_DBCS_MASK = FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB;
2272 FONTSIGNATURE fs;
2274 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_ALLOW_BITMAP );
2275 if (!ft_face) return 0;
2277 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
2279 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
2280 pFT_Done_Face(ft_face);
2281 return 0;
2284 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags);
2285 ++ret;
2287 get_fontsig(ft_face, &fs);
2288 if (fs.fsCsb[0] & FS_DBCS_MASK)
2290 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index,
2291 flags | ADDFONT_VERTICAL_FONT);
2292 ++ret;
2295 num_faces = ft_face->num_faces;
2296 pFT_Done_Face(ft_face);
2297 } while(num_faces > ++face_index);
2298 return ret;
2301 static int remove_font_resource( const char *file, DWORD flags )
2303 Family *family, *family_next;
2304 Face *face, *face_next;
2305 struct stat st;
2306 int count = 0;
2308 if (stat( file, &st ) == -1) return 0;
2309 LIST_FOR_EACH_ENTRY_SAFE( family, family_next, &font_list, Family, entry )
2311 family->refcount++;
2312 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, Face, entry )
2314 if (!face->file) continue;
2315 if (LOWORD(face->flags) != LOWORD(flags)) continue;
2316 if (st.st_dev == face->dev && st.st_ino == face->ino)
2318 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount );
2319 release_face( face );
2320 count++;
2323 release_family( family );
2325 return count;
2328 static void DumpFontList(void)
2330 Family *family;
2331 Face *face;
2333 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2334 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
2335 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2336 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
2337 if(!face->scalable)
2338 TRACE(" %d", face->size.height);
2339 TRACE("\n");
2344 static BOOL map_font_family(const WCHAR *orig, const WCHAR *repl)
2346 Family *family = find_family_from_any_name(repl);
2347 if (family != NULL)
2349 Family *new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2350 if (new_family != NULL)
2352 TRACE("mapping %s to %s\n", debugstr_w(repl), debugstr_w(orig));
2353 new_family->FamilyName = strdupW(orig);
2354 new_family->EnglishName = NULL;
2355 list_init(&new_family->faces);
2356 new_family->replacement = &family->faces;
2357 list_add_tail(&font_list, &new_family->entry);
2358 return TRUE;
2361 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(repl));
2362 return FALSE;
2365 /***********************************************************
2366 * The replacement list is a way to map an entire font
2367 * family onto another family. For example adding
2369 * [HKCU\Software\Wine\Fonts\Replacements]
2370 * "Wingdings"="Winedings"
2372 * would enumerate the Winedings font both as Winedings and
2373 * Wingdings. However if a real Wingdings font is present the
2374 * replacement does not take place.
2377 static void LoadReplaceList(void)
2379 HKEY hkey;
2380 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2381 LPWSTR value;
2382 LPVOID data;
2384 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2385 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
2387 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2388 &valuelen, &datalen, NULL, NULL);
2390 valuelen++; /* returned value doesn't include room for '\0' */
2391 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2392 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2394 dlen = datalen;
2395 vlen = valuelen;
2396 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data, &dlen) == ERROR_SUCCESS)
2398 /* "NewName"="Oldname" */
2399 if(!find_family_from_any_name(value))
2401 if (type == REG_MULTI_SZ)
2403 WCHAR *replace = data;
2404 while(*replace)
2406 if (map_font_family(value, replace))
2407 break;
2408 replace += strlenW(replace) + 1;
2411 else if (type == REG_SZ)
2412 map_font_family(value, data);
2414 else
2415 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2417 /* reset dlen and vlen */
2418 dlen = datalen;
2419 vlen = valuelen;
2421 HeapFree(GetProcessHeap(), 0, data);
2422 HeapFree(GetProcessHeap(), 0, value);
2423 RegCloseKey(hkey);
2427 static const WCHAR *font_links_list[] =
2429 Lucida_Sans_Unicode,
2430 Microsoft_Sans_Serif,
2431 Tahoma
2434 static const struct font_links_defaults_list
2436 /* Keyed off substitution for "MS Shell Dlg" */
2437 const WCHAR *shelldlg;
2438 /* Maximum of four substitutes, plus terminating NULL pointer */
2439 const WCHAR *substitutes[5];
2440 } font_links_defaults_list[] =
2442 /* Non East-Asian */
2443 { Tahoma, /* FIXME unverified ordering */
2444 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2446 /* Below lists are courtesy of
2447 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2449 /* Japanese */
2450 { MS_UI_Gothic,
2451 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2453 /* Chinese Simplified */
2454 { SimSun,
2455 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2457 /* Korean */
2458 { Gulim,
2459 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2461 /* Chinese Traditional */
2462 { PMingLiU,
2463 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2468 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2470 SYSTEM_LINKS *font_link;
2472 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2474 if(!strcmpiW(font_link->font_name, name))
2475 return font_link;
2478 return NULL;
2481 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2483 const WCHAR *value;
2484 int i;
2485 FontSubst *psub;
2486 Family *family;
2487 Face *face;
2488 const WCHAR *file;
2490 if (values)
2492 SYSTEM_LINKS *font_link;
2494 psub = get_font_subst(&font_subst_list, name, -1);
2495 /* Don't store fonts that are only substitutes for other fonts */
2496 if(psub)
2498 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2499 return;
2502 font_link = find_font_link(name);
2503 if (font_link == NULL)
2505 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2506 font_link->font_name = strdupW(name);
2507 list_init(&font_link->links);
2508 list_add_tail(&system_links, &font_link->entry);
2511 memset(&font_link->fs, 0, sizeof font_link->fs);
2512 for (i = 0; values[i] != NULL; i++)
2514 const struct list *face_list;
2515 CHILD_FONT *child_font;
2517 value = values[i];
2518 if (!strcmpiW(name,value))
2519 continue;
2520 psub = get_font_subst(&font_subst_list, value, -1);
2521 if(psub)
2522 value = psub->to.name;
2523 family = find_family_from_name(value);
2524 if (!family)
2525 continue;
2526 file = NULL;
2527 /* Use first extant filename for this Family */
2528 face_list = get_face_list_from_family(family);
2529 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2531 if (!face->file)
2532 continue;
2533 file = strrchrW(face->file, '/');
2534 if (!file)
2535 file = face->file;
2536 else
2537 file++;
2538 break;
2540 if (!file)
2541 continue;
2542 face = find_face_from_filename(file, value);
2543 if(!face)
2545 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2546 continue;
2549 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2550 child_font->face = face;
2551 child_font->font = NULL;
2552 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2553 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2554 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2555 child_font->face->face_index);
2556 list_add_tail(&font_link->links, &child_font->entry);
2558 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2564 /*************************************************************
2565 * init_system_links
2567 static BOOL init_system_links(void)
2569 HKEY hkey;
2570 BOOL ret = FALSE;
2571 DWORD type, max_val, max_data, val_len, data_len, index;
2572 WCHAR *value, *data;
2573 WCHAR *entry, *next;
2574 SYSTEM_LINKS *font_link, *system_font_link;
2575 CHILD_FONT *child_font;
2576 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2577 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2578 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2579 Face *face;
2580 FontSubst *psub;
2581 UINT i, j;
2583 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2585 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2586 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2587 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2588 val_len = max_val + 1;
2589 data_len = max_data;
2590 index = 0;
2591 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2593 psub = get_font_subst(&font_subst_list, value, -1);
2594 /* Don't store fonts that are only substitutes for other fonts */
2595 if(psub)
2597 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2598 goto next;
2600 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2601 font_link->font_name = strdupW(value);
2602 memset(&font_link->fs, 0, sizeof font_link->fs);
2603 list_init(&font_link->links);
2604 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2606 WCHAR *face_name;
2607 CHILD_FONT *child_font;
2609 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2611 next = entry + strlenW(entry) + 1;
2613 face_name = strchrW(entry, ',');
2614 if(face_name)
2616 *face_name++ = 0;
2617 while(isspaceW(*face_name))
2618 face_name++;
2620 psub = get_font_subst(&font_subst_list, face_name, -1);
2621 if(psub)
2622 face_name = psub->to.name;
2624 face = find_face_from_filename(entry, face_name);
2625 if(!face)
2627 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2628 continue;
2631 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2632 child_font->face = face;
2633 child_font->font = NULL;
2634 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2635 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2636 TRACE("Adding file %s index %ld\n",
2637 debugstr_w(child_font->face->file), child_font->face->face_index);
2638 list_add_tail(&font_link->links, &child_font->entry);
2640 list_add_tail(&system_links, &font_link->entry);
2641 next:
2642 val_len = max_val + 1;
2643 data_len = max_data;
2646 HeapFree(GetProcessHeap(), 0, value);
2647 HeapFree(GetProcessHeap(), 0, data);
2648 RegCloseKey(hkey);
2652 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2653 if (!psub) {
2654 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2655 goto skip_internal;
2658 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2660 const FontSubst *psub2;
2661 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2663 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2665 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2666 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2668 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2669 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2671 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2673 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2677 skip_internal:
2679 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2680 that Tahoma has */
2682 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2683 system_font_link->font_name = strdupW(System);
2684 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2685 list_init(&system_font_link->links);
2687 face = find_face_from_filename(tahoma_ttf, Tahoma);
2688 if(face)
2690 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2691 child_font->face = face;
2692 child_font->font = NULL;
2693 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2694 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2695 TRACE("Found Tahoma in %s index %ld\n",
2696 debugstr_w(child_font->face->file), child_font->face->face_index);
2697 list_add_tail(&system_font_link->links, &child_font->entry);
2699 font_link = find_font_link(Tahoma);
2700 if (font_link != NULL)
2702 CHILD_FONT *font_link_entry;
2703 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2705 CHILD_FONT *new_child;
2706 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2707 new_child->face = font_link_entry->face;
2708 new_child->font = NULL;
2709 new_child->face->refcount++;
2710 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2711 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2712 list_add_tail(&system_font_link->links, &new_child->entry);
2715 list_add_tail(&system_links, &system_font_link->entry);
2716 return ret;
2719 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2721 DIR *dir;
2722 struct dirent *dent;
2723 char path[MAX_PATH];
2725 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2727 dir = opendir(dirname);
2728 if(!dir) {
2729 WARN("Can't open directory %s\n", debugstr_a(dirname));
2730 return FALSE;
2732 while((dent = readdir(dir)) != NULL) {
2733 struct stat statbuf;
2735 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2736 continue;
2738 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2740 sprintf(path, "%s/%s", dirname, dent->d_name);
2742 if(stat(path, &statbuf) == -1)
2744 WARN("Can't stat %s\n", debugstr_a(path));
2745 continue;
2747 if(S_ISDIR(statbuf.st_mode))
2748 ReadFontDir(path, external_fonts);
2749 else
2751 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2752 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2753 AddFontToList(path, NULL, 0, addfont_flags);
2756 closedir(dir);
2757 return TRUE;
2760 #ifdef SONAME_LIBFONTCONFIG
2762 static BOOL fontconfig_enabled;
2764 static UINT parse_aa_pattern( FcPattern *pattern )
2766 FcBool antialias;
2767 int rgba;
2768 UINT aa_flags = 0;
2770 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2771 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2773 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2775 switch (rgba)
2777 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2778 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2779 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2780 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2781 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2784 return aa_flags;
2787 static void init_fontconfig(void)
2789 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2791 if (!fc_handle)
2793 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2794 return;
2797 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2798 LOAD_FUNCPTR(FcConfigSubstitute);
2799 LOAD_FUNCPTR(FcFontList);
2800 LOAD_FUNCPTR(FcFontSetDestroy);
2801 LOAD_FUNCPTR(FcInit);
2802 LOAD_FUNCPTR(FcObjectSetAdd);
2803 LOAD_FUNCPTR(FcObjectSetCreate);
2804 LOAD_FUNCPTR(FcObjectSetDestroy);
2805 LOAD_FUNCPTR(FcPatternCreate);
2806 LOAD_FUNCPTR(FcPatternDestroy);
2807 LOAD_FUNCPTR(FcPatternGetBool);
2808 LOAD_FUNCPTR(FcPatternGetInteger);
2809 LOAD_FUNCPTR(FcPatternGetString);
2810 #undef LOAD_FUNCPTR
2812 if (pFcInit())
2814 FcPattern *pattern = pFcPatternCreate();
2815 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2816 default_aa_flags = parse_aa_pattern( pattern );
2817 pFcPatternDestroy( pattern );
2818 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2819 fontconfig_enabled = TRUE;
2823 static void load_fontconfig_fonts(void)
2825 FcPattern *pat;
2826 FcObjectSet *os;
2827 FcFontSet *fontset;
2828 int i, len;
2829 char *file;
2830 const char *ext;
2832 if (!fontconfig_enabled) return;
2834 pat = pFcPatternCreate();
2835 os = pFcObjectSetCreate();
2836 pFcObjectSetAdd(os, FC_FILE);
2837 pFcObjectSetAdd(os, FC_SCALABLE);
2838 pFcObjectSetAdd(os, FC_ANTIALIAS);
2839 pFcObjectSetAdd(os, FC_RGBA);
2840 fontset = pFcFontList(NULL, pat, os);
2841 if(!fontset) return;
2842 for(i = 0; i < fontset->nfont; i++) {
2843 FcBool scalable;
2844 DWORD aa_flags;
2846 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2847 continue;
2849 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2851 /* We're just interested in OT/TT fonts for now, so this hack just
2852 picks up the scalable fonts without extensions .pf[ab] to save time
2853 loading every other font */
2855 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2857 TRACE("not scalable\n");
2858 continue;
2861 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2862 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2864 len = strlen( file );
2865 if(len < 4) continue;
2866 ext = &file[ len - 3 ];
2867 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2868 AddFontToList(file, NULL, 0,
2869 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2871 pFcFontSetDestroy(fontset);
2872 pFcObjectSetDestroy(os);
2873 pFcPatternDestroy(pat);
2876 #elif defined(HAVE_CARBON_CARBON_H)
2878 static void load_mac_font_callback(const void *value, void *context)
2880 CFStringRef pathStr = value;
2881 CFIndex len;
2882 char* path;
2884 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2885 path = HeapAlloc(GetProcessHeap(), 0, len);
2886 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2888 TRACE("font file %s\n", path);
2889 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2891 HeapFree(GetProcessHeap(), 0, path);
2894 static void load_mac_fonts(void)
2896 CFStringRef removeDupesKey;
2897 CFBooleanRef removeDupesValue;
2898 CFDictionaryRef options;
2899 CTFontCollectionRef col;
2900 CFArrayRef descs;
2901 CFMutableSetRef paths;
2902 CFIndex i;
2904 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2905 removeDupesValue = kCFBooleanTrue;
2906 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2907 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2908 col = CTFontCollectionCreateFromAvailableFonts(options);
2909 if (options) CFRelease(options);
2910 if (!col)
2912 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2913 return;
2916 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2917 CFRelease(col);
2918 if (!descs)
2920 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2921 return;
2924 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2925 if (!paths)
2927 WARN("CFSetCreateMutable failed\n");
2928 CFRelease(descs);
2929 return;
2932 for (i = 0; i < CFArrayGetCount(descs); i++)
2934 CTFontDescriptorRef desc;
2935 CFURLRef url;
2936 CFStringRef ext;
2937 CFStringRef path;
2939 desc = CFArrayGetValueAtIndex(descs, i);
2941 #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2942 url = CTFontDescriptorCopyAttribute(desc, kCTFontURLAttribute);
2943 #else
2944 /* CTFontDescriptor doesn't support kCTFontURLAttribute prior to 10.6, so
2945 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2947 CTFontRef font;
2948 ATSFontRef atsFont;
2949 OSStatus status;
2950 FSRef fsref;
2952 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2953 if (!font) continue;
2955 atsFont = CTFontGetPlatformFont(font, NULL);
2956 if (!atsFont)
2958 CFRelease(font);
2959 continue;
2962 status = ATSFontGetFileReference(atsFont, &fsref);
2963 CFRelease(font);
2964 if (status != noErr) continue;
2966 url = CFURLCreateFromFSRef(NULL, &fsref);
2968 #endif
2969 if (!url) continue;
2971 ext = CFURLCopyPathExtension(url);
2972 if (ext)
2974 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2975 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2976 CFRelease(ext);
2977 if (skip)
2979 CFRelease(url);
2980 continue;
2984 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2985 CFRelease(url);
2986 if (!path) continue;
2988 CFSetAddValue(paths, path);
2989 CFRelease(path);
2992 CFRelease(descs);
2994 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2995 CFRelease(paths);
2998 #endif
3000 static char *get_font_dir(void)
3002 const char *build_dir, *data_dir;
3003 char *name = NULL;
3005 if ((data_dir = wine_get_data_dir()))
3007 if (!(name = HeapAlloc( GetProcessHeap(), 0, strlen(data_dir) + 1 + sizeof(WINE_FONT_DIR) )))
3008 return NULL;
3009 strcpy( name, data_dir );
3010 strcat( name, "/" );
3011 strcat( name, WINE_FONT_DIR );
3013 else if ((build_dir = wine_get_build_dir()))
3015 if (!(name = HeapAlloc( GetProcessHeap(), 0, strlen(build_dir) + sizeof("/fonts") )))
3016 return NULL;
3017 strcpy( name, build_dir );
3018 strcat( name, "/fonts" );
3020 return name;
3023 static char *get_data_dir_path( LPCWSTR file )
3025 char *unix_name = NULL;
3026 char *font_dir = get_font_dir();
3028 if (font_dir)
3030 INT len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
3032 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(font_dir) + len + 1 );
3033 strcpy(unix_name, font_dir);
3034 strcat(unix_name, "/");
3036 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
3037 HeapFree( GetProcessHeap(), 0, font_dir );
3039 return unix_name;
3042 static BOOL load_font_from_data_dir(LPCWSTR file)
3044 BOOL ret = FALSE;
3045 char *unix_name = get_data_dir_path( file );
3047 if (unix_name)
3049 EnterCriticalSection( &freetype_cs );
3050 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3051 LeaveCriticalSection( &freetype_cs );
3052 HeapFree(GetProcessHeap(), 0, unix_name);
3054 return ret;
3057 static char *get_winfonts_dir_path(LPCWSTR file)
3059 static const WCHAR slashW[] = {'\\','\0'};
3060 WCHAR windowsdir[MAX_PATH];
3062 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3063 strcatW(windowsdir, fontsW);
3064 strcatW(windowsdir, slashW);
3065 strcatW(windowsdir, file);
3066 return wine_get_unix_file_name( windowsdir );
3069 static void load_system_fonts(void)
3071 HKEY hkey;
3072 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
3073 const WCHAR * const *value;
3074 DWORD dlen, type;
3075 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3076 char *unixname;
3078 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
3079 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3080 strcatW(windowsdir, fontsW);
3081 for(value = SystemFontValues; *value; value++) {
3082 dlen = sizeof(data);
3083 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
3084 type == REG_SZ) {
3085 BOOL added = FALSE;
3087 sprintfW(pathW, fmtW, windowsdir, data);
3088 if((unixname = wine_get_unix_file_name(pathW))) {
3089 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3090 HeapFree(GetProcessHeap(), 0, unixname);
3092 if (!added)
3093 load_font_from_data_dir(data);
3096 RegCloseKey(hkey);
3100 /*************************************************************
3102 * This adds registry entries for any externally loaded fonts
3103 * (fonts from fontconfig or FontDirs). It also deletes entries
3104 * of no longer existing fonts.
3107 static void update_reg_entries(void)
3109 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
3110 LPWSTR valueW;
3111 DWORD len;
3112 Family *family;
3113 Face *face;
3114 WCHAR *file, *path;
3115 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
3117 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
3118 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
3119 ERR("Can't create Windows font reg key\n");
3120 goto end;
3123 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
3124 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
3125 ERR("Can't create Windows font reg key\n");
3126 goto end;
3129 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
3130 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
3131 ERR("Can't create external font reg key\n");
3132 goto end;
3135 /* enumerate the fonts and add external ones to the two keys */
3137 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
3138 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
3139 char *buffer;
3140 WCHAR *name;
3142 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
3144 name = face->FullName ? face->FullName : family->FamilyName;
3146 len = strlenW(name) + 1;
3147 if (face->scalable)
3148 len += sizeof(TrueType) / sizeof(WCHAR);
3150 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3151 strcpyW(valueW, name);
3153 if (face->scalable)
3154 strcatW(valueW, TrueType);
3156 buffer = strWtoA( CP_UNIXCP, face->file );
3157 path = wine_get_dos_file_name( buffer );
3158 HeapFree( GetProcessHeap(), 0, buffer );
3160 if (path)
3161 file = path;
3162 else if ((file = strrchrW(face->file, '/')))
3163 file++;
3164 else
3165 file = face->file;
3167 len = strlenW(file) + 1;
3168 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3169 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3170 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3172 HeapFree(GetProcessHeap(), 0, path);
3173 HeapFree(GetProcessHeap(), 0, valueW);
3176 end:
3177 if(external_key) RegCloseKey(external_key);
3178 if(win9x_key) RegCloseKey(win9x_key);
3179 if(winnt_key) RegCloseKey(winnt_key);
3182 static void delete_external_font_keys(void)
3184 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
3185 DWORD dlen, plen, vlen, datalen, valuelen, i, type, path_type;
3186 LPWSTR valueW;
3187 LPVOID data;
3188 BYTE *path;
3190 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
3191 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
3192 ERR("Can't create Windows font reg key\n");
3193 goto end;
3196 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
3197 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
3198 ERR("Can't create Windows font reg key\n");
3199 goto end;
3202 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
3203 ERR("Can't create external font reg key\n");
3204 goto end;
3207 /* Delete all external fonts added last time */
3209 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3210 &valuelen, &datalen, NULL, NULL);
3211 valuelen++; /* returned value doesn't include room for '\0' */
3212 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3213 data = HeapAlloc(GetProcessHeap(), 0, datalen);
3214 path = HeapAlloc(GetProcessHeap(), 0, datalen);
3216 dlen = datalen;
3217 vlen = valuelen;
3218 i = 0;
3219 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
3220 &dlen) == ERROR_SUCCESS) {
3221 plen = dlen;
3222 if (RegQueryValueExW(winnt_key, valueW, 0, &path_type, path, &plen) == ERROR_SUCCESS &&
3223 type == path_type && dlen == plen && !memcmp(data, path, plen))
3224 RegDeleteValueW(winnt_key, valueW);
3226 plen = dlen;
3227 if (RegQueryValueExW(win9x_key, valueW, 0, &path_type, path, &plen) == ERROR_SUCCESS &&
3228 type == path_type && dlen == plen && !memcmp(data, path, plen))
3229 RegDeleteValueW(win9x_key, valueW);
3231 /* reset dlen and vlen */
3232 dlen = datalen;
3233 vlen = valuelen;
3235 HeapFree(GetProcessHeap(), 0, path);
3236 HeapFree(GetProcessHeap(), 0, data);
3237 HeapFree(GetProcessHeap(), 0, valueW);
3239 /* Delete the old external fonts key */
3240 RegCloseKey(external_key);
3241 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
3243 end:
3244 if(win9x_key) RegCloseKey(win9x_key);
3245 if(winnt_key) RegCloseKey(winnt_key);
3248 /*************************************************************
3249 * WineEngAddFontResourceEx
3252 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3254 INT ret = 0;
3256 GDI_CheckNotLock();
3258 if (ft_handle) /* do it only if we have freetype up and running */
3260 char *unixname;
3262 EnterCriticalSection( &freetype_cs );
3264 if((unixname = wine_get_unix_file_name(file)))
3266 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3268 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3269 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
3270 HeapFree(GetProcessHeap(), 0, unixname);
3272 if (!ret && !strchrW(file, '\\')) {
3273 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
3274 if ((unixname = get_winfonts_dir_path( file )))
3276 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3277 HeapFree(GetProcessHeap(), 0, unixname);
3279 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
3280 if (!ret && (unixname = get_data_dir_path( file )))
3282 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3283 HeapFree(GetProcessHeap(), 0, unixname);
3287 LeaveCriticalSection( &freetype_cs );
3289 return ret;
3292 /*************************************************************
3293 * WineEngAddFontMemResourceEx
3296 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3298 GDI_CheckNotLock();
3300 if (ft_handle) /* do it only if we have freetype up and running */
3302 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
3304 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
3305 memcpy(pFontCopy, pbFont, cbFont);
3307 EnterCriticalSection( &freetype_cs );
3308 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3309 LeaveCriticalSection( &freetype_cs );
3311 if (*pcFonts == 0)
3313 TRACE("AddFontToList failed\n");
3314 HeapFree(GetProcessHeap(), 0, pFontCopy);
3315 return 0;
3317 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
3318 * For now return something unique but quite random
3320 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
3321 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
3324 *pcFonts = 0;
3325 return 0;
3328 /*************************************************************
3329 * WineEngRemoveFontResourceEx
3332 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3334 INT ret = 0;
3336 GDI_CheckNotLock();
3338 if (ft_handle) /* do it only if we have freetype up and running */
3340 char *unixname;
3342 EnterCriticalSection( &freetype_cs );
3344 if ((unixname = wine_get_unix_file_name(file)))
3346 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3348 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3349 ret = remove_font_resource( unixname, addfont_flags );
3350 HeapFree(GetProcessHeap(), 0, unixname);
3352 if (!ret && !strchrW(file, '\\'))
3354 if ((unixname = get_winfonts_dir_path( file )))
3356 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3357 HeapFree(GetProcessHeap(), 0, unixname);
3359 if (!ret && (unixname = get_data_dir_path( file )))
3361 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3362 HeapFree(GetProcessHeap(), 0, unixname);
3366 LeaveCriticalSection( &freetype_cs );
3368 return ret;
3371 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
3373 WCHAR *fullname;
3374 char *unix_name;
3375 int file_len;
3377 if (!font_file) return NULL;
3379 file_len = strlenW( font_file );
3381 if (font_path && font_path[0])
3383 int path_len = strlenW( font_path );
3384 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
3385 if (!fullname) return NULL;
3386 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
3387 fullname[path_len] = '\\';
3388 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
3390 else
3392 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
3393 if (!len) return NULL;
3394 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3395 if (!fullname) return NULL;
3396 GetFullPathNameW( font_file, len, fullname, NULL );
3399 unix_name = wine_get_unix_file_name( fullname );
3400 HeapFree( GetProcessHeap(), 0, fullname );
3401 return unix_name;
3404 #include <pshpack1.h>
3405 struct fontdir
3407 WORD num_of_resources;
3408 WORD res_id;
3409 WORD dfVersion;
3410 DWORD dfSize;
3411 CHAR dfCopyright[60];
3412 WORD dfType;
3413 WORD dfPoints;
3414 WORD dfVertRes;
3415 WORD dfHorizRes;
3416 WORD dfAscent;
3417 WORD dfInternalLeading;
3418 WORD dfExternalLeading;
3419 BYTE dfItalic;
3420 BYTE dfUnderline;
3421 BYTE dfStrikeOut;
3422 WORD dfWeight;
3423 BYTE dfCharSet;
3424 WORD dfPixWidth;
3425 WORD dfPixHeight;
3426 BYTE dfPitchAndFamily;
3427 WORD dfAvgWidth;
3428 WORD dfMaxWidth;
3429 BYTE dfFirstChar;
3430 BYTE dfLastChar;
3431 BYTE dfDefaultChar;
3432 BYTE dfBreakChar;
3433 WORD dfWidthBytes;
3434 DWORD dfDevice;
3435 DWORD dfFace;
3436 DWORD dfReserved;
3437 CHAR szFaceName[LF_FACESIZE];
3440 #include <poppack.h>
3442 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
3443 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
3445 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
3447 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3448 Face *face;
3449 WCHAR *name, *english_name;
3450 ENUMLOGFONTEXW elf;
3451 NEWTEXTMETRICEXW ntm;
3452 DWORD type;
3454 if (!ft_face) return FALSE;
3455 face = create_face( ft_face, 0, unix_name, NULL, 0, 0 );
3456 get_family_names( ft_face, &name, &english_name, FALSE );
3457 pFT_Done_Face( ft_face );
3459 GetEnumStructs( face, name, &elf, &ntm, &type );
3460 release_face( face );
3461 HeapFree( GetProcessHeap(), 0, name );
3462 HeapFree( GetProcessHeap(), 0, english_name );
3464 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3466 memset( fd, 0, sizeof(*fd) );
3468 fd->num_of_resources = 1;
3469 fd->res_id = 0;
3470 fd->dfVersion = 0x200;
3471 fd->dfSize = sizeof(*fd);
3472 strcpy( fd->dfCopyright, "Wine fontdir" );
3473 fd->dfType = 0x4003; /* 0x0080 set if private */
3474 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3475 fd->dfVertRes = 72;
3476 fd->dfHorizRes = 72;
3477 fd->dfAscent = ntm.ntmTm.tmAscent;
3478 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3479 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3480 fd->dfItalic = ntm.ntmTm.tmItalic;
3481 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3482 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3483 fd->dfWeight = ntm.ntmTm.tmWeight;
3484 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3485 fd->dfPixWidth = 0;
3486 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3487 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3488 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3489 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3490 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3491 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3492 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3493 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3494 fd->dfWidthBytes = 0;
3495 fd->dfDevice = 0;
3496 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3497 fd->dfReserved = 0;
3498 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3500 return TRUE;
3503 #define NE_FFLAGS_LIBMODULE 0x8000
3504 #define NE_OSFLAGS_WINDOWS 0x02
3506 static const char dos_string[0x40] = "This is a TrueType resource file";
3507 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3509 #include <pshpack2.h>
3511 struct ne_typeinfo
3513 WORD type_id;
3514 WORD count;
3515 DWORD res;
3518 struct ne_nameinfo
3520 WORD off;
3521 WORD len;
3522 WORD flags;
3523 WORD id;
3524 DWORD res;
3527 struct rsrc_tab
3529 WORD align;
3530 struct ne_typeinfo fontdir_type;
3531 struct ne_nameinfo fontdir_name;
3532 struct ne_typeinfo scalable_type;
3533 struct ne_nameinfo scalable_name;
3534 WORD end_of_rsrc;
3535 BYTE fontdir_res_name[8];
3538 #include <poppack.h>
3540 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3542 BOOL ret = FALSE;
3543 HANDLE file;
3544 DWORD size, written;
3545 BYTE *ptr, *start;
3546 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3547 char *font_fileA, *last_part, *ext;
3548 IMAGE_DOS_HEADER dos;
3549 IMAGE_OS2_HEADER ne =
3551 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3552 0, 0, 0, 0, 0, 0,
3553 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3554 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3556 struct rsrc_tab rsrc_tab =
3559 { 0x8007, 1, 0 },
3560 { 0, 0, 0x0c50, 0x2c, 0 },
3561 { 0x80cc, 1, 0 },
3562 { 0, 0, 0x0c50, 0x8001, 0 },
3564 { 7,'F','O','N','T','D','I','R'}
3567 memset( &dos, 0, sizeof(dos) );
3568 dos.e_magic = IMAGE_DOS_SIGNATURE;
3569 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3571 /* import name is last part\0, resident name is last part without extension
3572 non-resident name is "FONTRES:" + lfFaceName */
3574 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3575 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3576 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3578 last_part = strrchr( font_fileA, '\\' );
3579 if (last_part) last_part++;
3580 else last_part = font_fileA;
3581 import_name_len = strlen( last_part ) + 1;
3583 ext = strchr( last_part, '.' );
3584 if (ext) res_name_len = ext - last_part;
3585 else res_name_len = import_name_len - 1;
3587 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3589 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3590 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3591 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3592 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3593 ne.ne_cbenttab = 2;
3594 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3596 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3597 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3598 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3599 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3601 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3602 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3604 if (!ptr)
3606 HeapFree( GetProcessHeap(), 0, font_fileA );
3607 return FALSE;
3610 memcpy( ptr, &dos, sizeof(dos) );
3611 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3612 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3614 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3615 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3617 ptr = start + dos.e_lfanew + ne.ne_restab;
3618 *ptr++ = res_name_len;
3619 memcpy( ptr, last_part, res_name_len );
3621 ptr = start + dos.e_lfanew + ne.ne_imptab;
3622 *ptr++ = import_name_len;
3623 memcpy( ptr, last_part, import_name_len );
3625 ptr = start + ne.ne_nrestab;
3626 *ptr++ = non_res_name_len;
3627 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3628 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3630 ptr = start + (rsrc_tab.scalable_name.off << 4);
3631 memcpy( ptr, font_fileA, font_file_len );
3633 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3634 memcpy( ptr, fontdir, fontdir->dfSize );
3636 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3637 if (file != INVALID_HANDLE_VALUE)
3639 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3640 ret = TRUE;
3641 CloseHandle( file );
3644 HeapFree( GetProcessHeap(), 0, start );
3645 HeapFree( GetProcessHeap(), 0, font_fileA );
3647 return ret;
3650 /*************************************************************
3651 * WineEngCreateScalableFontResource
3654 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3655 LPCWSTR font_file, LPCWSTR font_path )
3657 char *unix_name = get_ttf_file_name( font_file, font_path );
3658 struct fontdir fontdir;
3659 BOOL ret = FALSE;
3661 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3662 SetLastError( ERROR_INVALID_PARAMETER );
3663 else
3665 if (hidden) fontdir.dfType |= 0x80;
3666 ret = create_fot( resource, font_file, &fontdir );
3669 HeapFree( GetProcessHeap(), 0, unix_name );
3670 return ret;
3673 static const struct nls_update_font_list
3675 UINT ansi_cp, oem_cp;
3676 const char *oem, *fixed, *system;
3677 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3678 /* these are for font substitutes */
3679 const char *shelldlg, *tmsrmn;
3680 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3681 *helv_0, *tmsrmn_0;
3682 const struct subst
3684 const char *from, *to;
3685 } arial_0, courier_new_0, times_new_roman_0;
3686 } nls_update_font_list[] =
3688 /* Latin 1 (United States) */
3689 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3690 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3691 "Tahoma","Times New Roman",
3692 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3693 { 0 }, { 0 }, { 0 }
3695 /* Latin 1 (Multilingual) */
3696 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3697 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3698 "Tahoma","Times New Roman", /* FIXME unverified */
3699 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3700 { 0 }, { 0 }, { 0 }
3702 /* Eastern Europe */
3703 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3704 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3705 "Tahoma","Times New Roman", /* FIXME unverified */
3706 "Fixedsys,238", "System,238",
3707 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3708 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3709 { "Arial CE,0", "Arial,238" },
3710 { "Courier New CE,0", "Courier New,238" },
3711 { "Times New Roman CE,0", "Times New Roman,238" }
3713 /* Cyrillic */
3714 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3715 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3716 "Tahoma","Times New Roman", /* FIXME unverified */
3717 "Fixedsys,204", "System,204",
3718 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3719 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3720 { "Arial Cyr,0", "Arial,204" },
3721 { "Courier New Cyr,0", "Courier New,204" },
3722 { "Times New Roman Cyr,0", "Times New Roman,204" }
3724 /* Greek */
3725 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3726 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3727 "Tahoma","Times New Roman", /* FIXME unverified */
3728 "Fixedsys,161", "System,161",
3729 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3730 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3731 { "Arial Greek,0", "Arial,161" },
3732 { "Courier New Greek,0", "Courier New,161" },
3733 { "Times New Roman Greek,0", "Times New Roman,161" }
3735 /* Turkish */
3736 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3737 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3738 "Tahoma","Times New Roman", /* FIXME unverified */
3739 "Fixedsys,162", "System,162",
3740 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3741 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3742 { "Arial Tur,0", "Arial,162" },
3743 { "Courier New Tur,0", "Courier New,162" },
3744 { "Times New Roman Tur,0", "Times New Roman,162" }
3746 /* Hebrew */
3747 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3748 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3749 "Tahoma","Times New Roman", /* FIXME unverified */
3750 "Fixedsys,177", "System,177",
3751 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3752 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3753 { 0 }, { 0 }, { 0 }
3755 /* Arabic */
3756 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3757 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3758 "Microsoft Sans Serif","Times New Roman",
3759 "Fixedsys,178", "System,178",
3760 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3761 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3762 { 0 }, { 0 }, { 0 }
3764 /* Baltic */
3765 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3766 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3767 "Tahoma","Times New Roman", /* FIXME unverified */
3768 "Fixedsys,186", "System,186",
3769 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3770 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3771 { "Arial Baltic,0", "Arial,186" },
3772 { "Courier New Baltic,0", "Courier New,186" },
3773 { "Times New Roman Baltic,0", "Times New Roman,186" }
3775 /* Vietnamese */
3776 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3777 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3778 "Tahoma","Times New Roman", /* FIXME unverified */
3779 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3780 { 0 }, { 0 }, { 0 }
3782 /* Thai */
3783 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3784 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3785 "Tahoma","Times New Roman", /* FIXME unverified */
3786 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3787 { 0 }, { 0 }, { 0 }
3789 /* Japanese */
3790 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3791 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3792 "MS UI Gothic","MS Serif",
3793 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3794 { 0 }, { 0 }, { 0 }
3796 /* Chinese Simplified */
3797 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3798 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3799 "SimSun", "NSimSun",
3800 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3801 { 0 }, { 0 }, { 0 }
3803 /* Korean */
3804 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3805 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3806 "Gulim", "Batang",
3807 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3808 { 0 }, { 0 }, { 0 }
3810 /* Chinese Traditional */
3811 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3812 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3813 "PMingLiU", "MingLiU",
3814 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3815 { 0 }, { 0 }, { 0 }
3819 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3821 return ( ansi_cp == 932 /* CP932 for Japanese */
3822 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3823 || ansi_cp == 949 /* CP949 for Korean */
3824 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3827 static inline HKEY create_fonts_NT_registry_key(void)
3829 HKEY hkey = 0;
3831 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3832 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3833 return hkey;
3836 static inline HKEY create_fonts_9x_registry_key(void)
3838 HKEY hkey = 0;
3840 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3841 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3842 return hkey;
3845 static inline HKEY create_config_fonts_registry_key(void)
3847 HKEY hkey = 0;
3849 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3850 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3851 return hkey;
3854 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3856 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3858 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3859 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3860 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3861 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3864 static void set_value_key(HKEY hkey, const char *name, const char *value)
3866 if (value)
3867 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3868 else if (name)
3869 RegDeleteValueA(hkey, name);
3872 static void update_font_association_info(UINT current_ansi_codepage)
3874 static const char *font_assoc_reg_key = "System\\CurrentControlSet\\Control\\FontAssoc";
3875 static const char *assoc_charset_subkey = "Associated Charset";
3877 if (is_dbcs_ansi_cp(current_ansi_codepage))
3879 HKEY hkey;
3880 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, font_assoc_reg_key, &hkey) == ERROR_SUCCESS)
3882 HKEY hsubkey;
3883 if (RegCreateKeyA(hkey, assoc_charset_subkey, &hsubkey) == ERROR_SUCCESS)
3885 switch (current_ansi_codepage)
3887 case 932:
3888 set_value_key(hsubkey, "ANSI(00)", "NO");
3889 set_value_key(hsubkey, "OEM(FF)", "NO");
3890 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3891 break;
3892 case 936:
3893 case 949:
3894 case 950:
3895 set_value_key(hsubkey, "ANSI(00)", "YES");
3896 set_value_key(hsubkey, "OEM(FF)", "YES");
3897 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3898 break;
3900 RegCloseKey(hsubkey);
3903 /* TODO: Associated DefaultFonts */
3905 RegCloseKey(hkey);
3908 else
3909 RegDeleteTreeA(HKEY_LOCAL_MACHINE, font_assoc_reg_key);
3912 static void set_multi_value_key(HKEY hkey, const WCHAR *name, const WCHAR *value, DWORD len)
3914 if (value)
3915 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (const BYTE *)value, len);
3916 else if (name)
3917 RegDeleteValueW(hkey, name);
3920 static void update_font_system_link_info(UINT current_ansi_codepage)
3922 static const WCHAR system_link_simplified_chinese[] =
3923 {'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3924 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3925 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3926 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3927 '\0'};
3928 static const WCHAR system_link_traditional_chinese[] =
3929 {'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3930 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3931 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3932 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3933 '\0'};
3934 static const WCHAR system_link_japanese[] =
3935 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3936 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3937 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3938 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3939 '\0'};
3940 static const WCHAR system_link_korean[] =
3941 {'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3942 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3943 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3944 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3945 '\0'};
3946 static const WCHAR system_link_non_cjk[] =
3947 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3948 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3949 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3950 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3951 '\0'};
3952 HKEY hkey;
3954 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
3956 const WCHAR *link;
3957 DWORD len;
3959 switch (current_ansi_codepage)
3961 case 932:
3962 link = system_link_japanese;
3963 len = sizeof(system_link_japanese);
3964 break;
3965 case 936:
3966 link = system_link_simplified_chinese;
3967 len = sizeof(system_link_simplified_chinese);
3968 break;
3969 case 949:
3970 link = system_link_korean;
3971 len = sizeof(system_link_korean);
3972 break;
3973 case 950:
3974 link = system_link_traditional_chinese;
3975 len = sizeof(system_link_traditional_chinese);
3976 break;
3977 default:
3978 link = system_link_non_cjk;
3979 len = sizeof(system_link_non_cjk);
3981 set_multi_value_key(hkey, Lucida_Sans_Unicode, link, len);
3982 set_multi_value_key(hkey, Microsoft_Sans_Serif, link, len);
3983 set_multi_value_key(hkey, Tahoma, link, len);
3984 RegCloseKey(hkey);
3988 static void update_font_info(void)
3990 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3991 char buf[40], cpbuf[40];
3992 DWORD len, type;
3993 HKEY hkey = 0;
3994 UINT i, ansi_cp = 0, oem_cp = 0;
3995 DWORD screen_dpi, font_dpi = 0;
3996 BOOL done = FALSE;
3998 screen_dpi = get_dpi();
3999 if (!screen_dpi) screen_dpi = 96;
4001 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
4002 return;
4004 reg_load_dword(hkey, logpixels, &font_dpi);
4006 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
4007 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
4008 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
4009 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
4010 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
4012 /* Setup Default_Fallback usage for DBCS ANSI codepages */
4013 if (is_dbcs_ansi_cp(ansi_cp))
4014 use_default_fallback = TRUE;
4016 buf[0] = 0;
4017 len = sizeof(buf);
4018 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
4020 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
4022 RegCloseKey(hkey);
4023 return;
4025 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
4026 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
4028 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
4029 ansi_cp, oem_cp, screen_dpi);
4031 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
4032 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
4033 RegCloseKey(hkey);
4035 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
4037 HKEY hkey;
4039 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
4040 nls_update_font_list[i].oem_cp == oem_cp)
4042 hkey = create_config_fonts_registry_key();
4043 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
4044 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
4045 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
4046 RegCloseKey(hkey);
4048 hkey = create_fonts_NT_registry_key();
4049 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
4050 RegCloseKey(hkey);
4052 hkey = create_fonts_9x_registry_key();
4053 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
4054 RegCloseKey(hkey);
4056 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
4058 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
4059 strlen(nls_update_font_list[i].shelldlg)+1);
4060 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
4061 strlen(nls_update_font_list[i].tmsrmn)+1);
4063 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
4064 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
4065 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
4066 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
4067 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
4068 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
4069 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
4070 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
4072 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
4073 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
4074 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
4076 RegCloseKey(hkey);
4078 done = TRUE;
4080 else
4082 /* Delete the FontSubstitutes from other locales */
4083 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
4085 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
4086 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
4087 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
4088 RegCloseKey(hkey);
4092 if (!done)
4093 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
4095 /* update locale dependent font association info and font system link info in registry.
4096 update only when codepages changed, not logpixels. */
4097 if (strcmp(buf, cpbuf) != 0)
4099 update_font_association_info(ansi_cp);
4100 update_font_system_link_info(ansi_cp);
4104 static BOOL init_freetype(void)
4106 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
4107 if(!ft_handle) {
4108 WINE_MESSAGE(
4109 "Wine cannot find the FreeType font library. To enable Wine to\n"
4110 "use TrueType fonts please install a version of FreeType greater than\n"
4111 "or equal to 2.0.5.\n"
4112 "http://www.freetype.org\n");
4113 return FALSE;
4116 #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;}
4118 LOAD_FUNCPTR(FT_Done_Face)
4119 LOAD_FUNCPTR(FT_Get_Char_Index)
4120 LOAD_FUNCPTR(FT_Get_First_Char)
4121 LOAD_FUNCPTR(FT_Get_Next_Char)
4122 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
4123 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
4124 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
4125 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
4126 LOAD_FUNCPTR(FT_Init_FreeType)
4127 LOAD_FUNCPTR(FT_Library_Version)
4128 LOAD_FUNCPTR(FT_Load_Glyph)
4129 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
4130 LOAD_FUNCPTR(FT_Matrix_Multiply)
4131 #ifndef FT_MULFIX_INLINED
4132 LOAD_FUNCPTR(FT_MulFix)
4133 #endif
4134 LOAD_FUNCPTR(FT_New_Face)
4135 LOAD_FUNCPTR(FT_New_Memory_Face)
4136 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
4137 LOAD_FUNCPTR(FT_Outline_Get_CBox)
4138 LOAD_FUNCPTR(FT_Outline_Transform)
4139 LOAD_FUNCPTR(FT_Outline_Translate)
4140 LOAD_FUNCPTR(FT_Render_Glyph)
4141 LOAD_FUNCPTR(FT_Set_Charmap)
4142 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
4143 LOAD_FUNCPTR(FT_Vector_Length)
4144 LOAD_FUNCPTR(FT_Vector_Transform)
4145 LOAD_FUNCPTR(FT_Vector_Unit)
4146 #undef LOAD_FUNCPTR
4147 /* Don't warn if these ones are missing */
4148 pFT_Outline_Embolden = wine_dlsym(ft_handle, "FT_Outline_Embolden", NULL, 0);
4149 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
4150 #ifdef FT_LCD_FILTER_H
4151 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
4152 #endif
4154 if(pFT_Init_FreeType(&library) != 0) {
4155 ERR("Can't init FreeType library\n");
4156 wine_dlclose(ft_handle, NULL, 0);
4157 ft_handle = NULL;
4158 return FALSE;
4160 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
4162 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
4163 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
4164 ((FT_Version.minor << 8) & 0x00ff00) |
4165 ((FT_Version.patch ) & 0x0000ff);
4167 font_driver = &freetype_funcs;
4168 return TRUE;
4170 sym_not_found:
4171 WINE_MESSAGE(
4172 "Wine cannot find certain functions that it needs inside the FreeType\n"
4173 "font library. To enable Wine to use TrueType fonts please upgrade\n"
4174 "FreeType to at least version 2.1.4.\n"
4175 "http://www.freetype.org\n");
4176 wine_dlclose(ft_handle, NULL, 0);
4177 ft_handle = NULL;
4178 return FALSE;
4181 static void init_font_list(void)
4183 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
4184 static const WCHAR pathW[] = {'P','a','t','h',0};
4185 HKEY hkey;
4186 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
4187 WCHAR windowsdir[MAX_PATH];
4188 char *unixname;
4190 delete_external_font_keys();
4192 /* load the system bitmap fonts */
4193 load_system_fonts();
4195 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
4196 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
4197 strcatW(windowsdir, fontsW);
4198 if((unixname = wine_get_unix_file_name(windowsdir)))
4200 ReadFontDir(unixname, FALSE);
4201 HeapFree(GetProcessHeap(), 0, unixname);
4204 /* load the wine fonts */
4205 if ((unixname = get_font_dir()))
4207 ReadFontDir(unixname, TRUE);
4208 HeapFree(GetProcessHeap(), 0, unixname);
4211 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
4212 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
4213 full path as the entry. Also look for any .fon fonts, since ReadFontDir
4214 will skip these. */
4215 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
4216 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
4217 &hkey) == ERROR_SUCCESS)
4219 LPWSTR data, valueW;
4220 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
4221 &valuelen, &datalen, NULL, NULL);
4223 valuelen++; /* returned value doesn't include room for '\0' */
4224 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
4225 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
4226 if (valueW && data)
4228 dlen = datalen * sizeof(WCHAR);
4229 vlen = valuelen;
4230 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
4231 &dlen) == ERROR_SUCCESS)
4233 if(data[0] && (data[1] == ':'))
4235 if((unixname = wine_get_unix_file_name(data)))
4237 AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
4238 HeapFree(GetProcessHeap(), 0, unixname);
4241 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
4243 WCHAR pathW[MAX_PATH];
4244 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
4245 BOOL added = FALSE;
4247 sprintfW(pathW, fmtW, windowsdir, data);
4248 if((unixname = wine_get_unix_file_name(pathW)))
4250 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
4251 HeapFree(GetProcessHeap(), 0, unixname);
4253 if (!added)
4254 load_font_from_data_dir(data);
4256 /* reset dlen and vlen */
4257 dlen = datalen;
4258 vlen = valuelen;
4261 HeapFree(GetProcessHeap(), 0, data);
4262 HeapFree(GetProcessHeap(), 0, valueW);
4263 RegCloseKey(hkey);
4266 #ifdef SONAME_LIBFONTCONFIG
4267 load_fontconfig_fonts();
4268 #elif defined(HAVE_CARBON_CARBON_H)
4269 load_mac_fonts();
4270 #elif defined(__ANDROID__)
4271 ReadFontDir("/system/fonts", TRUE);
4272 #endif
4274 /* then look in any directories that we've specified in the config file */
4275 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
4276 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
4278 DWORD len;
4279 LPWSTR valueW;
4280 LPSTR valueA, ptr;
4282 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
4284 len += sizeof(WCHAR);
4285 valueW = HeapAlloc( GetProcessHeap(), 0, len );
4286 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
4288 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
4289 valueA = HeapAlloc( GetProcessHeap(), 0, len );
4290 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
4291 TRACE( "got font path %s\n", debugstr_a(valueA) );
4292 ptr = valueA;
4293 while (ptr)
4295 const char* home;
4296 LPSTR next = strchr( ptr, ':' );
4297 if (next) *next++ = 0;
4298 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
4299 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
4301 strcpy( unixname, home );
4302 strcat( unixname, ptr + 1 );
4303 ReadFontDir( unixname, TRUE );
4304 HeapFree( GetProcessHeap(), 0, unixname );
4306 else
4307 ReadFontDir( ptr, TRUE );
4308 ptr = next;
4310 HeapFree( GetProcessHeap(), 0, valueA );
4312 HeapFree( GetProcessHeap(), 0, valueW );
4314 RegCloseKey(hkey);
4318 static BOOL move_to_front(const WCHAR *name)
4320 Family *family, *cursor2;
4321 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
4323 if(!strcmpiW(family->FamilyName, name))
4325 list_remove(&family->entry);
4326 list_add_head(&font_list, &family->entry);
4327 return TRUE;
4330 return FALSE;
4333 static BOOL set_default(const WCHAR **name_list)
4335 while (*name_list)
4337 if (move_to_front(*name_list)) return TRUE;
4338 name_list++;
4341 return FALSE;
4344 static void reorder_font_list(void)
4346 set_default( default_serif_list );
4347 set_default( default_fixed_list );
4348 set_default( default_sans_list );
4351 /*************************************************************
4352 * WineEngInit
4354 * Initialize FreeType library and create a list of available faces
4356 BOOL WineEngInit(void)
4358 HKEY hkey;
4359 DWORD disposition;
4360 HANDLE font_mutex;
4362 /* update locale dependent font info in registry */
4363 update_font_info();
4365 if(!init_freetype()) return FALSE;
4367 #ifdef SONAME_LIBFONTCONFIG
4368 init_fontconfig();
4369 #endif
4371 if (!RegOpenKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, KEY_READ, &hkey))
4373 static const WCHAR antialias_fake_bold_or_italic[] = { 'A','n','t','i','a','l','i','a','s','F','a','k','e',
4374 'B','o','l','d','O','r','I','t','a','l','i','c',0 };
4375 static const WCHAR true_options[] = { 'y','Y','t','T','1',0 };
4376 DWORD type, size;
4377 WCHAR buffer[20];
4379 size = sizeof(buffer);
4380 if (!RegQueryValueExW(hkey, antialias_fake_bold_or_italic, NULL, &type, (BYTE*)buffer, &size) &&
4381 type == REG_SZ && size >= 1)
4383 antialias_fakes = (strchrW(true_options, buffer[0]) != NULL);
4385 RegCloseKey(hkey);
4388 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
4390 ERR("Failed to create font mutex\n");
4391 return FALSE;
4393 WaitForSingleObject(font_mutex, INFINITE);
4395 create_font_cache_key(&hkey_font_cache, &disposition);
4397 if(disposition == REG_CREATED_NEW_KEY)
4398 init_font_list();
4399 else
4400 load_font_list_from_cache(hkey_font_cache);
4402 reorder_font_list();
4404 DumpFontList();
4405 LoadSubstList();
4406 DumpSubstList();
4407 LoadReplaceList();
4409 if(disposition == REG_CREATED_NEW_KEY)
4410 update_reg_entries();
4412 init_system_links();
4414 ReleaseMutex(font_mutex);
4415 return TRUE;
4418 /* Some fonts have large usWinDescent values, as a result of storing signed short
4419 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
4420 some font generation tools. */
4421 static inline USHORT get_fixed_windescent(USHORT windescent)
4423 return abs((SHORT)windescent);
4426 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
4428 TT_OS2 *pOS2;
4429 TT_HoriHeader *pHori;
4431 LONG ppem;
4432 const LONG MAX_PPEM = (1 << 16) - 1;
4434 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4435 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4437 if(height == 0) height = 16;
4439 /* Calc. height of EM square:
4441 * For +ve lfHeight we have
4442 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
4443 * Re-arranging gives:
4444 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4446 * For -ve lfHeight we have
4447 * |lfHeight| = ppem
4448 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4449 * with il = winAscent + winDescent - units_per_em]
4453 if(height > 0) {
4454 USHORT windescent = get_fixed_windescent(pOS2->usWinDescent);
4455 if(pOS2->usWinAscent + windescent == 0)
4456 ppem = MulDiv(ft_face->units_per_EM, height,
4457 pHori->Ascender - pHori->Descender);
4458 else
4459 ppem = MulDiv(ft_face->units_per_EM, height,
4460 pOS2->usWinAscent + windescent);
4461 if(ppem > MAX_PPEM) {
4462 WARN("Ignoring too large height %d, ppem %d\n", height, ppem);
4463 ppem = 1;
4466 else if(height >= -MAX_PPEM)
4467 ppem = -height;
4468 else {
4469 WARN("Ignoring too large height %d\n", height);
4470 ppem = 1;
4473 return ppem;
4476 static struct font_mapping *map_font_file( const char *name )
4478 struct font_mapping *mapping;
4479 struct stat st;
4480 int fd;
4482 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
4483 if (fstat( fd, &st ) == -1) goto error;
4485 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
4487 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
4489 mapping->refcount++;
4490 close( fd );
4491 return mapping;
4494 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
4495 goto error;
4497 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
4498 close( fd );
4500 if (mapping->data == MAP_FAILED)
4502 HeapFree( GetProcessHeap(), 0, mapping );
4503 return NULL;
4505 mapping->refcount = 1;
4506 mapping->dev = st.st_dev;
4507 mapping->ino = st.st_ino;
4508 mapping->size = st.st_size;
4509 list_add_tail( &mappings_list, &mapping->entry );
4510 return mapping;
4512 error:
4513 close( fd );
4514 return NULL;
4517 static void unmap_font_file( struct font_mapping *mapping )
4519 if (!--mapping->refcount)
4521 list_remove( &mapping->entry );
4522 munmap( mapping->data, mapping->size );
4523 HeapFree( GetProcessHeap(), 0, mapping );
4527 static LONG load_VDMX(GdiFont*, LONG);
4529 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
4531 FT_Error err;
4532 FT_Face ft_face;
4533 void *data_ptr;
4534 DWORD data_size;
4536 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
4538 if (face->file)
4540 char *filename = strWtoA( CP_UNIXCP, face->file );
4541 font->mapping = map_font_file( filename );
4542 HeapFree( GetProcessHeap(), 0, filename );
4543 if (!font->mapping)
4545 WARN("failed to map %s\n", debugstr_w(face->file));
4546 return 0;
4548 data_ptr = font->mapping->data;
4549 data_size = font->mapping->size;
4551 else
4553 data_ptr = face->font_data_ptr;
4554 data_size = face->font_data_size;
4557 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
4558 if(err) {
4559 ERR("FT_New_Face rets %d\n", err);
4560 return 0;
4563 /* set it here, as load_VDMX needs it */
4564 font->ft_face = ft_face;
4566 if(FT_IS_SCALABLE(ft_face)) {
4567 FT_ULong len;
4568 DWORD header;
4570 /* load the VDMX table if we have one */
4571 font->ppem = load_VDMX(font, height);
4572 if(font->ppem == 0)
4573 font->ppem = calc_ppem_for_height(ft_face, height);
4574 TRACE("height %d => ppem %d\n", height, font->ppem);
4576 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
4577 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
4579 /* see if it's a TTC */
4580 len = sizeof(header);
4581 if (!pFT_Load_Sfnt_Table(ft_face, 0, 0, (void*)&header, &len)) {
4582 if (header == MS_TTCF_TAG)
4584 len = sizeof(font->ttc_item_offset);
4585 if (pFT_Load_Sfnt_Table(ft_face, 0, (3 + face->face_index) * sizeof(DWORD),
4586 (void*)&font->ttc_item_offset, &len))
4587 font->ttc_item_offset = 0;
4588 else
4589 font->ttc_item_offset = GET_BE_DWORD(font->ttc_item_offset);
4592 } else {
4593 font->ppem = height;
4594 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
4595 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
4597 return ft_face;
4601 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
4603 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4604 a single face with the requested charset. The idea is to check if
4605 the selected font supports the current ANSI codepage, if it does
4606 return the corresponding charset, else return the first charset */
4608 CHARSETINFO csi;
4609 int acp = GetACP(), i;
4610 DWORD fs0;
4612 *cp = acp;
4613 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
4615 const SYSTEM_LINKS *font_link;
4617 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4618 return csi.ciCharset;
4620 font_link = find_font_link(family_name);
4621 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4622 return csi.ciCharset;
4625 for(i = 0; i < 32; i++) {
4626 fs0 = 1L << i;
4627 if(face->fs.fsCsb[0] & fs0) {
4628 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4629 *cp = csi.ciACP;
4630 return csi.ciCharset;
4632 else
4633 FIXME("TCI failing on %x\n", fs0);
4637 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4638 face->fs.fsCsb[0], debugstr_w(face->file));
4639 *cp = acp;
4640 return DEFAULT_CHARSET;
4643 static GdiFont *alloc_font(void)
4645 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4646 ret->refcount = 1;
4647 ret->gmsize = 1;
4648 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4649 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4650 ret->potm = NULL;
4651 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4652 ret->total_kern_pairs = (DWORD)-1;
4653 ret->kern_pairs = NULL;
4654 ret->instance_id = alloc_font_handle(ret);
4655 list_init(&ret->child_fonts);
4656 return ret;
4659 static void free_font(GdiFont *font)
4661 CHILD_FONT *child, *child_next;
4662 DWORD i;
4664 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
4666 list_remove(&child->entry);
4667 if(child->font)
4668 free_font(child->font);
4669 release_face( child->face );
4670 HeapFree(GetProcessHeap(), 0, child);
4673 HeapFree(GetProcessHeap(), 0, font->fileinfo);
4674 free_font_handle(font->instance_id);
4675 if (font->ft_face) pFT_Done_Face(font->ft_face);
4676 if (font->mapping) unmap_font_file( font->mapping );
4677 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4678 HeapFree(GetProcessHeap(), 0, font->potm);
4679 HeapFree(GetProcessHeap(), 0, font->name);
4680 for (i = 0; i < font->gmsize; i++)
4681 HeapFree(GetProcessHeap(),0,font->gm[i]);
4682 HeapFree(GetProcessHeap(), 0, font->gm);
4683 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4684 HeapFree(GetProcessHeap(), 0, font);
4688 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4690 FT_Face ft_face = font->ft_face;
4691 FT_ULong len;
4692 FT_Error err;
4694 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4696 if(!buf)
4697 len = 0;
4698 else
4699 len = cbData;
4701 /* if font is a member of TTC, 'ttcf' tag allows reading from beginning of TTC file,
4702 0 tag means to read from start of collection member data. */
4703 if (font->ttc_item_offset)
4705 if (table == MS_TTCF_TAG)
4706 table = 0;
4707 else if (table == 0)
4708 offset += font->ttc_item_offset;
4711 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4713 /* make sure value of len is the value freetype says it needs */
4714 if (buf && len)
4716 FT_ULong needed = 0;
4717 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4718 if( !err && needed < len) len = needed;
4720 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4721 if (err)
4723 table = RtlUlongByteSwap( table );
4724 TRACE("Can't find table %s\n", debugstr_an((char*)&table, 4));
4725 return GDI_ERROR;
4727 return len;
4730 /*************************************************************
4731 * load_VDMX
4733 * load the vdmx entry for the specified height
4738 typedef struct {
4739 WORD version;
4740 WORD numRecs;
4741 WORD numRatios;
4742 } VDMX_Header;
4744 typedef struct {
4745 BYTE bCharSet;
4746 BYTE xRatio;
4747 BYTE yStartRatio;
4748 BYTE yEndRatio;
4749 } Ratios;
4751 typedef struct {
4752 WORD recs;
4753 BYTE startsz;
4754 BYTE endsz;
4755 } VDMX_group;
4757 typedef struct {
4758 WORD yPelHeight;
4759 WORD yMax;
4760 WORD yMin;
4761 } VDMX_vTable;
4763 static LONG load_VDMX(GdiFont *font, LONG height)
4765 VDMX_Header hdr;
4766 VDMX_group group;
4767 BYTE devXRatio, devYRatio;
4768 USHORT numRecs, numRatios;
4769 DWORD result, offset = -1;
4770 LONG ppem = 0;
4771 int i;
4773 result = get_font_data(font, MS_VDMX_TAG, 0, &hdr, sizeof(hdr));
4775 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4776 return ppem;
4778 /* FIXME: need the real device aspect ratio */
4779 devXRatio = 1;
4780 devYRatio = 1;
4782 numRecs = GET_BE_WORD(hdr.numRecs);
4783 numRatios = GET_BE_WORD(hdr.numRatios);
4785 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr.version), numRecs, numRatios);
4786 for(i = 0; i < numRatios; i++) {
4787 Ratios ratio;
4789 offset = sizeof(hdr) + (i * sizeof(Ratios));
4790 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4791 offset = -1;
4793 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4795 if (!ratio.bCharSet) continue;
4797 if((ratio.xRatio == 0 &&
4798 ratio.yStartRatio == 0 &&
4799 ratio.yEndRatio == 0) ||
4800 (devXRatio == ratio.xRatio &&
4801 devYRatio >= ratio.yStartRatio &&
4802 devYRatio <= ratio.yEndRatio))
4804 WORD group_offset;
4806 offset = sizeof(hdr) + numRatios * sizeof(ratio) + i * sizeof(group_offset);
4807 get_font_data(font, MS_VDMX_TAG, offset, &group_offset, sizeof(group_offset));
4808 offset = GET_BE_WORD(group_offset);
4809 break;
4813 if(offset == -1) return 0;
4815 if(get_font_data(font, MS_VDMX_TAG, offset, &group, sizeof(group)) != GDI_ERROR) {
4816 USHORT recs;
4817 BYTE startsz, endsz;
4818 WORD *vTable;
4820 recs = GET_BE_WORD(group.recs);
4821 startsz = group.startsz;
4822 endsz = group.endsz;
4824 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4826 vTable = HeapAlloc(GetProcessHeap(), 0, recs * sizeof(VDMX_vTable));
4827 result = get_font_data(font, MS_VDMX_TAG, offset + sizeof(group), vTable, recs * sizeof(VDMX_vTable));
4828 if(result == GDI_ERROR) {
4829 FIXME("Failed to retrieve vTable\n");
4830 goto end;
4833 if(height > 0) {
4834 for(i = 0; i < recs; i++) {
4835 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4836 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4837 ppem = GET_BE_WORD(vTable[i * 3]);
4839 if(yMax + -yMin == height) {
4840 font->yMax = yMax;
4841 font->yMin = yMin;
4842 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4843 break;
4845 if(yMax + -yMin > height) {
4846 if(--i < 0) {
4847 ppem = 0;
4848 goto end; /* failed */
4850 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4851 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4852 ppem = GET_BE_WORD(vTable[i * 3]);
4853 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4854 break;
4857 if(!font->yMax) {
4858 ppem = 0;
4859 TRACE("ppem not found for height %d\n", height);
4861 } else {
4862 ppem = -height;
4863 if(ppem < startsz || ppem > endsz)
4865 ppem = 0;
4866 goto end;
4869 for(i = 0; i < recs; i++) {
4870 USHORT yPelHeight;
4871 yPelHeight = GET_BE_WORD(vTable[i * 3]);
4873 if(yPelHeight > ppem)
4875 ppem = 0;
4876 break; /* failed */
4879 if(yPelHeight == ppem) {
4880 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4881 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4882 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
4883 break;
4887 end:
4888 HeapFree(GetProcessHeap(), 0, vTable);
4891 return ppem;
4894 static void dump_gdi_font_list(void)
4896 GdiFont *font;
4898 TRACE("---------- Font Cache ----------\n");
4899 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct tagGdiFont, entry )
4900 TRACE("font=%p ref=%u %s %d\n", font, font->refcount,
4901 debugstr_w(font->font_desc.lf.lfFaceName), font->font_desc.lf.lfHeight);
4904 static void grab_font( GdiFont *font )
4906 if (!font->refcount++)
4908 list_remove( &font->unused_entry );
4909 unused_font_count--;
4913 static void release_font( GdiFont *font )
4915 if (!font) return;
4916 if (!--font->refcount)
4918 TRACE( "font %p\n", font );
4920 /* add it to the unused list */
4921 list_add_head( &unused_gdi_font_list, &font->unused_entry );
4922 if (unused_font_count > UNUSED_CACHE_SIZE)
4924 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct tagGdiFont, unused_entry );
4925 TRACE( "freeing %p\n", font );
4926 list_remove( &font->entry );
4927 list_remove( &font->unused_entry );
4928 free_font( font );
4930 else unused_font_count++;
4932 if (TRACE_ON(font)) dump_gdi_font_list();
4936 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4938 if(font->font_desc.hash != fd->hash) return TRUE;
4939 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4940 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4941 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4942 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4945 static void calc_hash(FONT_DESC *pfd)
4947 DWORD hash = 0, *ptr, two_chars;
4948 WORD *pwc;
4949 unsigned int i;
4951 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4952 hash ^= *ptr;
4953 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4954 hash ^= *ptr;
4955 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4956 two_chars = *ptr;
4957 pwc = (WCHAR *)&two_chars;
4958 if(!*pwc) break;
4959 *pwc = toupperW(*pwc);
4960 pwc++;
4961 *pwc = toupperW(*pwc);
4962 hash ^= two_chars;
4963 if(!*pwc) break;
4965 hash ^= !pfd->can_use_bitmap;
4966 pfd->hash = hash;
4969 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4971 GdiFont *ret;
4972 FONT_DESC fd;
4974 fd.lf = *plf;
4975 fd.matrix = *pmat;
4976 fd.can_use_bitmap = can_use_bitmap;
4977 calc_hash(&fd);
4979 /* try the in-use list */
4980 LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
4982 if(fontcmp(ret, &fd)) continue;
4983 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4984 list_remove( &ret->entry );
4985 list_add_head( &gdi_font_list, &ret->entry );
4986 grab_font( ret );
4987 return ret;
4989 return NULL;
4992 static void add_to_cache(GdiFont *font)
4994 static DWORD cache_num = 1;
4996 font->cache_num = cache_num++;
4997 list_add_head(&gdi_font_list, &font->entry);
4998 TRACE( "font %p\n", font );
5001 /*************************************************************
5002 * create_child_font_list
5004 static BOOL create_child_font_list(GdiFont *font)
5006 BOOL ret = FALSE;
5007 SYSTEM_LINKS *font_link;
5008 CHILD_FONT *font_link_entry, *new_child;
5009 FontSubst *psub;
5010 WCHAR* font_name;
5012 psub = get_font_subst(&font_subst_list, font->name, -1);
5013 font_name = psub ? psub->to.name : font->name;
5014 font_link = find_font_link(font_name);
5015 if (font_link != NULL)
5017 TRACE("found entry in system list\n");
5018 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5020 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
5021 new_child->face = font_link_entry->face;
5022 new_child->font = NULL;
5023 new_child->face->refcount++;
5024 list_add_tail(&font->child_fonts, &new_child->entry);
5025 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
5027 ret = TRUE;
5030 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
5031 * Sans Serif. This is how asian windows get default fallbacks for fonts
5033 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
5034 font->charset != OEM_CHARSET &&
5035 strcmpiW(font_name,szDefaultFallbackLink) != 0)
5037 font_link = find_font_link(szDefaultFallbackLink);
5038 if (font_link != NULL)
5040 TRACE("found entry in default fallback list\n");
5041 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5043 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
5044 new_child->face = font_link_entry->face;
5045 new_child->font = NULL;
5046 new_child->face->refcount++;
5047 list_add_tail(&font->child_fonts, &new_child->entry);
5048 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
5050 ret = TRUE;
5054 return ret;
5057 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
5059 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
5060 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
5061 FT_Int i;
5063 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
5065 for (i = 0; i < ft_face->num_charmaps; i++)
5067 if (ft_face->charmaps[i]->encoding == encoding)
5069 TRACE("found cmap with platform_id %u, encoding_id %u\n",
5070 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
5072 switch (ft_face->charmaps[i]->platform_id)
5074 default:
5075 cmap_def = ft_face->charmaps[i];
5076 break;
5077 case 0: /* Apple Unicode */
5078 cmap0 = ft_face->charmaps[i];
5079 break;
5080 case 1: /* Macintosh */
5081 cmap1 = ft_face->charmaps[i];
5082 break;
5083 case 2: /* ISO */
5084 cmap2 = ft_face->charmaps[i];
5085 break;
5086 case 3: /* Microsoft */
5087 cmap3 = ft_face->charmaps[i];
5088 break;
5092 if (cmap3) /* prefer Microsoft cmap table */
5093 ft_err = pFT_Set_Charmap(ft_face, cmap3);
5094 else if (cmap1)
5095 ft_err = pFT_Set_Charmap(ft_face, cmap1);
5096 else if (cmap2)
5097 ft_err = pFT_Set_Charmap(ft_face, cmap2);
5098 else if (cmap0)
5099 ft_err = pFT_Set_Charmap(ft_face, cmap0);
5100 else if (cmap_def)
5101 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
5104 return ft_err == FT_Err_Ok;
5108 /*************************************************************
5109 * freetype_CreateDC
5111 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
5112 LPCWSTR output, const DEVMODEW *devmode )
5114 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
5116 if (!physdev) return FALSE;
5117 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
5118 return TRUE;
5122 /*************************************************************
5123 * freetype_DeleteDC
5125 static BOOL freetype_DeleteDC( PHYSDEV dev )
5127 struct freetype_physdev *physdev = get_freetype_dev( dev );
5128 release_font( physdev->font );
5129 HeapFree( GetProcessHeap(), 0, physdev );
5130 return TRUE;
5133 static FT_Encoding pick_charmap( FT_Face face, int charset )
5135 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
5136 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
5137 const FT_Encoding *encs = regular_order;
5139 if (charset == SYMBOL_CHARSET) encs = symbol_order;
5141 while (*encs != 0)
5143 if (select_charmap( face, *encs )) break;
5144 encs++;
5147 if (!face->charmap && face->num_charmaps)
5149 if (!pFT_Set_Charmap(face, face->charmaps[0]))
5150 return face->charmap->encoding;
5153 return *encs;
5156 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
5158 DWORD size;
5159 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
5160 WORD *alloced = NULL, *ptr = buf;
5161 WORD num_recs, version;
5162 BOOL ret = FALSE;
5164 *flags = 0;
5165 size = get_font_data( font, MS_GASP_TAG, 0, NULL, 0 );
5166 if (size == GDI_ERROR) return FALSE;
5167 if (size < 4 * sizeof(WORD)) return FALSE;
5168 if (size > sizeof(buf))
5170 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
5171 if (!ptr) return FALSE;
5174 get_font_data( font, MS_GASP_TAG, 0, ptr, size );
5176 version = GET_BE_WORD( *ptr++ );
5177 num_recs = GET_BE_WORD( *ptr++ );
5179 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
5181 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
5182 goto done;
5185 while (num_recs--)
5187 *flags = GET_BE_WORD( *(ptr + 1) );
5188 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
5189 ptr += 2;
5191 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
5192 ret = TRUE;
5194 done:
5195 HeapFree( GetProcessHeap(), 0, alloced );
5196 return ret;
5199 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5201 const GSUB_ScriptList *script;
5202 const GSUB_Script *deflt = NULL;
5203 int i;
5204 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5206 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5207 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5209 const GSUB_Script *scr;
5210 int offset;
5212 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5213 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5215 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5216 return scr;
5217 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5218 deflt = scr;
5220 return deflt;
5223 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5225 int i;
5226 int offset;
5227 const GSUB_LangSys *Lang;
5229 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5231 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5233 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5234 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5236 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5237 return Lang;
5239 offset = GET_BE_WORD(script->DefaultLangSys);
5240 if (offset)
5242 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5243 return Lang;
5245 return NULL;
5248 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5250 int i;
5251 const GSUB_FeatureList *feature;
5252 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5254 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5255 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5257 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5258 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5260 const GSUB_Feature *feat;
5261 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5262 return feat;
5265 return NULL;
5268 static const char* get_opentype_script(const GdiFont *font)
5271 * I am not sure if this is the correct way to generate our script tag
5274 switch (font->charset)
5276 case ANSI_CHARSET: return "latn";
5277 case BALTIC_CHARSET: return "latn"; /* ?? */
5278 case CHINESEBIG5_CHARSET: return "hani";
5279 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5280 case GB2312_CHARSET: return "hani";
5281 case GREEK_CHARSET: return "grek";
5282 case HANGUL_CHARSET: return "hang";
5283 case RUSSIAN_CHARSET: return "cyrl";
5284 case SHIFTJIS_CHARSET: return "kana";
5285 case TURKISH_CHARSET: return "latn"; /* ?? */
5286 case VIETNAMESE_CHARSET: return "latn";
5287 case JOHAB_CHARSET: return "latn"; /* ?? */
5288 case ARABIC_CHARSET: return "arab";
5289 case HEBREW_CHARSET: return "hebr";
5290 case THAI_CHARSET: return "thai";
5291 default: return "latn";
5295 static const VOID * get_GSUB_vert_feature(const GdiFont *font)
5297 const GSUB_Header *header;
5298 const GSUB_Script *script;
5299 const GSUB_LangSys *language;
5300 const GSUB_Feature *feature;
5302 if (!font->GSUB_Table)
5303 return NULL;
5305 header = font->GSUB_Table;
5307 script = GSUB_get_script_table(header, get_opentype_script(font));
5308 if (!script)
5310 TRACE("Script not found\n");
5311 return NULL;
5313 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5314 if (!language)
5316 TRACE("Language not found\n");
5317 return NULL;
5319 feature = GSUB_get_feature(header, language, "vrt2");
5320 if (!feature)
5321 feature = GSUB_get_feature(header, language, "vert");
5322 if (!feature)
5324 TRACE("vrt2/vert feature not found\n");
5325 return NULL;
5327 return feature;
5330 static void fill_fileinfo_from_face( GdiFont *font, Face *face )
5332 WIN32_FILE_ATTRIBUTE_DATA info;
5333 int len;
5335 if (!face->file)
5337 font->fileinfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*font->fileinfo));
5338 return;
5341 len = strlenW(face->file);
5342 font->fileinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*font->fileinfo) + len * sizeof(WCHAR));
5343 if (GetFileAttributesExW(face->file, GetFileExInfoStandard, &info))
5345 font->fileinfo->writetime = info.ftLastWriteTime;
5346 font->fileinfo->size.QuadPart = (LONGLONG)info.nFileSizeHigh << 32 | info.nFileSizeLow;
5347 strcpyW(font->fileinfo->path, face->file);
5349 else
5350 memset(font->fileinfo, 0, sizeof(*font->fileinfo) + len * sizeof(WCHAR));
5353 /*************************************************************
5354 * freetype_SelectFont
5356 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
5358 struct freetype_physdev *physdev = get_freetype_dev( dev );
5359 GdiFont *ret;
5360 Face *face, *best, *best_bitmap;
5361 Family *family, *last_resort_family;
5362 const struct list *face_list;
5363 INT height, width = 0;
5364 unsigned int score = 0, new_score;
5365 signed int diff = 0, newdiff;
5366 BOOL bd, it, can_use_bitmap, want_vertical;
5367 LOGFONTW lf;
5368 CHARSETINFO csi;
5369 FMAT2 dcmat;
5370 FontSubst *psub = NULL;
5371 DC *dc = get_physdev_dc( dev );
5372 const SYSTEM_LINKS *font_link;
5374 if (!hfont) /* notification that the font has been changed by another driver */
5376 release_font( physdev->font );
5377 physdev->font = NULL;
5378 return 0;
5381 GetObjectW( hfont, sizeof(lf), &lf );
5382 lf.lfWidth = abs(lf.lfWidth);
5384 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
5386 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
5387 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
5388 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
5389 lf.lfEscapement);
5391 if(dc->GraphicsMode == GM_ADVANCED)
5393 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
5394 /* Try to avoid not necessary glyph transformations */
5395 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
5397 lf.lfHeight *= fabs(dcmat.eM11);
5398 lf.lfWidth *= fabs(dcmat.eM11);
5399 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
5402 else
5404 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
5405 font scaling abilities. */
5406 dcmat.eM11 = dcmat.eM22 = 1.0;
5407 dcmat.eM21 = dcmat.eM12 = 0;
5408 lf.lfOrientation = lf.lfEscapement;
5409 if (dc->vport2WorldValid)
5411 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
5412 lf.lfOrientation = -lf.lfOrientation;
5413 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
5414 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
5418 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
5419 dcmat.eM21, dcmat.eM22);
5421 GDI_CheckNotLock();
5422 EnterCriticalSection( &freetype_cs );
5424 /* check the cache first */
5425 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5426 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
5427 goto done;
5430 TRACE("not in cache\n");
5431 ret = alloc_font();
5433 ret->font_desc.matrix = dcmat;
5434 ret->font_desc.lf = lf;
5435 ret->font_desc.can_use_bitmap = can_use_bitmap;
5436 calc_hash(&ret->font_desc);
5438 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
5439 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
5440 original value lfCharSet. Note this is a special case for
5441 Symbol and doesn't happen at least for "Wingdings*" */
5443 if(!strcmpiW(lf.lfFaceName, SymbolW))
5444 lf.lfCharSet = SYMBOL_CHARSET;
5446 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
5447 switch(lf.lfCharSet) {
5448 case DEFAULT_CHARSET:
5449 csi.fs.fsCsb[0] = 0;
5450 break;
5451 default:
5452 FIXME("Untranslated charset %d\n", lf.lfCharSet);
5453 csi.fs.fsCsb[0] = 0;
5454 break;
5458 family = NULL;
5459 if(lf.lfFaceName[0] != '\0') {
5460 CHILD_FONT *font_link_entry;
5461 LPWSTR FaceName = lf.lfFaceName;
5463 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
5465 if(psub) {
5466 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
5467 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
5468 if (psub->to.charset != -1)
5469 lf.lfCharSet = psub->to.charset;
5472 /* We want a match on name and charset or just name if
5473 charset was DEFAULT_CHARSET. If the latter then
5474 we fixup the returned charset later in get_nearest_charset
5475 where we'll either use the charset of the current ansi codepage
5476 or if that's unavailable the first charset that the font supports.
5478 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5479 if (!strcmpiW(family->FamilyName, FaceName) ||
5480 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
5482 font_link = find_font_link(family->FamilyName);
5483 face_list = get_face_list_from_family(family);
5484 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5485 if (!(face->scalable || can_use_bitmap))
5486 continue;
5487 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5488 goto found;
5489 if (font_link != NULL &&
5490 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5491 goto found;
5492 if (!csi.fs.fsCsb[0])
5493 goto found;
5498 /* Search by full face name. */
5499 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5500 face_list = get_face_list_from_family(family);
5501 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5502 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
5503 (face->scalable || can_use_bitmap))
5505 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5506 goto found_face;
5507 font_link = find_font_link(family->FamilyName);
5508 if (font_link != NULL &&
5509 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5510 goto found_face;
5516 * Try check the SystemLink list first for a replacement font.
5517 * We may find good replacements there.
5519 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
5521 if(!strcmpiW(font_link->font_name, FaceName) ||
5522 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
5524 TRACE("found entry in system list\n");
5525 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5527 const SYSTEM_LINKS *links;
5529 face = font_link_entry->face;
5530 if (!(face->scalable || can_use_bitmap))
5531 continue;
5532 family = face->family;
5533 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5534 goto found;
5535 links = find_font_link(family->FamilyName);
5536 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
5537 goto found;
5543 psub = NULL; /* substitution is no more relevant */
5545 /* If requested charset was DEFAULT_CHARSET then try using charset
5546 corresponding to the current ansi codepage */
5547 if (!csi.fs.fsCsb[0])
5549 INT acp = GetACP();
5550 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
5551 FIXME("TCI failed on codepage %d\n", acp);
5552 csi.fs.fsCsb[0] = 0;
5553 } else
5554 lf.lfCharSet = csi.ciCharset;
5557 want_vertical = (lf.lfFaceName[0] == '@');
5559 /* Face families are in the top 4 bits of lfPitchAndFamily,
5560 so mask with 0xF0 before testing */
5562 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
5563 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
5564 strcpyW(lf.lfFaceName, defFixed);
5565 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
5566 strcpyW(lf.lfFaceName, defSerif);
5567 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
5568 strcpyW(lf.lfFaceName, defSans);
5569 else
5570 strcpyW(lf.lfFaceName, defSans);
5571 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5572 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
5573 font_link = find_font_link(family->FamilyName);
5574 face_list = get_face_list_from_family(family);
5575 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5576 if (!(face->scalable || can_use_bitmap))
5577 continue;
5578 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5579 goto found;
5580 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5581 goto found;
5586 last_resort_family = NULL;
5587 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5588 font_link = find_font_link(family->FamilyName);
5589 face_list = get_face_list_from_family(family);
5590 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5591 if(!(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical &&
5592 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5593 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
5594 if(face->scalable)
5595 goto found;
5596 if(can_use_bitmap && !last_resort_family)
5597 last_resort_family = family;
5602 if(last_resort_family) {
5603 family = last_resort_family;
5604 csi.fs.fsCsb[0] = 0;
5605 goto found;
5608 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5609 face_list = get_face_list_from_family(family);
5610 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5611 if(face->scalable && !(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical) {
5612 csi.fs.fsCsb[0] = 0;
5613 WARN("just using first face for now\n");
5614 goto found;
5616 if(can_use_bitmap && !last_resort_family)
5617 last_resort_family = family;
5620 if(!last_resort_family) {
5621 FIXME("can't find a single appropriate font - bailing\n");
5622 free_font(ret);
5623 ret = NULL;
5624 goto done;
5627 WARN("could only find a bitmap font - this will probably look awful!\n");
5628 family = last_resort_family;
5629 csi.fs.fsCsb[0] = 0;
5631 found:
5632 it = lf.lfItalic ? 1 : 0;
5633 bd = lf.lfWeight > 550 ? 1 : 0;
5635 height = lf.lfHeight;
5637 face = best = best_bitmap = NULL;
5638 font_link = find_font_link(family->FamilyName);
5639 face_list = get_face_list_from_family(family);
5640 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5642 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5643 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
5644 !csi.fs.fsCsb[0])
5646 BOOL italic, bold;
5648 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
5649 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
5650 new_score = (italic ^ it) + (bold ^ bd);
5651 if(!best || new_score <= score)
5653 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5654 italic, bold, it, bd);
5655 score = new_score;
5656 best = face;
5657 if(best->scalable && score == 0) break;
5658 if(!best->scalable)
5660 if(height > 0)
5661 newdiff = height - (signed int)(best->size.height);
5662 else
5663 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
5664 if(!best_bitmap || new_score < score ||
5665 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
5667 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
5668 diff = newdiff;
5669 best_bitmap = best;
5670 if(score == 0 && diff == 0) break;
5676 if(best)
5677 face = best->scalable ? best : best_bitmap;
5678 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
5679 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
5681 found_face:
5682 height = lf.lfHeight;
5684 ret->fs = face->fs;
5686 if(csi.fs.fsCsb[0]) {
5687 ret->charset = lf.lfCharSet;
5688 ret->codepage = csi.ciACP;
5690 else
5691 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
5693 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
5694 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
5696 ret->aveWidth = height ? lf.lfWidth : 0;
5698 if(!face->scalable) {
5699 /* Windows uses integer scaling factors for bitmap fonts */
5700 INT scale, scaled_height;
5701 GdiFont *cachedfont;
5703 /* FIXME: rotation of bitmap fonts is ignored */
5704 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
5705 if (ret->aveWidth)
5706 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
5707 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
5708 dcmat.eM11 = dcmat.eM22 = 1.0;
5709 /* As we changed the matrix, we need to search the cache for the font again,
5710 * otherwise we might explode the cache. */
5711 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5712 TRACE("Found cached font after non-scalable matrix rescale!\n");
5713 free_font( ret );
5714 ret = cachedfont;
5715 goto done;
5717 calc_hash(&ret->font_desc);
5719 if (height != 0) height = diff;
5720 height += face->size.height;
5722 scale = (height + face->size.height - 1) / face->size.height;
5723 scaled_height = scale * face->size.height;
5724 /* Only jump to the next height if the difference <= 25% original height */
5725 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
5726 /* The jump between unscaled and doubled is delayed by 1 */
5727 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
5728 ret->scale_y = scale;
5730 width = face->size.x_ppem >> 6;
5731 height = face->size.y_ppem >> 6;
5733 else
5734 ret->scale_y = 1.0;
5735 TRACE("font scale y: %f\n", ret->scale_y);
5737 ret->ft_face = OpenFontFace(ret, face, width, height);
5739 if (!ret->ft_face)
5741 free_font( ret );
5742 ret = NULL;
5743 goto done;
5746 fill_fileinfo_from_face( ret, face );
5747 ret->ntmFlags = face->ntmFlags;
5749 pick_charmap( ret->ft_face, ret->charset );
5751 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
5752 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
5753 ret->underline = lf.lfUnderline ? 0xff : 0;
5754 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
5755 create_child_font_list(ret);
5757 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
5759 int length = get_font_data(ret, MS_GSUB_TAG , 0, NULL, 0);
5760 if (length != GDI_ERROR)
5762 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
5763 get_font_data(ret, MS_GSUB_TAG , 0, ret->GSUB_Table, length);
5764 TRACE("Loaded GSUB table of %i bytes\n",length);
5765 ret->vert_feature = get_GSUB_vert_feature(ret);
5766 if (!ret->vert_feature)
5768 TRACE("Vertical feature not found\n");
5769 HeapFree(GetProcessHeap(), 0, ret->GSUB_Table);
5770 ret->GSUB_Table = NULL;
5774 ret->aa_flags = HIWORD( face->flags );
5776 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
5778 add_to_cache(ret);
5779 done:
5780 if (ret)
5782 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
5784 switch (lf.lfQuality)
5786 case NONANTIALIASED_QUALITY:
5787 case ANTIALIASED_QUALITY:
5788 next->funcs->pSelectFont( dev, hfont, aa_flags );
5789 break;
5790 case CLEARTYPE_QUALITY:
5791 case CLEARTYPE_NATURAL_QUALITY:
5792 default:
5793 if (!*aa_flags) *aa_flags = ret->aa_flags;
5794 next->funcs->pSelectFont( dev, hfont, aa_flags );
5796 /* fixup the antialiasing flags for that font */
5797 switch (*aa_flags)
5799 case WINE_GGO_HRGB_BITMAP:
5800 case WINE_GGO_HBGR_BITMAP:
5801 case WINE_GGO_VRGB_BITMAP:
5802 case WINE_GGO_VBGR_BITMAP:
5803 if (is_subpixel_rendering_enabled()) break;
5804 *aa_flags = GGO_GRAY4_BITMAP;
5805 /* fall through */
5806 case GGO_GRAY2_BITMAP:
5807 case GGO_GRAY4_BITMAP:
5808 case GGO_GRAY8_BITMAP:
5809 case WINE_GGO_GRAY16_BITMAP:
5810 if ((!antialias_fakes || (!ret->fake_bold && !ret->fake_italic)) && is_hinting_enabled())
5812 WORD gasp_flags;
5813 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
5815 TRACE( "font %s %d aa disabled by GASP\n",
5816 debugstr_w(lf.lfFaceName), lf.lfHeight );
5817 *aa_flags = GGO_BITMAP;
5822 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5823 release_font( physdev->font );
5824 physdev->font = ret;
5826 LeaveCriticalSection( &freetype_cs );
5827 return ret ? hfont : 0;
5830 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5832 HRSRC rsrc;
5833 HGLOBAL hMem;
5834 WCHAR *p;
5835 int i;
5837 id += IDS_FIRST_SCRIPT;
5838 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5839 if (!rsrc) return 0;
5840 hMem = LoadResource( gdi32_module, rsrc );
5841 if (!hMem) return 0;
5843 p = LockResource( hMem );
5844 id &= 0x000f;
5845 while (id--) p += *p + 1;
5847 i = min(LF_FACESIZE - 1, *p);
5848 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5849 buffer[i] = 0;
5850 return i;
5853 static inline BOOL is_complex_script_ansi_cp(UINT ansi_cp)
5855 return (ansi_cp == 874 /* Thai */
5856 || ansi_cp == 1255 /* Hebrew */
5857 || ansi_cp == 1256 /* Arabic */
5861 /***************************************************
5862 * create_enum_charset_list
5864 * This function creates charset enumeration list because in DEFAULT_CHARSET
5865 * case, the ANSI codepage's charset takes precedence over other charsets.
5866 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
5867 * This function works as a filter other than DEFAULT_CHARSET case.
5869 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5871 CHARSETINFO csi;
5872 DWORD n = 0;
5874 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5875 csi.fs.fsCsb[0] != 0) {
5876 list->element[n].mask = csi.fs.fsCsb[0];
5877 list->element[n].charset = csi.ciCharset;
5878 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5879 n++;
5881 else { /* charset is DEFAULT_CHARSET or invalid. */
5882 INT acp, i;
5883 DWORD mask = 0;
5885 /* Set the current codepage's charset as the first element. */
5886 acp = GetACP();
5887 if (!is_complex_script_ansi_cp(acp) &&
5888 TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5889 csi.fs.fsCsb[0] != 0) {
5890 list->element[n].mask = csi.fs.fsCsb[0];
5891 list->element[n].charset = csi.ciCharset;
5892 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5893 mask |= csi.fs.fsCsb[0];
5894 n++;
5897 /* Fill out left elements. */
5898 for (i = 0; i < 32; i++) {
5899 FONTSIGNATURE fs;
5900 fs.fsCsb[0] = 1L << i;
5901 fs.fsCsb[1] = 0;
5902 if (fs.fsCsb[0] & mask)
5903 continue; /* skip, already added. */
5904 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5905 continue; /* skip, this is an invalid fsCsb bit. */
5907 list->element[n].mask = fs.fsCsb[0];
5908 list->element[n].charset = csi.ciCharset;
5909 load_script_name( i, list->element[n].name );
5910 mask |= fs.fsCsb[0];
5911 n++;
5914 /* add catch all mask for remaining bits */
5915 if (~mask)
5917 list->element[n].mask = ~mask;
5918 list->element[n].charset = DEFAULT_CHARSET;
5919 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5920 n++;
5923 list->total = n;
5925 return n;
5928 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
5929 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5931 GdiFont *font;
5932 LONG width, height;
5934 if (face->cached_enum_data)
5936 TRACE("Cached\n");
5937 *pelf = face->cached_enum_data->elf;
5938 *pntm = face->cached_enum_data->ntm;
5939 *ptype = face->cached_enum_data->type;
5940 return;
5943 font = alloc_font();
5945 if(face->scalable) {
5946 height = 100;
5947 width = 0;
5948 } else {
5949 height = face->size.y_ppem >> 6;
5950 width = face->size.x_ppem >> 6;
5952 font->scale_y = 1.0;
5954 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5956 free_font(font);
5957 return;
5960 font->name = strdupW( family_name );
5961 font->ntmFlags = face->ntmFlags;
5963 if (get_outline_text_metrics(font))
5965 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5967 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5968 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5969 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5971 lstrcpynW(pelf->elfLogFont.lfFaceName,
5972 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5973 LF_FACESIZE);
5974 lstrcpynW(pelf->elfFullName,
5975 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5976 LF_FULLFACESIZE);
5977 lstrcpynW(pelf->elfStyle,
5978 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5979 LF_FACESIZE);
5981 else
5983 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5985 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5986 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5987 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5989 lstrcpynW(pelf->elfLogFont.lfFaceName, family_name, LF_FACESIZE);
5990 if (face->FullName)
5991 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5992 else
5993 lstrcpynW(pelf->elfFullName, family_name, LF_FULLFACESIZE);
5994 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5997 pntm->ntmTm.ntmFlags = face->ntmFlags;
5998 pntm->ntmFontSig = face->fs;
6000 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
6002 pelf->elfLogFont.lfEscapement = 0;
6003 pelf->elfLogFont.lfOrientation = 0;
6004 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
6005 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
6006 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
6007 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
6008 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
6009 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
6010 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
6011 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
6012 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
6013 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
6014 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
6016 *ptype = 0;
6017 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
6018 *ptype |= TRUETYPE_FONTTYPE;
6019 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
6020 *ptype |= DEVICE_FONTTYPE;
6021 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
6022 *ptype |= RASTER_FONTTYPE;
6024 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
6025 if (face->cached_enum_data)
6027 face->cached_enum_data->elf = *pelf;
6028 face->cached_enum_data->ntm = *pntm;
6029 face->cached_enum_data->type = *ptype;
6032 free_font(font);
6035 static BOOL family_matches(Family *family, const WCHAR *face_name)
6037 Face *face;
6038 const struct list *face_list;
6040 if (!strcmpiW(face_name, family->FamilyName)) return TRUE;
6042 face_list = get_face_list_from_family(family);
6043 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
6044 if (face->FullName && !strcmpiW(face_name, face->FullName)) return TRUE;
6046 return FALSE;
6049 static BOOL face_matches(const WCHAR *family_name, Face *face, const WCHAR *face_name)
6051 if (!strcmpiW(face_name, family_name)) return TRUE;
6053 return (face->FullName && !strcmpiW(face_name, face->FullName));
6056 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
6057 FONTENUMPROCW proc, LPARAM lparam, const WCHAR *subst)
6059 ENUMLOGFONTEXW elf;
6060 NEWTEXTMETRICEXW ntm;
6061 DWORD type = 0;
6062 DWORD i;
6064 GetEnumStructs(face, face->family->FamilyName, &elf, &ntm, &type);
6065 for(i = 0; i < list->total; i++) {
6066 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
6067 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
6068 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
6069 i = list->total; /* break out of loop after enumeration */
6071 else
6073 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
6074 /* use the DEFAULT_CHARSET case only if no other charset is present */
6075 if (list->element[i].charset == DEFAULT_CHARSET &&
6076 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
6077 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
6078 strcpyW(elf.elfScript, list->element[i].name);
6079 if (!elf.elfScript[0])
6080 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
6082 /* Font Replacement */
6083 if (family != face->family)
6085 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
6086 if (face->FullName)
6087 strcpyW(elf.elfFullName, face->FullName);
6088 else
6089 strcpyW(elf.elfFullName, family->FamilyName);
6091 if (subst)
6092 strcpyW(elf.elfLogFont.lfFaceName, subst);
6093 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
6094 debugstr_w(elf.elfLogFont.lfFaceName),
6095 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
6096 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
6097 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
6098 ntm.ntmTm.ntmFlags);
6099 /* release section before callback (FIXME) */
6100 LeaveCriticalSection( &freetype_cs );
6101 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
6102 EnterCriticalSection( &freetype_cs );
6104 return TRUE;
6107 /*************************************************************
6108 * freetype_EnumFonts
6110 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
6112 Family *family;
6113 Face *face;
6114 const struct list *face_list;
6115 LOGFONTW lf;
6116 struct enum_charset_list enum_charsets;
6118 if (!plf)
6120 lf.lfCharSet = DEFAULT_CHARSET;
6121 lf.lfPitchAndFamily = 0;
6122 lf.lfFaceName[0] = 0;
6123 plf = &lf;
6126 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
6128 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
6130 GDI_CheckNotLock();
6131 EnterCriticalSection( &freetype_cs );
6132 if(plf->lfFaceName[0]) {
6133 WCHAR *face_name = plf->lfFaceName;
6134 FontSubst *psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
6136 if(psub) {
6137 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
6138 debugstr_w(psub->to.name));
6139 face_name = psub->to.name;
6142 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
6143 if (!family_matches(family, face_name)) continue;
6144 face_list = get_face_list_from_family(family);
6145 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
6146 if (!face_matches(family->FamilyName, face, face_name)) continue;
6147 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam, psub ? psub->from.name : NULL)) return FALSE;
6150 } else {
6151 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
6152 face_list = get_face_list_from_family(family);
6153 face = LIST_ENTRY(list_head(face_list), Face, entry);
6154 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam, NULL)) return FALSE;
6157 LeaveCriticalSection( &freetype_cs );
6158 return TRUE;
6161 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
6163 pt->x.value = vec->x >> 6;
6164 pt->x.fract = (vec->x & 0x3f) << 10;
6165 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
6166 pt->y.value = vec->y >> 6;
6167 pt->y.fract = (vec->y & 0x3f) << 10;
6168 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
6171 /***************************************************
6172 * According to the MSDN documentation on WideCharToMultiByte,
6173 * certain codepages cannot set the default_used parameter.
6174 * This returns TRUE if the codepage can set that parameter, false else
6175 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
6177 static BOOL codepage_sets_default_used(UINT codepage)
6179 switch (codepage)
6181 case CP_UTF7:
6182 case CP_UTF8:
6183 case CP_SYMBOL:
6184 return FALSE;
6185 default:
6186 return TRUE;
6191 * GSUB Table handling functions
6194 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
6196 const GSUB_CoverageFormat1* cf1;
6198 cf1 = table;
6200 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
6202 int count = GET_BE_WORD(cf1->GlyphCount);
6203 int i;
6204 TRACE("Coverage Format 1, %i glyphs\n",count);
6205 for (i = 0; i < count; i++)
6206 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
6207 return i;
6208 return -1;
6210 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
6212 const GSUB_CoverageFormat2* cf2;
6213 int i;
6214 int count;
6215 cf2 = (const GSUB_CoverageFormat2*)cf1;
6217 count = GET_BE_WORD(cf2->RangeCount);
6218 TRACE("Coverage Format 2, %i ranges\n",count);
6219 for (i = 0; i < count; i++)
6221 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
6222 return -1;
6223 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
6224 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
6226 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
6227 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
6230 return -1;
6232 else
6233 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
6235 return -1;
6238 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
6240 int i;
6241 int offset;
6242 const GSUB_LookupList *lookup;
6243 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
6245 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
6246 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
6248 const GSUB_LookupTable *look;
6249 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
6250 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
6251 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
6252 if (GET_BE_WORD(look->LookupType) != 1)
6253 FIXME("We only handle SubType 1\n");
6254 else
6256 int j;
6258 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
6260 const GSUB_SingleSubstFormat1 *ssf1;
6261 offset = GET_BE_WORD(look->SubTable[j]);
6262 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
6263 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
6265 int offset = GET_BE_WORD(ssf1->Coverage);
6266 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
6267 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
6269 TRACE(" Glyph 0x%x ->",glyph);
6270 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
6271 TRACE(" 0x%x\n",glyph);
6274 else
6276 const GSUB_SingleSubstFormat2 *ssf2;
6277 INT index;
6278 INT offset;
6280 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
6281 offset = GET_BE_WORD(ssf1->Coverage);
6282 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
6283 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
6284 TRACE(" Coverage index %i\n",index);
6285 if (index != -1)
6287 TRACE(" Glyph is 0x%x ->",glyph);
6288 glyph = GET_BE_WORD(ssf2->Substitute[index]);
6289 TRACE("0x%x\n",glyph);
6295 return glyph;
6299 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
6301 const GSUB_Header *header;
6302 const GSUB_Feature *feature;
6304 if (!font->GSUB_Table)
6305 return glyph;
6307 header = font->GSUB_Table;
6308 feature = font->vert_feature;
6310 return GSUB_apply_feature(header, feature, glyph);
6313 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
6315 FT_UInt glyphId;
6317 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
6318 WCHAR wc = (WCHAR)glyph;
6319 BOOL default_used;
6320 BOOL *default_used_pointer;
6321 FT_UInt ret;
6322 char buf;
6323 default_used_pointer = NULL;
6324 default_used = FALSE;
6325 if (codepage_sets_default_used(font->codepage))
6326 default_used_pointer = &default_used;
6327 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
6329 if (font->codepage == CP_SYMBOL && wc < 0x100)
6330 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
6331 else
6332 ret = 0;
6334 else
6335 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
6336 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6337 return ret;
6340 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
6342 if (glyph < 0x100) glyph += 0xf000;
6343 /* there is a number of old pre-Unicode "broken" TTFs, which
6344 do have symbols at U+00XX instead of U+f0XX */
6345 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
6346 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
6348 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
6350 return glyphId;
6353 /* helper for freetype_GetGlyphIndices */
6354 static FT_UInt get_gdi_glyph_index(const GdiFont *font, UINT glyph)
6356 WCHAR wc = (WCHAR)glyph;
6357 BOOL default_used = FALSE;
6358 BOOL *default_used_pointer = NULL;
6359 FT_UInt ret;
6360 char buf;
6362 if(font->ft_face->charmap->encoding != FT_ENCODING_NONE)
6363 return get_glyph_index(font, glyph);
6365 if (codepage_sets_default_used(font->codepage))
6366 default_used_pointer = &default_used;
6367 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer)
6368 || default_used)
6370 if (font->codepage == CP_SYMBOL && wc < 0x100)
6371 ret = (unsigned char)wc;
6372 else
6373 ret = 0;
6375 else
6376 ret = (unsigned char)buf;
6377 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6378 return ret;
6381 static FT_UInt get_default_char_index(GdiFont *font)
6383 FT_UInt default_char;
6385 if (FT_IS_SFNT(font->ft_face))
6387 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
6388 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
6390 else
6392 TEXTMETRICW textm;
6393 get_text_metrics(font, &textm);
6394 default_char = textm.tmDefaultChar;
6397 return default_char;
6400 /*************************************************************
6401 * freetype_GetGlyphIndices
6403 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
6405 struct freetype_physdev *physdev = get_freetype_dev( dev );
6406 int i;
6407 WORD default_char;
6408 BOOL got_default = FALSE;
6410 if (!physdev->font)
6412 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
6413 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
6416 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
6418 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
6419 got_default = TRUE;
6422 GDI_CheckNotLock();
6423 EnterCriticalSection( &freetype_cs );
6425 for(i = 0; i < count; i++)
6427 pgi[i] = get_gdi_glyph_index(physdev->font, lpstr[i]);
6428 if (pgi[i] == 0)
6430 if (!got_default)
6432 default_char = get_default_char_index(physdev->font);
6433 got_default = TRUE;
6435 pgi[i] = default_char;
6437 else
6438 pgi[i] = get_GSUB_vert_glyph(physdev->font, pgi[i]);
6440 LeaveCriticalSection( &freetype_cs );
6441 return count;
6444 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
6446 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
6447 return !memcmp(matrix, &identity, sizeof(FMAT2));
6450 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
6452 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
6453 return !memcmp(matrix, &identity, sizeof(MAT2));
6456 static inline FT_Vector normalize_vector(FT_Vector *vec)
6458 FT_Vector out;
6459 FT_Fixed len;
6460 len = pFT_Vector_Length(vec);
6461 if (len) {
6462 out.x = (vec->x << 6) / len;
6463 out.y = (vec->y << 6) / len;
6465 else
6466 out.x = out.y = 0;
6467 return out;
6470 static BOOL get_bold_glyph_outline(FT_GlyphSlot glyph, LONG ppem, FT_Glyph_Metrics *metrics)
6472 FT_Error err;
6473 FT_Pos strength;
6474 FT_BBox bbox;
6476 if(glyph->format != FT_GLYPH_FORMAT_OUTLINE)
6477 return FALSE;
6478 if(!pFT_Outline_Embolden)
6479 return FALSE;
6481 strength = MulDiv(ppem, 1 << 6, 24);
6482 err = pFT_Outline_Embolden(&glyph->outline, strength);
6483 if(err) {
6484 TRACE("FT_Ouline_Embolden returns %d\n", err);
6485 return FALSE;
6488 pFT_Outline_Get_CBox(&glyph->outline, &bbox);
6489 metrics->width = bbox.xMax - bbox.xMin;
6490 metrics->height = bbox.yMax - bbox.yMin;
6491 metrics->horiBearingX = bbox.xMin;
6492 metrics->horiBearingY = bbox.yMax;
6493 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
6494 metrics->vertBearingY = (metrics->vertAdvance - metrics->height) / 2;
6495 return TRUE;
6498 static inline BYTE get_max_level( UINT format )
6500 switch( format )
6502 case GGO_GRAY2_BITMAP: return 4;
6503 case GGO_GRAY4_BITMAP: return 16;
6504 case GGO_GRAY8_BITMAP: return 64;
6506 return 255;
6509 extern const unsigned short vertical_orientation_table[] DECLSPEC_HIDDEN;
6511 static BOOL check_unicode_tategaki(WCHAR uchar)
6513 unsigned short orientation = vertical_orientation_table[vertical_orientation_table[vertical_orientation_table[uchar >> 8]+((uchar >> 4) & 0x0f)]+ (uchar & 0xf)];
6515 /* We only reach this code if typographical substitution did not occur */
6516 /* Type: U or Type: Tu */
6517 return (orientation == 1 || orientation == 3);
6520 static FT_Vector get_advance_metric(GdiFont *incoming_font, GdiFont *font,
6521 const FT_Glyph_Metrics *metrics,
6522 const FT_Matrix *transMat, BOOL vertical_metrics)
6524 FT_Vector adv;
6525 FT_Fixed base_advance, em_scale = 0;
6526 BOOL fixed_pitch_full = FALSE;
6528 if (vertical_metrics)
6529 base_advance = metrics->vertAdvance;
6530 else
6531 base_advance = metrics->horiAdvance;
6533 adv.x = base_advance;
6534 adv.y = 0;
6536 /* In fixed-pitch font, we adjust the fullwidth character advance so that
6537 they have double halfwidth character width. E.g. if the font is 19 ppem,
6538 we return 20 (not 19) for fullwidth characters as we return 10 for
6539 halfwidth characters. */
6540 if(FT_IS_SCALABLE(incoming_font->ft_face) &&
6541 (incoming_font->potm || get_outline_text_metrics(incoming_font)) &&
6542 !(incoming_font->potm->otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
6543 UINT avg_advance;
6544 em_scale = MulDiv(incoming_font->ppem, 1 << 16,
6545 incoming_font->ft_face->units_per_EM);
6546 avg_advance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
6547 fixed_pitch_full = (avg_advance > 0 &&
6548 (base_advance + 63) >> 6 ==
6549 pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale));
6550 if (fixed_pitch_full && !transMat)
6551 adv.x = (avg_advance * 2) << 6;
6554 if (transMat) {
6555 pFT_Vector_Transform(&adv, transMat);
6556 if (fixed_pitch_full && adv.y == 0) {
6557 FT_Vector vec;
6558 vec.x = incoming_font->ntmAvgWidth;
6559 vec.y = 0;
6560 pFT_Vector_Transform(&vec, transMat);
6561 adv.x = (pFT_MulFix(vec.x, em_scale) * 2) << 6;
6565 if (font->fake_bold) {
6566 if (!transMat)
6567 adv.x += 1 << 6;
6568 else {
6569 FT_Vector fake_bold_adv, vec = { 1 << 6, 0 };
6570 pFT_Vector_Transform(&vec, transMat);
6571 fake_bold_adv = normalize_vector(&vec);
6572 adv.x += fake_bold_adv.x;
6573 adv.y += fake_bold_adv.y;
6577 adv.x = (adv.x + 63) & -64;
6578 adv.y = -((adv.y + 63) & -64);
6579 return adv;
6582 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
6584 TTPOLYGONHEADER *pph;
6585 TTPOLYCURVE *ppc;
6586 unsigned int needed = 0, point = 0, contour, first_pt;
6587 unsigned int pph_start, cpfx;
6588 DWORD type;
6590 for (contour = 0; contour < outline->n_contours; contour++)
6592 /* Ignore contours containing one point */
6593 if (point == outline->contours[contour])
6595 point++;
6596 continue;
6599 pph_start = needed;
6600 pph = (TTPOLYGONHEADER *)(buf + needed);
6601 first_pt = point;
6602 if (buf)
6604 pph->dwType = TT_POLYGON_TYPE;
6605 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6607 needed += sizeof(*pph);
6608 point++;
6609 while (point <= outline->contours[contour])
6611 ppc = (TTPOLYCURVE *)(buf + needed);
6612 type = outline->tags[point] & FT_Curve_Tag_On ?
6613 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6614 cpfx = 0;
6617 if (buf)
6618 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6619 cpfx++;
6620 point++;
6621 } while (point <= outline->contours[contour] &&
6622 (outline->tags[point] & FT_Curve_Tag_On) ==
6623 (outline->tags[point-1] & FT_Curve_Tag_On));
6624 /* At the end of a contour Windows adds the start point, but
6625 only for Beziers */
6626 if (point > outline->contours[contour] &&
6627 !(outline->tags[point-1] & FT_Curve_Tag_On))
6629 if (buf)
6630 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6631 cpfx++;
6633 else if (point <= outline->contours[contour] &&
6634 outline->tags[point] & FT_Curve_Tag_On)
6636 /* add closing pt for bezier */
6637 if (buf)
6638 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6639 cpfx++;
6640 point++;
6642 if (buf)
6644 ppc->wType = type;
6645 ppc->cpfx = cpfx;
6647 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6649 if (buf)
6650 pph->cb = needed - pph_start;
6652 return needed;
6655 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
6657 /* Convert the quadratic Beziers to cubic Beziers.
6658 The parametric eqn for a cubic Bezier is, from PLRM:
6659 r(t) = at^3 + bt^2 + ct + r0
6660 with the control points:
6661 r1 = r0 + c/3
6662 r2 = r1 + (c + b)/3
6663 r3 = r0 + c + b + a
6665 A quadratic Bezier has the form:
6666 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6668 So equating powers of t leads to:
6669 r1 = 2/3 p1 + 1/3 p0
6670 r2 = 2/3 p1 + 1/3 p2
6671 and of course r0 = p0, r3 = p2
6673 int contour, point = 0, first_pt;
6674 TTPOLYGONHEADER *pph;
6675 TTPOLYCURVE *ppc;
6676 DWORD pph_start, cpfx, type;
6677 FT_Vector cubic_control[4];
6678 unsigned int needed = 0;
6680 for (contour = 0; contour < outline->n_contours; contour++)
6682 pph_start = needed;
6683 pph = (TTPOLYGONHEADER *)(buf + needed);
6684 first_pt = point;
6685 if (buf)
6687 pph->dwType = TT_POLYGON_TYPE;
6688 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6690 needed += sizeof(*pph);
6691 point++;
6692 while (point <= outline->contours[contour])
6694 ppc = (TTPOLYCURVE *)(buf + needed);
6695 type = outline->tags[point] & FT_Curve_Tag_On ?
6696 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6697 cpfx = 0;
6700 if (type == TT_PRIM_LINE)
6702 if (buf)
6703 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6704 cpfx++;
6705 point++;
6707 else
6709 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6710 so cpfx = 3n */
6712 /* FIXME: Possible optimization in endpoint calculation
6713 if there are two consecutive curves */
6714 cubic_control[0] = outline->points[point-1];
6715 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
6717 cubic_control[0].x += outline->points[point].x + 1;
6718 cubic_control[0].y += outline->points[point].y + 1;
6719 cubic_control[0].x >>= 1;
6720 cubic_control[0].y >>= 1;
6722 if (point+1 > outline->contours[contour])
6723 cubic_control[3] = outline->points[first_pt];
6724 else
6726 cubic_control[3] = outline->points[point+1];
6727 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
6729 cubic_control[3].x += outline->points[point].x + 1;
6730 cubic_control[3].y += outline->points[point].y + 1;
6731 cubic_control[3].x >>= 1;
6732 cubic_control[3].y >>= 1;
6735 /* r1 = 1/3 p0 + 2/3 p1
6736 r2 = 1/3 p2 + 2/3 p1 */
6737 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6738 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6739 cubic_control[2] = cubic_control[1];
6740 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6741 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6742 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6743 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6744 if (buf)
6746 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6747 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6748 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6750 cpfx += 3;
6751 point++;
6753 } while (point <= outline->contours[contour] &&
6754 (outline->tags[point] & FT_Curve_Tag_On) ==
6755 (outline->tags[point-1] & FT_Curve_Tag_On));
6756 /* At the end of a contour Windows adds the start point,
6757 but only for Beziers and we've already done that.
6759 if (point <= outline->contours[contour] &&
6760 outline->tags[point] & FT_Curve_Tag_On)
6762 /* This is the closing pt of a bezier, but we've already
6763 added it, so just inc point and carry on */
6764 point++;
6766 if (buf)
6768 ppc->wType = type;
6769 ppc->cpfx = cpfx;
6771 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6773 if (buf)
6774 pph->cb = needed - pph_start;
6776 return needed;
6779 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6781 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
6782 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
6783 const MAT2* lpmat)
6785 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
6786 GLYPHMETRICS gm;
6787 FT_Face ft_face = incoming_font->ft_face;
6788 GdiFont *font = incoming_font;
6789 FT_Glyph_Metrics metrics;
6790 FT_UInt glyph_index;
6791 DWORD width, height, pitch, needed = 0;
6792 FT_Bitmap ft_bitmap;
6793 FT_Error err;
6794 INT left, right, top = 0, bottom = 0;
6795 FT_Vector adv;
6796 INT origin_x = 0, origin_y = 0;
6797 FT_Angle angle = 0;
6798 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
6799 double widthRatio = 1.0;
6800 FT_Matrix transMat = identityMat;
6801 FT_Matrix transMatUnrotated;
6802 FT_Matrix transMatTategaki;
6803 BOOL needsTransform = FALSE;
6804 BOOL tategaki = (font->name[0] == '@');
6805 BOOL vertical_metrics;
6806 UINT original_index;
6808 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
6809 buflen, buf, lpmat);
6811 TRACE("font transform %f %f %f %f\n",
6812 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
6813 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
6815 if(format & GGO_GLYPH_INDEX) {
6816 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
6817 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
6818 as glyph index. "Treasure Adventure Game" depends on this. */
6819 glyph_index = pFT_Get_Char_Index(font->ft_face, glyph);
6820 TRACE("translate glyph index %04x -> %04x\n", glyph, glyph_index);
6821 } else
6822 glyph_index = glyph;
6823 original_index = glyph_index;
6824 format &= ~GGO_GLYPH_INDEX;
6825 /* TODO: Window also turns off tategaki for glyphs passed in by index
6826 if their unicode code points fall outside of the range that is
6827 rotated. */
6828 } else {
6829 BOOL vert;
6830 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index, &vert);
6831 ft_face = font->ft_face;
6832 original_index = glyph_index;
6833 if (!vert && tategaki)
6834 tategaki = check_unicode_tategaki(glyph);
6837 if(format & GGO_UNHINTED) {
6838 load_flags |= FT_LOAD_NO_HINTING;
6839 format &= ~GGO_UNHINTED;
6842 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
6843 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
6844 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
6845 font->gmsize * sizeof(GM*));
6846 } else {
6847 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
6848 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
6850 *lpgm = FONT_GM(font,original_index)->gm;
6851 *abc = FONT_GM(font,original_index)->abc;
6852 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6853 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6854 lpgm->gmCellIncX, lpgm->gmCellIncY);
6855 return 1; /* FIXME */
6859 if (!font->gm[original_index / GM_BLOCK_SIZE])
6860 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
6862 /* Scaling factor */
6863 if (font->aveWidth)
6865 TEXTMETRICW tm;
6867 get_text_metrics(font, &tm);
6869 widthRatio = (double)font->aveWidth;
6870 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6872 else
6873 widthRatio = font->scale_y;
6875 /* Scaling transform */
6876 if (widthRatio != 1.0 || font->scale_y != 1.0)
6878 FT_Matrix scaleMat;
6879 scaleMat.xx = FT_FixedFromFloat(widthRatio);
6880 scaleMat.xy = 0;
6881 scaleMat.yx = 0;
6882 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
6884 pFT_Matrix_Multiply(&scaleMat, &transMat);
6885 needsTransform = TRUE;
6888 /* Slant transform */
6889 if (font->fake_italic) {
6890 FT_Matrix slantMat;
6892 slantMat.xx = (1 << 16);
6893 slantMat.xy = ((1 << 16) >> 2);
6894 slantMat.yx = 0;
6895 slantMat.yy = (1 << 16);
6896 pFT_Matrix_Multiply(&slantMat, &transMat);
6897 needsTransform = TRUE;
6900 /* Rotation transform */
6901 transMatUnrotated = transMat;
6902 transMatTategaki = transMat;
6903 if(font->orientation || tategaki) {
6904 FT_Matrix rotationMat;
6905 FT_Matrix taterotationMat;
6906 FT_Vector vecAngle;
6908 double orient = font->orientation / 10.0;
6909 double tate_orient = 0.f;
6911 if (tategaki)
6912 tate_orient = ((font->orientation+900)%3600)/10.0;
6913 else
6914 tate_orient = font->orientation/10.0;
6916 if (orient)
6918 angle = FT_FixedFromFloat(orient);
6919 pFT_Vector_Unit(&vecAngle, angle);
6920 rotationMat.xx = vecAngle.x;
6921 rotationMat.xy = -vecAngle.y;
6922 rotationMat.yx = -rotationMat.xy;
6923 rotationMat.yy = rotationMat.xx;
6925 pFT_Matrix_Multiply(&rotationMat, &transMat);
6928 if (tate_orient)
6930 angle = FT_FixedFromFloat(tate_orient);
6931 pFT_Vector_Unit(&vecAngle, angle);
6932 taterotationMat.xx = vecAngle.x;
6933 taterotationMat.xy = -vecAngle.y;
6934 taterotationMat.yx = -taterotationMat.xy;
6935 taterotationMat.yy = taterotationMat.xx;
6936 pFT_Matrix_Multiply(&taterotationMat, &transMatTategaki);
6939 needsTransform = TRUE;
6942 /* World transform */
6943 if (!is_identity_FMAT2(&font->font_desc.matrix))
6945 FT_Matrix worldMat;
6946 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
6947 worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21);
6948 worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12);
6949 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
6950 pFT_Matrix_Multiply(&worldMat, &transMat);
6951 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
6952 pFT_Matrix_Multiply(&worldMat, &transMatTategaki);
6953 needsTransform = TRUE;
6956 /* Extra transformation specified by caller */
6957 if (!is_identity_MAT2(lpmat))
6959 FT_Matrix extraMat;
6960 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
6961 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
6962 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
6963 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
6964 pFT_Matrix_Multiply(&extraMat, &transMat);
6965 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
6966 pFT_Matrix_Multiply(&extraMat, &transMatTategaki);
6967 needsTransform = TRUE;
6970 vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face));
6971 /* there is a freetype bug where vertical metrics are only
6972 properly scaled and correct in 2.4.0 or greater */
6973 if ((vertical_metrics) && (FT_Version.major < 2 || (FT_Version.major == 2 && FT_Version.minor < 4)))
6974 vertical_metrics = FALSE;
6976 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
6977 if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
6979 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
6981 if(err) {
6982 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
6983 return GDI_ERROR;
6986 metrics = ft_face->glyph->metrics;
6987 if(font->fake_bold) {
6988 if (!get_bold_glyph_outline(ft_face->glyph, font->ppem, &metrics) && metrics.width)
6989 metrics.width += 1 << 6;
6992 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6993 * by the text metrics. The proper behavior is to clip the glyph metrics to
6994 * fit within the maximums specified in the text metrics. */
6995 if(incoming_font->potm || get_outline_text_metrics(incoming_font) ||
6996 get_bitmap_text_metrics(incoming_font)) {
6997 TEXTMETRICW *ptm = &incoming_font->potm->otmTextMetrics;
6998 top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
6999 bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
7000 metrics.horiBearingY = top;
7001 metrics.height = top - bottom;
7003 /* TODO: Are we supposed to clip the width as well...? */
7004 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
7007 if(!needsTransform) {
7008 left = (INT)(metrics.horiBearingX) & -64;
7009 right = (INT)((metrics.horiBearingX + metrics.width) + 63) & -64;
7010 top = (metrics.horiBearingY + 63) & -64;
7011 bottom = (metrics.horiBearingY - metrics.height) & -64;
7012 adv = get_advance_metric(incoming_font, font, &metrics, NULL, vertical_metrics);
7013 gm.gmCellIncX = adv.x >> 6;
7014 gm.gmCellIncY = 0;
7015 origin_x = left;
7016 origin_y = top;
7017 abc->abcA = origin_x >> 6;
7018 abc->abcB = metrics.width >> 6;
7019 } else {
7020 INT xc, yc;
7021 FT_Vector vec;
7022 FT_Pos lsb;
7024 left = right = 0;
7026 for(xc = 0; xc < 2; xc++) {
7027 for(yc = 0; yc < 2; yc++) {
7028 vec.x = metrics.horiBearingX + xc * metrics.width;
7029 vec.y = metrics.horiBearingY - yc * metrics.height;
7030 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
7031 pFT_Vector_Transform(&vec, &transMatTategaki);
7032 if(xc == 0 && yc == 0) {
7033 left = right = vec.x;
7034 top = bottom = vec.y;
7035 } else {
7036 if(vec.x < left) left = vec.x;
7037 else if(vec.x > right) right = vec.x;
7038 if(vec.y < bottom) bottom = vec.y;
7039 else if(vec.y > top) top = vec.y;
7043 left = left & -64;
7044 right = (right + 63) & -64;
7045 bottom = bottom & -64;
7046 top = (top + 63) & -64;
7048 if (tategaki && (font->potm || get_outline_text_metrics(font)))
7050 if (vertical_metrics)
7051 lsb = metrics.horiBearingY + metrics.vertBearingY;
7052 else
7053 lsb = metrics.vertAdvance + (font->potm->otmDescent << 6);
7054 vec.x = lsb;
7055 vec.y = font->potm->otmDescent << 6;
7056 TRACE ("Vec %ld,%ld\n", vec.x>>6, vec.y>>6);
7057 pFT_Vector_Transform(&vec, &transMat);
7058 origin_x = (vec.x + left) & -64;
7059 origin_y = (vec.y + top + 63) & -64;
7061 else
7063 origin_x = left;
7064 origin_y = top;
7065 lsb = metrics.horiBearingX;
7068 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
7069 adv = get_advance_metric(incoming_font, font, &metrics, &transMat, vertical_metrics);
7070 gm.gmCellIncX = adv.x >> 6;
7071 gm.gmCellIncY = adv.y >> 6;
7073 adv = get_advance_metric(incoming_font, font, &metrics, &transMatUnrotated, vertical_metrics);
7075 vec.x = lsb;
7076 vec.y = 0;
7077 pFT_Vector_Transform(&vec, &transMatUnrotated);
7078 abc->abcA = vec.x >> 6;
7080 vec.x = metrics.width;
7081 vec.y = 0;
7082 pFT_Vector_Transform(&vec, &transMatUnrotated);
7083 if (vec.x >= 0)
7084 abc->abcB = vec.x >> 6;
7085 else
7086 abc->abcB = -vec.x >> 6;
7089 width = (right - left) >> 6;
7090 height = (top - bottom) >> 6;
7091 gm.gmBlackBoxX = width ? width : 1;
7092 gm.gmBlackBoxY = height ? height : 1;
7093 gm.gmptGlyphOrigin.x = origin_x >> 6;
7094 gm.gmptGlyphOrigin.y = origin_y >> 6;
7095 if (!abc->abcB) abc->abcB = 1;
7096 abc->abcC = (adv.x >> 6) - abc->abcA - abc->abcB;
7098 TRACE("%u,%u,%s,%d,%d\n", gm.gmBlackBoxX, gm.gmBlackBoxY,
7099 wine_dbgstr_point(&gm.gmptGlyphOrigin),
7100 gm.gmCellIncX, gm.gmCellIncY);
7102 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
7103 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
7105 FONT_GM(font,original_index)->gm = gm;
7106 FONT_GM(font,original_index)->abc = *abc;
7107 FONT_GM(font,original_index)->init = TRUE;
7110 if(format == GGO_METRICS)
7112 *lpgm = gm;
7113 return 1; /* FIXME */
7116 if(ft_face->glyph->format != ft_glyph_format_outline &&
7117 (format == GGO_NATIVE || format == GGO_BEZIER))
7119 TRACE("loaded a bitmap\n");
7120 return GDI_ERROR;
7123 switch(format) {
7124 case GGO_BITMAP:
7125 pitch = ((width + 31) >> 5) << 2;
7126 needed = pitch * height;
7128 if(!buf || !buflen) break;
7129 if (!needed) return GDI_ERROR; /* empty glyph */
7130 if (needed > buflen)
7131 return GDI_ERROR;
7133 switch(ft_face->glyph->format) {
7134 case ft_glyph_format_bitmap:
7136 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
7137 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
7138 INT h = min( height, ft_face->glyph->bitmap.rows );
7139 while(h--) {
7140 if (!font->fake_bold)
7141 memcpy(dst, src, w);
7142 else {
7143 INT x;
7144 dst[0] = 0;
7145 for (x = 0; x < w; x++) {
7146 dst[x ] = (dst[x] & 0x80) | (src[x] >> 1) | src[x];
7147 if (x+1 < pitch)
7148 dst[x+1] = (src[x] & 0x01) << 7;
7151 src += ft_face->glyph->bitmap.pitch;
7152 dst += pitch;
7154 break;
7157 case ft_glyph_format_outline:
7158 ft_bitmap.width = width;
7159 ft_bitmap.rows = height;
7160 ft_bitmap.pitch = pitch;
7161 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
7162 ft_bitmap.buffer = buf;
7164 if(needsTransform)
7165 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
7167 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
7169 /* Note: FreeType will only set 'black' bits for us. */
7170 memset(buf, 0, needed);
7171 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
7172 break;
7174 default:
7175 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
7176 return GDI_ERROR;
7178 break;
7180 case GGO_GRAY2_BITMAP:
7181 case GGO_GRAY4_BITMAP:
7182 case GGO_GRAY8_BITMAP:
7183 case WINE_GGO_GRAY16_BITMAP:
7185 unsigned int max_level, row, col;
7186 BYTE *start, *ptr;
7188 pitch = (width + 3) / 4 * 4;
7189 needed = pitch * height;
7191 if(!buf || !buflen) break;
7192 if (!needed) return GDI_ERROR; /* empty glyph */
7193 if (needed > buflen)
7194 return GDI_ERROR;
7196 max_level = get_max_level( format );
7198 switch(ft_face->glyph->format) {
7199 case ft_glyph_format_bitmap:
7201 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
7202 INT h = min( height, ft_face->glyph->bitmap.rows );
7203 INT x;
7204 memset( buf, 0, needed );
7205 while(h--) {
7206 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++) {
7207 if (src[x / 8] & masks[x % 8]) {
7208 dst[x] = max_level;
7209 if (font->fake_bold && x+1 < pitch) dst[x+1] = max_level;
7212 src += ft_face->glyph->bitmap.pitch;
7213 dst += pitch;
7215 break;
7217 case ft_glyph_format_outline:
7219 ft_bitmap.width = width;
7220 ft_bitmap.rows = height;
7221 ft_bitmap.pitch = pitch;
7222 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
7223 ft_bitmap.buffer = buf;
7225 if(needsTransform)
7226 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
7228 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
7230 memset(ft_bitmap.buffer, 0, buflen);
7232 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
7234 if (max_level != 255)
7236 for (row = 0, start = buf; row < height; row++)
7238 for (col = 0, ptr = start; col < width; col++, ptr++)
7239 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
7240 start += pitch;
7243 break;
7246 default:
7247 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
7248 return GDI_ERROR;
7250 break;
7253 case WINE_GGO_HRGB_BITMAP:
7254 case WINE_GGO_HBGR_BITMAP:
7255 case WINE_GGO_VRGB_BITMAP:
7256 case WINE_GGO_VBGR_BITMAP:
7257 #ifdef FT_LCD_FILTER_H
7259 switch (ft_face->glyph->format)
7261 case FT_GLYPH_FORMAT_BITMAP:
7263 BYTE *src, *dst;
7264 INT src_pitch, x;
7266 pitch = width * 4;
7267 needed = pitch * height;
7269 if (!buf || !buflen) break;
7270 if (!needed) return GDI_ERROR; /* empty glyph */
7271 if (needed > buflen)
7272 return GDI_ERROR;
7274 memset(buf, 0, buflen);
7275 dst = buf;
7276 src = ft_face->glyph->bitmap.buffer;
7277 src_pitch = ft_face->glyph->bitmap.pitch;
7279 height = min( height, ft_face->glyph->bitmap.rows );
7280 while ( height-- )
7282 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
7284 if ( src[x / 8] & masks[x % 8] )
7286 ((unsigned int *)dst)[x] = ~0u;
7287 if (font->fake_bold && x+1 < width) ((unsigned int *)dst)[x+1] = ~0u;
7290 src += src_pitch;
7291 dst += pitch;
7294 break;
7297 case FT_GLYPH_FORMAT_OUTLINE:
7299 unsigned int *dst;
7300 BYTE *src;
7301 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
7302 INT x_shift, y_shift;
7303 BOOL rgb;
7304 FT_Render_Mode render_mode =
7305 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
7306 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
7308 if (!width || !height)
7310 if (!buf || !buflen) break;
7311 return GDI_ERROR;
7314 if ( render_mode == FT_RENDER_MODE_LCD)
7316 gm.gmBlackBoxX += 2;
7317 gm.gmptGlyphOrigin.x -= 1;
7318 left -= (1 << 6);
7320 else
7322 gm.gmBlackBoxY += 2;
7323 gm.gmptGlyphOrigin.y += 1;
7324 top += (1 << 6);
7327 width = gm.gmBlackBoxX;
7328 height = gm.gmBlackBoxY;
7329 pitch = width * 4;
7330 needed = pitch * height;
7332 if (!buf || !buflen) break;
7333 if (needed > buflen)
7334 return GDI_ERROR;
7336 memset(buf, 0, buflen);
7337 dst = buf;
7338 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
7340 if ( needsTransform )
7341 pFT_Outline_Transform (&ft_face->glyph->outline, &transMatTategaki);
7343 if ( pFT_Library_SetLcdFilter )
7344 pFT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT );
7345 pFT_Render_Glyph (ft_face->glyph, render_mode);
7347 src = ft_face->glyph->bitmap.buffer;
7348 src_pitch = ft_face->glyph->bitmap.pitch;
7349 src_width = ft_face->glyph->bitmap.width;
7350 src_height = ft_face->glyph->bitmap.rows;
7352 if ( render_mode == FT_RENDER_MODE_LCD)
7354 rgb_interval = 1;
7355 hmul = 3;
7356 vmul = 1;
7358 else
7360 rgb_interval = src_pitch;
7361 hmul = 1;
7362 vmul = 3;
7365 x_shift = ft_face->glyph->bitmap_left - (left >> 6);
7366 if ( x_shift < 0 )
7368 src += hmul * -x_shift;
7369 src_width -= hmul * -x_shift;
7371 else if ( x_shift > 0 )
7373 dst += x_shift;
7374 width -= x_shift;
7377 y_shift = (top >> 6) - ft_face->glyph->bitmap_top;
7378 if ( y_shift < 0 )
7380 src += src_pitch * vmul * -y_shift;
7381 src_height -= vmul * -y_shift;
7383 else if ( y_shift > 0 )
7385 dst += y_shift * ( pitch / sizeof(*dst) );
7386 height -= y_shift;
7389 width = min( width, src_width / hmul );
7390 height = min( height, src_height / vmul );
7392 while ( height-- )
7394 for ( x = 0; x < width; x++ )
7396 if ( rgb )
7398 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
7399 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
7400 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
7401 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
7403 else
7405 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
7406 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
7407 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
7408 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
7411 src += src_pitch * vmul;
7412 dst += pitch / sizeof(*dst);
7415 break;
7418 default:
7419 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
7420 return GDI_ERROR;
7423 break;
7425 #else
7426 return GDI_ERROR;
7427 #endif
7429 case GGO_NATIVE:
7431 FT_Outline *outline = &ft_face->glyph->outline;
7433 if(buflen == 0) buf = NULL;
7435 if (needsTransform && buf)
7436 pFT_Outline_Transform(outline, &transMatTategaki);
7438 needed = get_native_glyph_outline(outline, buflen, NULL);
7440 if (!buf || !buflen)
7441 break;
7442 if (needed > buflen)
7443 return GDI_ERROR;
7445 get_native_glyph_outline(outline, buflen, buf);
7446 break;
7448 case GGO_BEZIER:
7450 FT_Outline *outline = &ft_face->glyph->outline;
7451 if(buflen == 0) buf = NULL;
7453 if (needsTransform && buf)
7454 pFT_Outline_Transform(outline, &transMat);
7456 needed = get_bezier_glyph_outline(outline, buflen, NULL);
7458 if (!buf || !buflen)
7459 break;
7460 if (needed > buflen)
7461 return GDI_ERROR;
7463 get_bezier_glyph_outline(outline, buflen, buf);
7464 break;
7467 default:
7468 FIXME("Unsupported format %d\n", format);
7469 return GDI_ERROR;
7471 *lpgm = gm;
7472 return needed;
7475 static BOOL get_bitmap_text_metrics(GdiFont *font)
7477 FT_Face ft_face = font->ft_face;
7478 FT_WinFNT_HeaderRec winfnt_header;
7479 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
7480 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
7481 font->potm->otmSize = size;
7483 #define TM font->potm->otmTextMetrics
7484 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
7486 TM.tmHeight = winfnt_header.pixel_height;
7487 TM.tmAscent = winfnt_header.ascent;
7488 TM.tmDescent = TM.tmHeight - TM.tmAscent;
7489 TM.tmInternalLeading = winfnt_header.internal_leading;
7490 TM.tmExternalLeading = winfnt_header.external_leading;
7491 TM.tmAveCharWidth = winfnt_header.avg_width;
7492 TM.tmMaxCharWidth = winfnt_header.max_width;
7493 TM.tmWeight = winfnt_header.weight;
7494 TM.tmOverhang = 0;
7495 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
7496 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
7497 TM.tmFirstChar = winfnt_header.first_char;
7498 TM.tmLastChar = winfnt_header.last_char;
7499 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
7500 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
7501 TM.tmItalic = winfnt_header.italic;
7502 TM.tmUnderlined = font->underline;
7503 TM.tmStruckOut = font->strikeout;
7504 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
7505 TM.tmCharSet = winfnt_header.charset;
7507 else
7509 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
7510 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
7511 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7512 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
7513 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
7514 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
7515 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
7516 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
7517 TM.tmOverhang = 0;
7518 TM.tmDigitizedAspectX = 96; /* FIXME */
7519 TM.tmDigitizedAspectY = 96; /* FIXME */
7520 TM.tmFirstChar = 1;
7521 TM.tmLastChar = 255;
7522 TM.tmDefaultChar = 32;
7523 TM.tmBreakChar = 32;
7524 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
7525 TM.tmUnderlined = font->underline;
7526 TM.tmStruckOut = font->strikeout;
7527 /* NB inverted meaning of TMPF_FIXED_PITCH */
7528 TM.tmPitchAndFamily = FT_IS_FIXED_WIDTH(ft_face) ? 0 : TMPF_FIXED_PITCH;
7529 TM.tmCharSet = font->charset;
7531 #undef TM
7533 return TRUE;
7537 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
7539 double scale_x, scale_y;
7541 if (font->aveWidth)
7543 scale_x = (double)font->aveWidth;
7544 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7546 else
7547 scale_x = font->scale_y;
7549 scale_x *= fabs(font->font_desc.matrix.eM11);
7550 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7552 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7553 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7555 SCALE_Y(ptm->tmHeight);
7556 SCALE_Y(ptm->tmAscent);
7557 SCALE_Y(ptm->tmDescent);
7558 SCALE_Y(ptm->tmInternalLeading);
7559 SCALE_Y(ptm->tmExternalLeading);
7560 SCALE_Y(ptm->tmOverhang);
7562 SCALE_X(ptm->tmAveCharWidth);
7563 SCALE_X(ptm->tmMaxCharWidth);
7565 #undef SCALE_X
7566 #undef SCALE_Y
7569 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
7571 double scale_x, scale_y;
7573 if (font->aveWidth)
7575 scale_x = (double)font->aveWidth;
7576 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7578 else
7579 scale_x = font->scale_y;
7581 scale_x *= fabs(font->font_desc.matrix.eM11);
7582 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7584 scale_font_metrics(font, &potm->otmTextMetrics);
7586 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7587 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7589 SCALE_Y(potm->otmAscent);
7590 SCALE_Y(potm->otmDescent);
7591 SCALE_Y(potm->otmLineGap);
7592 SCALE_Y(potm->otmsCapEmHeight);
7593 SCALE_Y(potm->otmsXHeight);
7594 SCALE_Y(potm->otmrcFontBox.top);
7595 SCALE_Y(potm->otmrcFontBox.bottom);
7596 SCALE_X(potm->otmrcFontBox.left);
7597 SCALE_X(potm->otmrcFontBox.right);
7598 SCALE_Y(potm->otmMacAscent);
7599 SCALE_Y(potm->otmMacDescent);
7600 SCALE_Y(potm->otmMacLineGap);
7601 SCALE_X(potm->otmptSubscriptSize.x);
7602 SCALE_Y(potm->otmptSubscriptSize.y);
7603 SCALE_X(potm->otmptSubscriptOffset.x);
7604 SCALE_Y(potm->otmptSubscriptOffset.y);
7605 SCALE_X(potm->otmptSuperscriptSize.x);
7606 SCALE_Y(potm->otmptSuperscriptSize.y);
7607 SCALE_X(potm->otmptSuperscriptOffset.x);
7608 SCALE_Y(potm->otmptSuperscriptOffset.y);
7609 SCALE_Y(potm->otmsStrikeoutSize);
7610 SCALE_Y(potm->otmsStrikeoutPosition);
7611 SCALE_Y(potm->otmsUnderscoreSize);
7612 SCALE_Y(potm->otmsUnderscorePosition);
7614 #undef SCALE_X
7615 #undef SCALE_Y
7618 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
7620 if(!font->potm)
7622 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
7624 /* Make sure that the font has sane width/height ratio */
7625 if (font->aveWidth)
7627 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
7629 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
7630 font->aveWidth = 0;
7634 *ptm = font->potm->otmTextMetrics;
7635 scale_font_metrics(font, ptm);
7636 return TRUE;
7639 static BOOL face_has_symbol_charmap(FT_Face ft_face)
7641 int i;
7643 for(i = 0; i < ft_face->num_charmaps; i++)
7645 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
7646 return TRUE;
7648 return FALSE;
7651 static BOOL get_outline_text_metrics(GdiFont *font)
7653 BOOL ret = FALSE;
7654 FT_Face ft_face = font->ft_face;
7655 UINT needed, lenfam, lensty, lenface, lenfull;
7656 TT_OS2 *pOS2;
7657 TT_HoriHeader *pHori;
7658 TT_Postscript *pPost;
7659 FT_Fixed em_scale;
7660 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
7661 char *cp;
7662 INT ascent, descent;
7663 USHORT windescent;
7665 TRACE("font=%p\n", font);
7667 if(!FT_IS_SCALABLE(ft_face))
7668 return FALSE;
7670 needed = sizeof(*font->potm);
7672 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
7673 family_nameW = strdupW(font->name);
7675 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
7676 if (!style_nameW)
7678 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
7679 style_nameW = towstr( CP_ACP, ft_face->style_name );
7681 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
7683 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
7684 if (!face_nameW)
7686 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
7687 face_nameW = strdupW(font->name);
7689 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
7690 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
7692 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
7693 if (!full_nameW)
7695 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
7696 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
7697 full_nameW = strdupW(fake_nameW);
7699 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
7701 /* These names should be read from the TT name table */
7703 /* length of otmpFamilyName */
7704 needed += lenfam;
7706 /* length of otmpFaceName */
7707 needed += lenface;
7709 /* length of otmpStyleName */
7710 needed += lensty;
7712 /* length of otmpFullName */
7713 needed += lenfull;
7716 em_scale = (FT_Fixed)MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
7718 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
7719 if(!pOS2) {
7720 FIXME("Can't find OS/2 table - not TT font?\n");
7721 goto end;
7724 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
7725 if(!pHori) {
7726 FIXME("Can't find HHEA table - not TT font?\n");
7727 goto end;
7730 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
7732 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",
7733 pOS2->usWinAscent, pOS2->usWinDescent,
7734 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
7735 pOS2->xAvgCharWidth,
7736 ft_face->ascender, ft_face->descender, ft_face->height,
7737 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
7738 ft_face->bbox.yMax, ft_face->bbox.yMin);
7740 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
7741 font->potm->otmSize = needed;
7743 #define TM font->potm->otmTextMetrics
7745 windescent = get_fixed_windescent(pOS2->usWinDescent);
7746 if(pOS2->usWinAscent + windescent == 0) {
7747 ascent = pHori->Ascender;
7748 descent = -pHori->Descender;
7749 } else {
7750 ascent = pOS2->usWinAscent;
7751 descent = windescent;
7754 font->ntmCellHeight = ascent + descent;
7755 font->ntmAvgWidth = pOS2->xAvgCharWidth;
7757 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7758 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7760 if(font->yMax) {
7761 TM.tmAscent = font->yMax;
7762 TM.tmDescent = -font->yMin;
7763 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
7764 } else {
7765 TM.tmAscent = SCALE_Y(ascent);
7766 TM.tmDescent = SCALE_Y(descent);
7767 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
7770 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7772 /* MSDN says:
7773 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7775 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
7776 ((ascent + descent) -
7777 (pHori->Ascender - pHori->Descender))));
7779 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
7780 if (TM.tmAveCharWidth == 0) {
7781 TM.tmAveCharWidth = 1;
7783 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
7784 TM.tmWeight = FW_REGULAR;
7785 if (font->fake_bold) {
7786 TM.tmAveCharWidth++;
7787 TM.tmMaxCharWidth++;
7788 TM.tmWeight = FW_BOLD;
7790 else
7792 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
7794 if (pOS2->usWeightClass > FW_MEDIUM)
7795 TM.tmWeight = pOS2->usWeightClass;
7797 else if (pOS2->usWeightClass <= FW_MEDIUM)
7798 TM.tmWeight = pOS2->usWeightClass;
7800 TM.tmOverhang = 0;
7801 TM.tmDigitizedAspectX = 96; /* FIXME */
7802 TM.tmDigitizedAspectY = 96; /* FIXME */
7803 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7804 * symbol range to 0 - f0ff
7807 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
7809 TM.tmFirstChar = 0;
7810 switch(GetACP())
7812 case 1255: /* Hebrew */
7813 TM.tmLastChar = 0xf896;
7814 break;
7815 case 1257: /* Baltic */
7816 TM.tmLastChar = 0xf8fd;
7817 break;
7818 default:
7819 TM.tmLastChar = 0xf0ff;
7821 TM.tmBreakChar = 0x20;
7822 TM.tmDefaultChar = 0x1f;
7824 else
7826 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
7827 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
7829 if(pOS2->usFirstCharIndex <= 1)
7830 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
7831 else if (pOS2->usFirstCharIndex > 0xff)
7832 TM.tmBreakChar = 0x20;
7833 else
7834 TM.tmBreakChar = pOS2->usFirstCharIndex;
7835 TM.tmDefaultChar = TM.tmBreakChar - 1;
7837 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
7838 TM.tmUnderlined = font->underline;
7839 TM.tmStruckOut = font->strikeout;
7841 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7842 if(!FT_IS_FIXED_WIDTH(ft_face) &&
7843 (pOS2->version == 0xFFFFU ||
7844 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
7845 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
7846 else
7847 TM.tmPitchAndFamily = 0;
7849 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
7851 case PAN_FAMILY_SCRIPT:
7852 TM.tmPitchAndFamily |= FF_SCRIPT;
7853 break;
7855 case PAN_FAMILY_DECORATIVE:
7856 TM.tmPitchAndFamily |= FF_DECORATIVE;
7857 break;
7859 case PAN_ANY:
7860 case PAN_NO_FIT:
7861 case PAN_FAMILY_TEXT_DISPLAY:
7862 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
7863 /* which is clearly not what the panose spec says. */
7864 default:
7865 if(TM.tmPitchAndFamily == 0 || /* fixed */
7866 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
7867 TM.tmPitchAndFamily = FF_MODERN;
7868 else
7870 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
7872 case PAN_ANY:
7873 case PAN_NO_FIT:
7874 default:
7875 TM.tmPitchAndFamily |= FF_DONTCARE;
7876 break;
7878 case PAN_SERIF_COVE:
7879 case PAN_SERIF_OBTUSE_COVE:
7880 case PAN_SERIF_SQUARE_COVE:
7881 case PAN_SERIF_OBTUSE_SQUARE_COVE:
7882 case PAN_SERIF_SQUARE:
7883 case PAN_SERIF_THIN:
7884 case PAN_SERIF_BONE:
7885 case PAN_SERIF_EXAGGERATED:
7886 case PAN_SERIF_TRIANGLE:
7887 TM.tmPitchAndFamily |= FF_ROMAN;
7888 break;
7890 case PAN_SERIF_NORMAL_SANS:
7891 case PAN_SERIF_OBTUSE_SANS:
7892 case PAN_SERIF_PERP_SANS:
7893 case PAN_SERIF_FLARED:
7894 case PAN_SERIF_ROUNDED:
7895 TM.tmPitchAndFamily |= FF_SWISS;
7896 break;
7899 break;
7902 if(FT_IS_SCALABLE(ft_face))
7903 TM.tmPitchAndFamily |= TMPF_VECTOR;
7905 if(FT_IS_SFNT(ft_face))
7907 if (font->ntmFlags & NTM_PS_OPENTYPE)
7908 TM.tmPitchAndFamily |= TMPF_DEVICE;
7909 else
7910 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
7913 TM.tmCharSet = font->charset;
7915 font->potm->otmFiller = 0;
7916 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
7917 font->potm->otmfsSelection = pOS2->fsSelection;
7918 if (font->fake_italic)
7919 font->potm->otmfsSelection |= 1;
7920 if (font->fake_bold)
7921 font->potm->otmfsSelection |= 1 << 5;
7922 /* Only return valid bits that define embedding and subsetting restrictions */
7923 font->potm->otmfsType = pOS2->fsType & 0x30e;
7924 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
7925 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
7926 font->potm->otmItalicAngle = 0; /* POST table */
7927 font->potm->otmEMSquare = ft_face->units_per_EM;
7928 font->potm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
7929 font->potm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
7930 font->potm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
7931 font->potm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
7932 font->potm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
7933 font->potm->otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
7934 font->potm->otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
7935 font->potm->otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
7936 font->potm->otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
7937 font->potm->otmMacAscent = TM.tmAscent;
7938 font->potm->otmMacDescent = -TM.tmDescent;
7939 font->potm->otmMacLineGap = font->potm->otmLineGap;
7940 font->potm->otmusMinimumPPEM = 0; /* TT Header */
7941 font->potm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
7942 font->potm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
7943 font->potm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
7944 font->potm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
7945 font->potm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
7946 font->potm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
7947 font->potm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
7948 font->potm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
7949 font->potm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
7950 font->potm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
7951 if(!pPost) {
7952 font->potm->otmsUnderscoreSize = 0;
7953 font->potm->otmsUnderscorePosition = 0;
7954 } else {
7955 font->potm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
7956 font->potm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
7958 #undef SCALE_X
7959 #undef SCALE_Y
7960 #undef TM
7962 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7963 cp = (char*)font->potm + sizeof(*font->potm);
7964 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
7965 strcpyW((WCHAR*)cp, family_nameW);
7966 cp += lenfam;
7967 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
7968 strcpyW((WCHAR*)cp, style_nameW);
7969 cp += lensty;
7970 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7971 strcpyW((WCHAR*)cp, face_nameW);
7972 cp += lenface;
7973 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
7974 strcpyW((WCHAR*)cp, full_nameW);
7975 ret = TRUE;
7977 end:
7978 HeapFree(GetProcessHeap(), 0, style_nameW);
7979 HeapFree(GetProcessHeap(), 0, family_nameW);
7980 HeapFree(GetProcessHeap(), 0, face_nameW);
7981 HeapFree(GetProcessHeap(), 0, full_nameW);
7982 return ret;
7985 /*************************************************************
7986 * freetype_GetGlyphOutline
7988 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
7989 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7991 struct freetype_physdev *physdev = get_freetype_dev( dev );
7992 DWORD ret;
7993 ABC abc;
7995 if (!physdev->font)
7997 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
7998 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
8001 GDI_CheckNotLock();
8002 EnterCriticalSection( &freetype_cs );
8003 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
8004 LeaveCriticalSection( &freetype_cs );
8005 return ret;
8008 /*************************************************************
8009 * freetype_GetTextMetrics
8011 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
8013 struct freetype_physdev *physdev = get_freetype_dev( dev );
8014 BOOL ret;
8016 if (!physdev->font)
8018 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
8019 return dev->funcs->pGetTextMetrics( dev, metrics );
8022 GDI_CheckNotLock();
8023 EnterCriticalSection( &freetype_cs );
8024 ret = get_text_metrics( physdev->font, metrics );
8025 LeaveCriticalSection( &freetype_cs );
8026 return ret;
8029 /*************************************************************
8030 * freetype_GetOutlineTextMetrics
8032 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
8034 struct freetype_physdev *physdev = get_freetype_dev( dev );
8035 UINT ret = 0;
8037 if (!physdev->font)
8039 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
8040 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
8043 TRACE("font=%p\n", physdev->font);
8045 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
8047 GDI_CheckNotLock();
8048 EnterCriticalSection( &freetype_cs );
8050 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
8052 if(potm && cbSize >= physdev->font->potm->otmSize)
8054 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
8055 scale_outline_font_metrics(physdev->font, potm);
8057 ret = physdev->font->potm->otmSize;
8059 LeaveCriticalSection( &freetype_cs );
8060 return ret;
8063 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
8065 child->font = alloc_font();
8066 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
8067 if(!child->font->ft_face)
8069 free_font(child->font);
8070 child->font = NULL;
8071 return FALSE;
8074 child->font->font_desc = font->font_desc;
8075 child->font->ntmFlags = child->face->ntmFlags;
8076 child->font->orientation = font->orientation;
8077 child->font->scale_y = font->scale_y;
8078 child->font->name = strdupW(child->face->family->FamilyName);
8079 child->font->base_font = font;
8080 TRACE("created child font %p for base %p\n", child->font, font);
8081 return TRUE;
8084 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL* vert)
8086 FT_UInt g,o;
8087 CHILD_FONT *child_font;
8089 if(font->base_font)
8090 font = font->base_font;
8092 *linked_font = font;
8094 if((*glyph = get_glyph_index(font, c)))
8096 o = *glyph;
8097 *glyph = get_GSUB_vert_glyph(font, *glyph);
8098 *vert = (o != *glyph);
8099 return TRUE;
8102 if (c < 32) goto done; /* don't check linked fonts for control characters */
8104 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
8106 if(!child_font->font)
8107 if(!load_child_font(font, child_font))
8108 continue;
8110 if(!child_font->font->ft_face)
8111 continue;
8112 g = get_glyph_index(child_font->font, c);
8113 o = g;
8114 g = get_GSUB_vert_glyph(child_font->font, g);
8115 if(g)
8117 *glyph = g;
8118 *linked_font = child_font->font;
8119 *vert = (o != g);
8120 return TRUE;
8124 done:
8125 *vert = FALSE;
8126 return FALSE;
8129 /*************************************************************
8130 * freetype_GetCharWidth
8132 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
8134 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8135 UINT c;
8136 GLYPHMETRICS gm;
8137 ABC abc;
8138 struct freetype_physdev *physdev = get_freetype_dev( dev );
8140 if (!physdev->font)
8142 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
8143 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
8146 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
8148 GDI_CheckNotLock();
8149 EnterCriticalSection( &freetype_cs );
8150 for(c = firstChar; c <= lastChar; c++) {
8151 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
8152 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
8154 LeaveCriticalSection( &freetype_cs );
8155 return TRUE;
8158 /*************************************************************
8159 * freetype_GetCharABCWidths
8161 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
8163 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8164 UINT c;
8165 GLYPHMETRICS gm;
8166 struct freetype_physdev *physdev = get_freetype_dev( dev );
8168 if (!physdev->font)
8170 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
8171 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
8174 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
8176 GDI_CheckNotLock();
8177 EnterCriticalSection( &freetype_cs );
8179 for(c = firstChar; c <= lastChar; c++, buffer++)
8180 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
8182 LeaveCriticalSection( &freetype_cs );
8183 return TRUE;
8186 /*************************************************************
8187 * freetype_GetCharABCWidthsI
8189 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
8191 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8192 UINT c;
8193 GLYPHMETRICS gm;
8194 struct freetype_physdev *physdev = get_freetype_dev( dev );
8196 if (!physdev->font)
8198 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
8199 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
8202 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
8203 return FALSE;
8205 GDI_CheckNotLock();
8206 EnterCriticalSection( &freetype_cs );
8208 for(c = 0; c < count; c++, buffer++)
8209 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
8210 &gm, buffer, 0, NULL, &identity );
8212 LeaveCriticalSection( &freetype_cs );
8213 return TRUE;
8216 /*************************************************************
8217 * freetype_GetTextExtentExPoint
8219 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
8221 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8222 INT idx, pos;
8223 ABC abc;
8224 GLYPHMETRICS gm;
8225 struct freetype_physdev *physdev = get_freetype_dev( dev );
8227 if (!physdev->font)
8229 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
8230 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
8233 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
8235 GDI_CheckNotLock();
8236 EnterCriticalSection( &freetype_cs );
8238 for (idx = pos = 0; idx < count; idx++)
8240 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
8241 pos += abc.abcA + abc.abcB + abc.abcC;
8242 dxs[idx] = pos;
8245 LeaveCriticalSection( &freetype_cs );
8246 return TRUE;
8249 /*************************************************************
8250 * freetype_GetTextExtentExPointI
8252 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
8254 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8255 INT idx, pos;
8256 ABC abc;
8257 GLYPHMETRICS gm;
8258 struct freetype_physdev *physdev = get_freetype_dev( dev );
8260 if (!physdev->font)
8262 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
8263 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
8266 TRACE("%p, %p, %d\n", physdev->font, indices, count);
8268 GDI_CheckNotLock();
8269 EnterCriticalSection( &freetype_cs );
8271 for (idx = pos = 0; idx < count; idx++)
8273 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
8274 &gm, &abc, 0, NULL, &identity );
8275 pos += abc.abcA + abc.abcB + abc.abcC;
8276 dxs[idx] = pos;
8279 LeaveCriticalSection( &freetype_cs );
8280 return TRUE;
8283 /*************************************************************
8284 * freetype_GetFontData
8286 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
8288 struct freetype_physdev *physdev = get_freetype_dev( dev );
8290 if (!physdev->font)
8292 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
8293 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
8296 TRACE("font=%p, table=%s, offset=0x%x, buf=%p, cbData=0x%x\n",
8297 physdev->font, debugstr_an((char*)&table, 4), offset, buf, cbData);
8299 return get_font_data( physdev->font, table, offset, buf, cbData );
8302 /*************************************************************
8303 * freetype_GetTextFace
8305 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
8307 INT n;
8308 struct freetype_physdev *physdev = get_freetype_dev( dev );
8310 if (!physdev->font)
8312 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
8313 return dev->funcs->pGetTextFace( dev, count, str );
8316 n = strlenW(physdev->font->name) + 1;
8317 if (str)
8319 lstrcpynW(str, physdev->font->name, count);
8320 n = min(count, n);
8322 return n;
8325 /*************************************************************
8326 * freetype_GetTextCharsetInfo
8328 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
8330 struct freetype_physdev *physdev = get_freetype_dev( dev );
8332 if (!physdev->font)
8334 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
8335 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
8337 if (fs) *fs = physdev->font->fs;
8338 return physdev->font->charset;
8341 /* Retrieve a list of supported Unicode ranges for a given font.
8342 * Can be called with NULL gs to calculate the buffer size. Returns
8343 * the number of ranges found.
8345 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
8347 DWORD num_ranges = 0;
8349 if (face->charmap->encoding == FT_ENCODING_UNICODE)
8351 FT_UInt glyph_code;
8352 FT_ULong char_code, char_code_prev;
8354 glyph_code = 0;
8355 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
8357 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
8358 face->num_glyphs, glyph_code, char_code);
8360 if (!glyph_code) return 0;
8362 if (gs)
8364 gs->ranges[0].wcLow = (USHORT)char_code;
8365 gs->ranges[0].cGlyphs = 0;
8366 gs->cGlyphsSupported = 0;
8369 num_ranges = 1;
8370 while (glyph_code)
8372 if (char_code < char_code_prev)
8374 ERR("expected increasing char code from FT_Get_Next_Char\n");
8375 return 0;
8377 if (char_code - char_code_prev > 1)
8379 num_ranges++;
8380 if (gs)
8382 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
8383 gs->ranges[num_ranges - 1].cGlyphs = 1;
8384 gs->cGlyphsSupported++;
8387 else if (gs)
8389 gs->ranges[num_ranges - 1].cGlyphs++;
8390 gs->cGlyphsSupported++;
8392 char_code_prev = char_code;
8393 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
8396 else
8398 DWORD encoding = RtlUlongByteSwap(face->charmap->encoding);
8399 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding, 4));
8402 return num_ranges;
8405 /*************************************************************
8406 * freetype_GetFontUnicodeRanges
8408 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
8410 struct freetype_physdev *physdev = get_freetype_dev( dev );
8411 DWORD size, num_ranges;
8413 if (!physdev->font)
8415 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
8416 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
8419 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
8420 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
8421 if (glyphset)
8423 glyphset->cbThis = size;
8424 glyphset->cRanges = num_ranges;
8425 glyphset->flAccel = 0;
8427 return size;
8430 /*************************************************************
8431 * freetype_FontIsLinked
8433 static BOOL freetype_FontIsLinked( PHYSDEV dev )
8435 struct freetype_physdev *physdev = get_freetype_dev( dev );
8436 BOOL ret;
8438 if (!physdev->font)
8440 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
8441 return dev->funcs->pFontIsLinked( dev );
8444 GDI_CheckNotLock();
8445 EnterCriticalSection( &freetype_cs );
8446 ret = !list_empty(&physdev->font->child_fonts);
8447 LeaveCriticalSection( &freetype_cs );
8448 return ret;
8451 /*************************************************************************
8452 * GetRasterizerCaps (GDI32.@)
8454 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8456 lprs->nSize = sizeof(RASTERIZER_STATUS);
8457 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
8458 lprs->nLanguageID = 0;
8459 return TRUE;
8462 /*************************************************************
8463 * freetype_GetFontRealizationInfo
8465 static BOOL freetype_GetFontRealizationInfo( PHYSDEV dev, void *ptr )
8467 struct freetype_physdev *physdev = get_freetype_dev( dev );
8468 struct font_realization_info *info = ptr;
8470 if (!physdev->font)
8472 dev = GET_NEXT_PHYSDEV( dev, pGetFontRealizationInfo );
8473 return dev->funcs->pGetFontRealizationInfo( dev, ptr );
8476 TRACE("(%p, %p)\n", physdev->font, info);
8478 info->flags = 1;
8479 if(FT_IS_SCALABLE(physdev->font->ft_face))
8480 info->flags |= 2;
8482 info->cache_num = physdev->font->cache_num;
8483 info->instance_id = physdev->font->instance_id;
8484 if (info->size == sizeof(*info))
8486 info->unk = 0;
8487 info->face_index = physdev->font->ft_face->face_index;
8488 info->simulations = 0;
8489 if (physdev->font->fake_bold)
8490 info->simulations |= 0x1;
8491 if (physdev->font->fake_italic)
8492 info->simulations |= 0x2;
8495 return TRUE;
8498 /*************************************************************************
8499 * GetFontFileInfo (GDI32.@)
8501 BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_fileinfo *info, DWORD size, DWORD *needed )
8503 struct font_handle_entry *entry = handle_entry( instance_id );
8504 const GdiFont *font;
8506 if (!entry)
8508 SetLastError(ERROR_INVALID_PARAMETER);
8509 return FALSE;
8512 font = entry->obj;
8513 *needed = sizeof(*info) + strlenW(font->fileinfo->path) * sizeof(WCHAR);
8514 if (*needed > size)
8516 SetLastError(ERROR_INSUFFICIENT_BUFFER);
8517 return FALSE;
8520 /* path is included too */
8521 memcpy(info, font->fileinfo, *needed);
8522 return TRUE;
8525 /*************************************************************************
8526 * Kerning support for TrueType fonts
8529 struct TT_kern_table
8531 USHORT version;
8532 USHORT nTables;
8535 struct TT_kern_subtable
8537 USHORT version;
8538 USHORT length;
8539 union
8541 USHORT word;
8542 struct
8544 USHORT horizontal : 1;
8545 USHORT minimum : 1;
8546 USHORT cross_stream: 1;
8547 USHORT override : 1;
8548 USHORT reserved1 : 4;
8549 USHORT format : 8;
8550 } bits;
8551 } coverage;
8554 struct TT_format0_kern_subtable
8556 USHORT nPairs;
8557 USHORT searchRange;
8558 USHORT entrySelector;
8559 USHORT rangeShift;
8562 struct TT_kern_pair
8564 USHORT left;
8565 USHORT right;
8566 short value;
8569 static DWORD parse_format0_kern_subtable(GdiFont *font,
8570 const struct TT_format0_kern_subtable *tt_f0_ks,
8571 const USHORT *glyph_to_char,
8572 KERNINGPAIR *kern_pair, DWORD cPairs)
8574 USHORT i, nPairs;
8575 const struct TT_kern_pair *tt_kern_pair;
8577 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
8579 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
8581 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8582 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
8583 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
8585 if (!kern_pair || !cPairs)
8586 return nPairs;
8588 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
8590 nPairs = min(nPairs, cPairs);
8592 for (i = 0; i < nPairs; i++)
8594 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
8595 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
8596 /* this algorithm appears to better match what Windows does */
8597 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
8598 if (kern_pair->iKernAmount < 0)
8600 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
8601 kern_pair->iKernAmount -= font->ppem;
8603 else if (kern_pair->iKernAmount > 0)
8605 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
8606 kern_pair->iKernAmount += font->ppem;
8608 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
8610 TRACE("left %u right %u value %d\n",
8611 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
8613 kern_pair++;
8615 TRACE("copied %u entries\n", nPairs);
8616 return nPairs;
8619 /*************************************************************
8620 * freetype_GetKerningPairs
8622 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
8624 DWORD length;
8625 void *buf;
8626 const struct TT_kern_table *tt_kern_table;
8627 const struct TT_kern_subtable *tt_kern_subtable;
8628 USHORT i, nTables;
8629 USHORT *glyph_to_char;
8630 GdiFont *font;
8631 struct freetype_physdev *physdev = get_freetype_dev( dev );
8633 if (!(font = physdev->font))
8635 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
8636 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
8639 GDI_CheckNotLock();
8640 EnterCriticalSection( &freetype_cs );
8641 if (font->total_kern_pairs != (DWORD)-1)
8643 if (cPairs && kern_pair)
8645 cPairs = min(cPairs, font->total_kern_pairs);
8646 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8648 else cPairs = font->total_kern_pairs;
8650 LeaveCriticalSection( &freetype_cs );
8651 return cPairs;
8654 font->total_kern_pairs = 0;
8656 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
8658 if (length == GDI_ERROR)
8660 TRACE("no kerning data in the font\n");
8661 LeaveCriticalSection( &freetype_cs );
8662 return 0;
8665 buf = HeapAlloc(GetProcessHeap(), 0, length);
8666 if (!buf)
8668 WARN("Out of memory\n");
8669 LeaveCriticalSection( &freetype_cs );
8670 return 0;
8673 get_font_data(font, MS_KERN_TAG, 0, buf, length);
8675 /* build a glyph index to char code map */
8676 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
8677 if (!glyph_to_char)
8679 WARN("Out of memory allocating a glyph index to char code map\n");
8680 HeapFree(GetProcessHeap(), 0, buf);
8681 LeaveCriticalSection( &freetype_cs );
8682 return 0;
8685 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
8687 FT_UInt glyph_code;
8688 FT_ULong char_code;
8690 glyph_code = 0;
8691 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
8693 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
8694 font->ft_face->num_glyphs, glyph_code, char_code);
8696 while (glyph_code)
8698 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
8700 /* FIXME: This doesn't match what Windows does: it does some fancy
8701 * things with duplicate glyph index to char code mappings, while
8702 * we just avoid overriding existing entries.
8704 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
8705 glyph_to_char[glyph_code] = (USHORT)char_code;
8707 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
8710 else
8712 DWORD encoding = RtlUlongByteSwap(font->ft_face->charmap->encoding);
8713 ULONG n;
8715 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding, 4));
8716 for (n = 0; n <= 65535; n++)
8717 glyph_to_char[n] = (USHORT)n;
8720 tt_kern_table = buf;
8721 nTables = GET_BE_WORD(tt_kern_table->nTables);
8722 TRACE("version %u, nTables %u\n",
8723 GET_BE_WORD(tt_kern_table->version), nTables);
8725 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
8727 for (i = 0; i < nTables; i++)
8729 struct TT_kern_subtable tt_kern_subtable_copy;
8731 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
8732 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
8733 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
8735 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8736 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
8737 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
8739 /* According to the TrueType specification this is the only format
8740 * that will be properly interpreted by Windows and OS/2
8742 if (tt_kern_subtable_copy.coverage.bits.format == 0)
8744 DWORD new_chunk, old_total = font->total_kern_pairs;
8746 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8747 glyph_to_char, NULL, 0);
8748 font->total_kern_pairs += new_chunk;
8750 if (!font->kern_pairs)
8751 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
8752 font->total_kern_pairs * sizeof(*font->kern_pairs));
8753 else
8754 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
8755 font->total_kern_pairs * sizeof(*font->kern_pairs));
8757 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8758 glyph_to_char, font->kern_pairs + old_total, new_chunk);
8760 else
8761 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
8763 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
8766 HeapFree(GetProcessHeap(), 0, glyph_to_char);
8767 HeapFree(GetProcessHeap(), 0, buf);
8769 if (cPairs && kern_pair)
8771 cPairs = min(cPairs, font->total_kern_pairs);
8772 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8774 else cPairs = font->total_kern_pairs;
8776 LeaveCriticalSection( &freetype_cs );
8777 return cPairs;
8780 static const struct gdi_dc_funcs freetype_funcs =
8782 NULL, /* pAbortDoc */
8783 NULL, /* pAbortPath */
8784 NULL, /* pAlphaBlend */
8785 NULL, /* pAngleArc */
8786 NULL, /* pArc */
8787 NULL, /* pArcTo */
8788 NULL, /* pBeginPath */
8789 NULL, /* pBlendImage */
8790 NULL, /* pChord */
8791 NULL, /* pCloseFigure */
8792 NULL, /* pCreateCompatibleDC */
8793 freetype_CreateDC, /* pCreateDC */
8794 freetype_DeleteDC, /* pDeleteDC */
8795 NULL, /* pDeleteObject */
8796 NULL, /* pDeviceCapabilities */
8797 NULL, /* pEllipse */
8798 NULL, /* pEndDoc */
8799 NULL, /* pEndPage */
8800 NULL, /* pEndPath */
8801 freetype_EnumFonts, /* pEnumFonts */
8802 NULL, /* pEnumICMProfiles */
8803 NULL, /* pExcludeClipRect */
8804 NULL, /* pExtDeviceMode */
8805 NULL, /* pExtEscape */
8806 NULL, /* pExtFloodFill */
8807 NULL, /* pExtSelectClipRgn */
8808 NULL, /* pExtTextOut */
8809 NULL, /* pFillPath */
8810 NULL, /* pFillRgn */
8811 NULL, /* pFlattenPath */
8812 freetype_FontIsLinked, /* pFontIsLinked */
8813 NULL, /* pFrameRgn */
8814 NULL, /* pGdiComment */
8815 NULL, /* pGetBoundsRect */
8816 freetype_GetCharABCWidths, /* pGetCharABCWidths */
8817 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
8818 freetype_GetCharWidth, /* pGetCharWidth */
8819 NULL, /* pGetDeviceCaps */
8820 NULL, /* pGetDeviceGammaRamp */
8821 freetype_GetFontData, /* pGetFontData */
8822 freetype_GetFontRealizationInfo, /* pGetFontRealizationInfo */
8823 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
8824 freetype_GetGlyphIndices, /* pGetGlyphIndices */
8825 freetype_GetGlyphOutline, /* pGetGlyphOutline */
8826 NULL, /* pGetICMProfile */
8827 NULL, /* pGetImage */
8828 freetype_GetKerningPairs, /* pGetKerningPairs */
8829 NULL, /* pGetNearestColor */
8830 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
8831 NULL, /* pGetPixel */
8832 NULL, /* pGetSystemPaletteEntries */
8833 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
8834 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
8835 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
8836 freetype_GetTextFace, /* pGetTextFace */
8837 freetype_GetTextMetrics, /* pGetTextMetrics */
8838 NULL, /* pGradientFill */
8839 NULL, /* pIntersectClipRect */
8840 NULL, /* pInvertRgn */
8841 NULL, /* pLineTo */
8842 NULL, /* pModifyWorldTransform */
8843 NULL, /* pMoveTo */
8844 NULL, /* pOffsetClipRgn */
8845 NULL, /* pOffsetViewportOrg */
8846 NULL, /* pOffsetWindowOrg */
8847 NULL, /* pPaintRgn */
8848 NULL, /* pPatBlt */
8849 NULL, /* pPie */
8850 NULL, /* pPolyBezier */
8851 NULL, /* pPolyBezierTo */
8852 NULL, /* pPolyDraw */
8853 NULL, /* pPolyPolygon */
8854 NULL, /* pPolyPolyline */
8855 NULL, /* pPolygon */
8856 NULL, /* pPolyline */
8857 NULL, /* pPolylineTo */
8858 NULL, /* pPutImage */
8859 NULL, /* pRealizeDefaultPalette */
8860 NULL, /* pRealizePalette */
8861 NULL, /* pRectangle */
8862 NULL, /* pResetDC */
8863 NULL, /* pRestoreDC */
8864 NULL, /* pRoundRect */
8865 NULL, /* pSaveDC */
8866 NULL, /* pScaleViewportExt */
8867 NULL, /* pScaleWindowExt */
8868 NULL, /* pSelectBitmap */
8869 NULL, /* pSelectBrush */
8870 NULL, /* pSelectClipPath */
8871 freetype_SelectFont, /* pSelectFont */
8872 NULL, /* pSelectPalette */
8873 NULL, /* pSelectPen */
8874 NULL, /* pSetArcDirection */
8875 NULL, /* pSetBkColor */
8876 NULL, /* pSetBkMode */
8877 NULL, /* pSetDCBrushColor */
8878 NULL, /* pSetDCPenColor */
8879 NULL, /* pSetDIBColorTable */
8880 NULL, /* pSetDIBitsToDevice */
8881 NULL, /* pSetDeviceClipping */
8882 NULL, /* pSetDeviceGammaRamp */
8883 NULL, /* pSetLayout */
8884 NULL, /* pSetMapMode */
8885 NULL, /* pSetMapperFlags */
8886 NULL, /* pSetPixel */
8887 NULL, /* pSetPolyFillMode */
8888 NULL, /* pSetROP2 */
8889 NULL, /* pSetRelAbs */
8890 NULL, /* pSetStretchBltMode */
8891 NULL, /* pSetTextAlign */
8892 NULL, /* pSetTextCharacterExtra */
8893 NULL, /* pSetTextColor */
8894 NULL, /* pSetTextJustification */
8895 NULL, /* pSetViewportExt */
8896 NULL, /* pSetViewportOrg */
8897 NULL, /* pSetWindowExt */
8898 NULL, /* pSetWindowOrg */
8899 NULL, /* pSetWorldTransform */
8900 NULL, /* pStartDoc */
8901 NULL, /* pStartPage */
8902 NULL, /* pStretchBlt */
8903 NULL, /* pStretchDIBits */
8904 NULL, /* pStrokeAndFillPath */
8905 NULL, /* pStrokePath */
8906 NULL, /* pUnrealizePalette */
8907 NULL, /* pWidenPath */
8908 NULL, /* wine_get_wgl_driver */
8909 GDI_PRIORITY_FONT_DRV /* priority */
8912 #else /* HAVE_FREETYPE */
8914 struct font_fileinfo;
8916 /*************************************************************************/
8918 BOOL WineEngInit(void)
8920 return FALSE;
8923 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8925 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8926 return 1;
8929 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8931 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8932 return TRUE;
8935 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
8937 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
8938 return NULL;
8941 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
8942 LPCWSTR font_file, LPCWSTR font_path )
8944 FIXME("stub\n");
8945 return FALSE;
8948 /*************************************************************************
8949 * GetRasterizerCaps (GDI32.@)
8951 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8953 lprs->nSize = sizeof(RASTERIZER_STATUS);
8954 lprs->wFlags = 0;
8955 lprs->nLanguageID = 0;
8956 return TRUE;
8959 /*************************************************************************
8960 * GetFontFileInfo (GDI32.@)
8962 BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_fileinfo *info, DWORD size, DWORD *needed)
8964 *needed = 0;
8965 return FALSE;
8968 #endif /* HAVE_FREETYPE */