d3d8/tests: Make the window client rect match the d3d swapchain size.
[wine.git] / dlls / gdi32 / freetype.c
bloba5147b5daf9d1bbdb2f3ca49e7c23daf3038b715
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_Select_Charmap);
163 MAKE_FUNCPTR(FT_Set_Charmap);
164 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
165 MAKE_FUNCPTR(FT_Vector_Length);
166 MAKE_FUNCPTR(FT_Vector_Transform);
167 MAKE_FUNCPTR(FT_Vector_Unit);
168 static FT_Error (*pFT_Outline_Embolden)(FT_Outline *, FT_Pos);
169 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
170 #ifdef FT_LCD_FILTER_H
171 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
172 #endif
174 #ifdef SONAME_LIBFONTCONFIG
175 #include <fontconfig/fontconfig.h>
176 MAKE_FUNCPTR(FcConfigSubstitute);
177 MAKE_FUNCPTR(FcFontList);
178 MAKE_FUNCPTR(FcFontSetDestroy);
179 MAKE_FUNCPTR(FcInit);
180 MAKE_FUNCPTR(FcObjectSetAdd);
181 MAKE_FUNCPTR(FcObjectSetCreate);
182 MAKE_FUNCPTR(FcObjectSetDestroy);
183 MAKE_FUNCPTR(FcPatternCreate);
184 MAKE_FUNCPTR(FcPatternDestroy);
185 MAKE_FUNCPTR(FcPatternGetBool);
186 MAKE_FUNCPTR(FcPatternGetInteger);
187 MAKE_FUNCPTR(FcPatternGetString);
188 #endif
190 #undef MAKE_FUNCPTR
192 #ifndef FT_MAKE_TAG
193 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
194 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
195 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
196 #endif
198 #ifndef ft_encoding_none
199 #define FT_ENCODING_NONE ft_encoding_none
200 #endif
201 #ifndef ft_encoding_ms_symbol
202 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
203 #endif
204 #ifndef ft_encoding_unicode
205 #define FT_ENCODING_UNICODE ft_encoding_unicode
206 #endif
207 #ifndef ft_encoding_apple_roman
208 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
209 #endif
211 #ifdef WORDS_BIGENDIAN
212 #define GET_BE_WORD(x) (x)
213 #define GET_BE_DWORD(x) (x)
214 #else
215 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
216 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
217 #endif
219 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
220 ( ( (FT_ULong)_x4 << 24 ) | \
221 ( (FT_ULong)_x3 << 16 ) | \
222 ( (FT_ULong)_x2 << 8 ) | \
223 (FT_ULong)_x1 )
225 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
226 #define MS_GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
227 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
228 #define MS_TTCF_TAG MS_MAKE_TAG('t', 't', 'c', 'f')
229 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
231 /* 'gasp' flags */
232 #define GASP_GRIDFIT 0x01
233 #define GASP_DOGRAY 0x02
235 #ifndef WINE_FONT_DIR
236 #define WINE_FONT_DIR "fonts"
237 #endif
239 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
240 typedef struct {
241 FT_Short height;
242 FT_Short width;
243 FT_Pos size;
244 FT_Pos x_ppem;
245 FT_Pos y_ppem;
246 FT_Short internal_leading;
247 } Bitmap_Size;
249 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
250 So to let this compile on older versions of FreeType we'll define the
251 new structure here. */
252 typedef struct {
253 FT_Short height, width;
254 FT_Pos size, x_ppem, y_ppem;
255 } My_FT_Bitmap_Size;
257 struct enum_data
259 ENUMLOGFONTEXW elf;
260 NEWTEXTMETRICEXW ntm;
261 DWORD type;
264 typedef struct tagFace {
265 struct list entry;
266 unsigned int refcount;
267 WCHAR *StyleName;
268 WCHAR *FullName;
269 WCHAR *file;
270 dev_t dev;
271 ino_t ino;
272 void *font_data_ptr;
273 DWORD font_data_size;
274 FT_Long face_index;
275 FONTSIGNATURE fs;
276 DWORD ntmFlags;
277 FT_Fixed font_version;
278 BOOL scalable;
279 Bitmap_Size size; /* set if face is a bitmap */
280 DWORD flags; /* ADDFONT flags */
281 struct tagFamily *family;
282 /* Cached data for Enum */
283 struct enum_data *cached_enum_data;
284 } Face;
286 #define ADDFONT_EXTERNAL_FONT 0x01
287 #define ADDFONT_ALLOW_BITMAP 0x02
288 #define ADDFONT_ADD_TO_CACHE 0x04
289 #define ADDFONT_ADD_RESOURCE 0x08 /* added through AddFontResource */
290 #define ADDFONT_VERTICAL_FONT 0x10
291 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
293 typedef struct tagFamily {
294 struct list entry;
295 unsigned int refcount;
296 WCHAR *FamilyName;
297 WCHAR *EnglishName;
298 struct list faces;
299 struct list *replacement;
300 } Family;
302 typedef struct {
303 GLYPHMETRICS gm;
304 ABC abc; /* metrics of the unrotated char */
305 BOOL init;
306 } GM;
308 typedef struct {
309 FLOAT eM11, eM12;
310 FLOAT eM21, eM22;
311 } FMAT2;
313 typedef struct {
314 DWORD hash;
315 LOGFONTW lf;
316 FMAT2 matrix;
317 BOOL can_use_bitmap;
318 } FONT_DESC;
320 typedef struct tagGdiFont GdiFont;
322 #define FIRST_FONT_HANDLE 1
323 #define MAX_FONT_HANDLES 256
325 struct font_handle_entry
327 void *obj;
328 WORD generation; /* generation count for reusing handle values */
331 static struct font_handle_entry font_handles[MAX_FONT_HANDLES];
332 static struct font_handle_entry *next_free;
333 static struct font_handle_entry *next_unused = font_handles;
335 static inline DWORD entry_to_handle( struct font_handle_entry *entry )
337 unsigned int idx = entry - font_handles + FIRST_FONT_HANDLE;
338 return idx | (entry->generation << 16);
341 static inline struct font_handle_entry *handle_entry( DWORD handle )
343 unsigned int idx = LOWORD(handle) - FIRST_FONT_HANDLE;
345 if (idx < MAX_FONT_HANDLES)
347 if (!HIWORD( handle ) || HIWORD( handle ) == font_handles[idx].generation)
348 return &font_handles[idx];
350 if (handle) WARN( "invalid handle 0x%08x\n", handle );
351 return NULL;
354 static DWORD alloc_font_handle( void *obj )
356 struct font_handle_entry *entry;
358 entry = next_free;
359 if (entry)
360 next_free = entry->obj;
361 else if (next_unused < font_handles + MAX_FONT_HANDLES)
362 entry = next_unused++;
363 else
365 ERR( "out of realized font handles\n" );
366 return 0;
368 entry->obj = obj;
369 if (++entry->generation == 0xffff) entry->generation = 1;
370 return entry_to_handle( entry );
373 static void free_font_handle( DWORD handle )
375 struct font_handle_entry *entry;
377 if ((entry = handle_entry( handle )))
379 entry->obj = next_free;
380 next_free = entry;
384 typedef struct {
385 struct list entry;
386 Face *face;
387 GdiFont *font;
388 } CHILD_FONT;
390 struct font_fileinfo {
391 FILETIME writetime;
392 LARGE_INTEGER size;
393 WCHAR path[1];
396 struct tagGdiFont {
397 struct list entry;
398 struct list unused_entry;
399 unsigned int refcount;
400 GM **gm;
401 DWORD gmsize;
402 OUTLINETEXTMETRICW *potm;
403 DWORD total_kern_pairs;
404 KERNINGPAIR *kern_pairs;
405 struct list child_fonts;
407 /* the following members can be accessed without locking, they are never modified after creation */
408 FT_Face ft_face;
409 struct font_mapping *mapping;
410 LPWSTR name;
411 int charset;
412 int codepage;
413 BOOL fake_italic;
414 BOOL fake_bold;
415 BYTE underline;
416 BYTE strikeout;
417 INT orientation;
418 FONT_DESC font_desc;
419 LONG aveWidth, ppem;
420 double scale_y;
421 SHORT yMax;
422 SHORT yMin;
423 DWORD ntmFlags;
424 DWORD aa_flags;
425 UINT ntmCellHeight, ntmAvgWidth;
426 FONTSIGNATURE fs;
427 GdiFont *base_font;
428 VOID *GSUB_Table;
429 const VOID *vert_feature;
430 ULONG ttc_item_offset; /* 0 if font is not a part of TrueType collection */
431 DWORD cache_num;
432 DWORD instance_id;
433 struct font_fileinfo *fileinfo;
436 typedef struct {
437 struct list entry;
438 const WCHAR *font_name;
439 FONTSIGNATURE fs;
440 struct list links;
441 } SYSTEM_LINKS;
443 struct enum_charset_element {
444 DWORD mask;
445 DWORD charset;
446 WCHAR name[LF_FACESIZE];
449 struct enum_charset_list {
450 DWORD total;
451 struct enum_charset_element element[32];
454 #define GM_BLOCK_SIZE 128
455 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
457 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
458 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
459 static unsigned int unused_font_count;
460 #define UNUSED_CACHE_SIZE 10
461 static struct list system_links = LIST_INIT(system_links);
463 static struct list font_subst_list = LIST_INIT(font_subst_list);
465 static struct list font_list = LIST_INIT(font_list);
467 struct freetype_physdev
469 struct gdi_physdev dev;
470 GdiFont *font;
473 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
475 return (struct freetype_physdev *)dev;
478 static const struct gdi_dc_funcs freetype_funcs;
480 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
481 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
482 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
484 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
485 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
486 'W','i','n','d','o','w','s','\\',
487 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
488 'F','o','n','t','s','\0'};
490 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
491 'W','i','n','d','o','w','s',' ','N','T','\\',
492 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
493 'F','o','n','t','s','\0'};
495 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
496 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
497 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
498 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
500 static const WCHAR * const SystemFontValues[] = {
501 System_Value,
502 OEMFont_Value,
503 FixedSys_Value,
504 NULL
507 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
508 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
510 /* Interesting and well-known (frequently-assumed!) font names */
511 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
512 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 };
513 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
514 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
515 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
516 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
517 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
518 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
520 static const WCHAR arial[] = {'A','r','i','a','l',0};
521 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
522 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};
523 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};
524 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
525 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
526 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
527 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
528 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
529 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
531 static const WCHAR *default_serif_list[] =
533 times_new_roman,
534 liberation_serif,
535 bitstream_vera_serif,
536 NULL
539 static const WCHAR *default_fixed_list[] =
541 courier_new,
542 liberation_mono,
543 bitstream_vera_sans_mono,
544 NULL
547 static const WCHAR *default_sans_list[] =
549 arial,
550 liberation_sans,
551 bitstream_vera_sans,
552 NULL
555 typedef struct {
556 WCHAR *name;
557 INT charset;
558 } NameCs;
560 typedef struct tagFontSubst {
561 struct list entry;
562 NameCs from;
563 NameCs to;
564 } FontSubst;
566 /* Registry font cache key and value names */
567 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
568 'F','o','n','t','s',0};
569 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
570 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
571 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
572 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
573 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
574 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
575 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
576 static const WCHAR face_size_value[] = {'S','i','z','e',0};
577 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
578 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
579 static const WCHAR face_flags_value[] = {'F','l','a','g','s',0};
580 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
581 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
582 static const WCHAR face_file_name_value[] = {'F','i','l','e',' ','N','a','m','e','\0'};
583 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
586 struct font_mapping
588 struct list entry;
589 int refcount;
590 dev_t dev;
591 ino_t ino;
592 void *data;
593 size_t size;
596 static struct list mappings_list = LIST_INIT( mappings_list );
598 static UINT default_aa_flags;
599 static HKEY hkey_font_cache;
600 static BOOL antialias_fakes = TRUE;
602 static CRITICAL_SECTION freetype_cs;
603 static CRITICAL_SECTION_DEBUG critsect_debug =
605 0, 0, &freetype_cs,
606 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
607 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
609 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
611 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
613 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
614 static BOOL use_default_fallback = FALSE;
616 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL *vert);
617 static BOOL get_outline_text_metrics(GdiFont *font);
618 static BOOL get_bitmap_text_metrics(GdiFont *font);
619 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
620 static void remove_face_from_cache( Face *face );
622 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
623 'W','i','n','d','o','w','s',' ','N','T','\\',
624 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
625 'S','y','s','t','e','m','L','i','n','k',0};
627 /****************************************
628 * Notes on .fon files
630 * The fonts System, FixedSys and Terminal are special. There are typically multiple
631 * versions installed for different resolutions and codepages. Windows stores which one to use
632 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
633 * Key Meaning
634 * FIXEDFON.FON FixedSys
635 * FONTS.FON System
636 * OEMFONT.FON Terminal
637 * LogPixels Current dpi set by the display control panel applet
638 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
639 * also has a LogPixels value that appears to mirror this)
641 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
642 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
643 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
644 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
645 * so that makes sense.
647 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
648 * to be mapped into the registry on Windows 2000 at least).
649 * I have
650 * woafont=app850.fon
651 * ega80woa.fon=ega80850.fon
652 * ega40woa.fon=ega40850.fon
653 * cga80woa.fon=cga80850.fon
654 * cga40woa.fon=cga40850.fon
657 /* These are all structures needed for the GSUB table */
660 typedef struct {
661 DWORD version;
662 WORD ScriptList;
663 WORD FeatureList;
664 WORD LookupList;
665 } GSUB_Header;
667 typedef struct {
668 CHAR ScriptTag[4];
669 WORD Script;
670 } GSUB_ScriptRecord;
672 typedef struct {
673 WORD ScriptCount;
674 GSUB_ScriptRecord ScriptRecord[1];
675 } GSUB_ScriptList;
677 typedef struct {
678 CHAR LangSysTag[4];
679 WORD LangSys;
680 } GSUB_LangSysRecord;
682 typedef struct {
683 WORD DefaultLangSys;
684 WORD LangSysCount;
685 GSUB_LangSysRecord LangSysRecord[1];
686 } GSUB_Script;
688 typedef struct {
689 WORD LookupOrder; /* Reserved */
690 WORD ReqFeatureIndex;
691 WORD FeatureCount;
692 WORD FeatureIndex[1];
693 } GSUB_LangSys;
695 typedef struct {
696 CHAR FeatureTag[4];
697 WORD Feature;
698 } GSUB_FeatureRecord;
700 typedef struct {
701 WORD FeatureCount;
702 GSUB_FeatureRecord FeatureRecord[1];
703 } GSUB_FeatureList;
705 typedef struct {
706 WORD FeatureParams; /* Reserved */
707 WORD LookupCount;
708 WORD LookupListIndex[1];
709 } GSUB_Feature;
711 typedef struct {
712 WORD LookupCount;
713 WORD Lookup[1];
714 } GSUB_LookupList;
716 typedef struct {
717 WORD LookupType;
718 WORD LookupFlag;
719 WORD SubTableCount;
720 WORD SubTable[1];
721 } GSUB_LookupTable;
723 typedef struct {
724 WORD CoverageFormat;
725 WORD GlyphCount;
726 WORD GlyphArray[1];
727 } GSUB_CoverageFormat1;
729 typedef struct {
730 WORD Start;
731 WORD End;
732 WORD StartCoverageIndex;
733 } GSUB_RangeRecord;
735 typedef struct {
736 WORD CoverageFormat;
737 WORD RangeCount;
738 GSUB_RangeRecord RangeRecord[1];
739 } GSUB_CoverageFormat2;
741 typedef struct {
742 WORD SubstFormat; /* = 1 */
743 WORD Coverage;
744 WORD DeltaGlyphID;
745 } GSUB_SingleSubstFormat1;
747 typedef struct {
748 WORD SubstFormat; /* = 2 */
749 WORD Coverage;
750 WORD GlyphCount;
751 WORD Substitute[1];
752 }GSUB_SingleSubstFormat2;
754 #ifdef HAVE_CARBON_CARBON_H
755 static char *find_cache_dir(void)
757 FSRef ref;
758 OSErr err;
759 static char cached_path[MAX_PATH];
760 static const char *wine = "/Wine", *fonts = "/Fonts";
762 if(*cached_path) return cached_path;
764 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
765 if(err != noErr)
767 WARN("can't create cached data folder\n");
768 return NULL;
770 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
771 if(err != noErr)
773 WARN("can't create cached data path\n");
774 *cached_path = '\0';
775 return NULL;
777 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
779 ERR("Could not create full path\n");
780 *cached_path = '\0';
781 return NULL;
783 strcat(cached_path, wine);
785 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
787 WARN("Couldn't mkdir %s\n", cached_path);
788 *cached_path = '\0';
789 return NULL;
791 strcat(cached_path, fonts);
792 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
794 WARN("Couldn't mkdir %s\n", cached_path);
795 *cached_path = '\0';
796 return NULL;
798 return cached_path;
801 /******************************************************************
802 * expand_mac_font
804 * Extracts individual TrueType font files from a Mac suitcase font
805 * and saves them into the user's caches directory (see
806 * find_cache_dir()).
807 * Returns a NULL terminated array of filenames.
809 * We do this because they are apps that try to read ttf files
810 * themselves and they don't like Mac suitcase files.
812 static char **expand_mac_font(const char *path)
814 FSRef ref;
815 SInt16 res_ref;
816 OSStatus s;
817 unsigned int idx;
818 const char *out_dir;
819 const char *filename;
820 int output_len;
821 struct {
822 char **array;
823 unsigned int size, max_size;
824 } ret;
826 TRACE("path %s\n", path);
828 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
829 if(s != noErr)
831 WARN("failed to get ref\n");
832 return NULL;
835 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
836 if(s != noErr)
838 TRACE("no data fork, so trying resource fork\n");
839 res_ref = FSOpenResFile(&ref, fsRdPerm);
840 if(res_ref == -1)
842 TRACE("unable to open resource fork\n");
843 return NULL;
847 ret.size = 0;
848 ret.max_size = 10;
849 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
850 if(!ret.array)
852 CloseResFile(res_ref);
853 return NULL;
856 out_dir = find_cache_dir();
858 filename = strrchr(path, '/');
859 if(!filename) filename = path;
860 else filename++;
862 /* output filename has the form out_dir/filename_%04x.ttf */
863 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
865 UseResFile(res_ref);
866 idx = 1;
867 while(1)
869 FamRec *fam_rec;
870 unsigned short *num_faces_ptr, num_faces, face;
871 AsscEntry *assoc;
872 Handle fond;
873 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
875 fond = Get1IndResource(fond_res, idx);
876 if(!fond) break;
877 TRACE("got fond resource %d\n", idx);
878 HLock(fond);
880 fam_rec = *(FamRec**)fond;
881 num_faces_ptr = (unsigned short *)(fam_rec + 1);
882 num_faces = GET_BE_WORD(*num_faces_ptr);
883 num_faces++;
884 assoc = (AsscEntry*)(num_faces_ptr + 1);
885 TRACE("num faces %04x\n", num_faces);
886 for(face = 0; face < num_faces; face++, assoc++)
888 Handle sfnt;
889 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
890 unsigned short size, font_id;
891 char *output;
893 size = GET_BE_WORD(assoc->fontSize);
894 font_id = GET_BE_WORD(assoc->fontID);
895 if(size != 0)
897 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
898 continue;
901 TRACE("trying to load sfnt id %04x\n", font_id);
902 sfnt = GetResource(sfnt_res, font_id);
903 if(!sfnt)
905 TRACE("can't get sfnt resource %04x\n", font_id);
906 continue;
909 output = HeapAlloc(GetProcessHeap(), 0, output_len);
910 if(output)
912 int fd;
914 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
916 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
917 if(fd != -1 || errno == EEXIST)
919 if(fd != -1)
921 unsigned char *sfnt_data;
923 HLock(sfnt);
924 sfnt_data = *(unsigned char**)sfnt;
925 write(fd, sfnt_data, GetHandleSize(sfnt));
926 HUnlock(sfnt);
927 close(fd);
929 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
931 ret.max_size *= 2;
932 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
934 ret.array[ret.size++] = output;
936 else
938 WARN("unable to create %s\n", output);
939 HeapFree(GetProcessHeap(), 0, output);
942 ReleaseResource(sfnt);
944 HUnlock(fond);
945 ReleaseResource(fond);
946 idx++;
948 CloseResFile(res_ref);
950 return ret.array;
953 #endif /* HAVE_CARBON_CARBON_H */
955 static inline BOOL is_win9x(void)
957 return GetVersion() & 0x80000000;
960 This function builds an FT_Fixed from a double. It fails if the absolute
961 value of the float number is greater than 32768.
963 static inline FT_Fixed FT_FixedFromFloat(double f)
965 return f * 0x10000;
969 This function builds an FT_Fixed from a FIXED. It simply put f.value
970 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
972 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
974 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
977 static BOOL is_hinting_enabled(void)
979 static int enabled = -1;
981 if (enabled == -1)
983 /* Use the >= 2.2.0 function if available */
984 if (pFT_Get_TrueType_Engine_Type)
986 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
987 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
989 else enabled = FALSE;
990 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
992 return enabled;
995 static BOOL is_subpixel_rendering_enabled( void )
997 #ifdef FT_LCD_FILTER_H
998 static int enabled = -1;
999 if (enabled == -1)
1001 enabled = (pFT_Library_SetLcdFilter &&
1002 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature);
1003 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
1005 return enabled;
1006 #else
1007 return FALSE;
1008 #endif
1012 static const struct list *get_face_list_from_family(const Family *family)
1014 if (!list_empty(&family->faces))
1015 return &family->faces;
1016 else
1017 return family->replacement;
1020 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
1022 Family *family;
1023 Face *face;
1024 const WCHAR *file;
1026 TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
1028 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1030 const struct list *face_list;
1031 if(face_name && strcmpiW(face_name, family->FamilyName))
1032 continue;
1033 face_list = get_face_list_from_family(family);
1034 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
1036 if (!face->file)
1037 continue;
1038 file = strrchrW(face->file, '/');
1039 if(!file)
1040 file = face->file;
1041 else
1042 file++;
1043 if(strcmpiW(file, file_name)) continue;
1044 face->refcount++;
1045 return face;
1048 return NULL;
1051 static Family *find_family_from_name(const WCHAR *name)
1053 Family *family;
1055 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1057 if(!strcmpiW(family->FamilyName, name))
1058 return family;
1061 return NULL;
1064 static Family *find_family_from_any_name(const WCHAR *name)
1066 Family *family;
1068 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1070 if(!strcmpiW(family->FamilyName, name))
1071 return family;
1072 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
1073 return family;
1076 return NULL;
1079 static void DumpSubstList(void)
1081 FontSubst *psub;
1083 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
1085 if(psub->from.charset != -1 || psub->to.charset != -1)
1086 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
1087 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
1088 else
1089 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
1090 debugstr_w(psub->to.name));
1094 static LPWSTR strdupW(LPCWSTR p)
1096 LPWSTR ret;
1097 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
1098 ret = HeapAlloc(GetProcessHeap(), 0, len);
1099 memcpy(ret, p, len);
1100 return ret;
1103 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1104 INT from_charset)
1106 FontSubst *element;
1108 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1110 if(!strcmpiW(element->from.name, from_name) &&
1111 (element->from.charset == from_charset ||
1112 element->from.charset == -1))
1113 return element;
1116 return NULL;
1119 #define ADD_FONT_SUBST_FORCE 1
1121 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1123 FontSubst *from_exist, *to_exist;
1125 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1127 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1129 list_remove(&from_exist->entry);
1130 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
1131 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
1132 HeapFree(GetProcessHeap(), 0, from_exist);
1133 from_exist = NULL;
1136 if(!from_exist)
1138 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1140 if(to_exist)
1142 HeapFree(GetProcessHeap(), 0, subst->to.name);
1143 subst->to.name = strdupW(to_exist->to.name);
1146 list_add_tail(subst_list, &subst->entry);
1148 return TRUE;
1151 HeapFree(GetProcessHeap(), 0, subst->from.name);
1152 HeapFree(GetProcessHeap(), 0, subst->to.name);
1153 HeapFree(GetProcessHeap(), 0, subst);
1154 return FALSE;
1157 static WCHAR *towstr(UINT cp, const char *str)
1159 int len;
1160 WCHAR *wstr;
1162 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1163 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1164 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1165 return wstr;
1168 static char *strWtoA(UINT cp, const WCHAR *str)
1170 int len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL );
1171 char *ret = HeapAlloc( GetProcessHeap(), 0, len );
1172 WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL );
1173 return ret;
1176 static void split_subst_info(NameCs *nc, LPSTR str)
1178 CHAR *p = strrchr(str, ',');
1180 nc->charset = -1;
1181 if(p && *(p+1)) {
1182 nc->charset = strtol(p+1, NULL, 10);
1183 *p = '\0';
1185 nc->name = towstr(CP_ACP, str);
1188 static void LoadSubstList(void)
1190 FontSubst *psub;
1191 HKEY hkey;
1192 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1193 LPSTR value;
1194 LPVOID data;
1196 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1197 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1198 &hkey) == ERROR_SUCCESS) {
1200 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1201 &valuelen, &datalen, NULL, NULL);
1203 valuelen++; /* returned value doesn't include room for '\0' */
1204 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1205 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1207 dlen = datalen;
1208 vlen = valuelen;
1209 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1210 &dlen) == ERROR_SUCCESS) {
1211 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1213 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1214 split_subst_info(&psub->from, value);
1215 split_subst_info(&psub->to, data);
1217 /* Win 2000 doesn't allow mapping between different charsets
1218 or mapping of DEFAULT_CHARSET */
1219 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1220 psub->to.charset == DEFAULT_CHARSET) {
1221 HeapFree(GetProcessHeap(), 0, psub->to.name);
1222 HeapFree(GetProcessHeap(), 0, psub->from.name);
1223 HeapFree(GetProcessHeap(), 0, psub);
1224 } else {
1225 add_font_subst(&font_subst_list, psub, 0);
1227 /* reset dlen and vlen */
1228 dlen = datalen;
1229 vlen = valuelen;
1231 HeapFree(GetProcessHeap(), 0, data);
1232 HeapFree(GetProcessHeap(), 0, value);
1233 RegCloseKey(hkey);
1238 static const LANGID mac_langid_table[] =
1240 MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */
1241 MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */
1242 MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */
1243 MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */
1244 MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */
1245 MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */
1246 MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */
1247 MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */
1248 MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */
1249 MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */
1250 MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */
1251 MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */
1252 MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */
1253 MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */
1254 MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */
1255 MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */
1256 MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */
1257 MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */
1258 MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */
1259 MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
1260 MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */
1261 MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */
1262 MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */
1263 MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */
1264 MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */
1265 MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */
1266 MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */
1267 MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */
1268 MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */
1269 MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */
1270 MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */
1271 MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */
1272 MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */
1273 MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
1274 MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */
1275 MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */
1276 MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */
1277 MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */
1278 MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */
1279 MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */
1280 MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */
1281 0, /* TT_MAC_LANGID_YIDDISH */
1282 MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */
1283 MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */
1284 MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */
1285 MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */
1286 MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */
1287 MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */
1288 MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */
1289 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */
1290 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
1291 MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */
1292 MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */
1293 0, /* TT_MAC_LANGID_MOLDAVIAN */
1294 MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */
1295 MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */
1296 MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */
1297 MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */
1298 MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
1299 MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */
1300 0, /* TT_MAC_LANGID_KURDISH */
1301 MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */
1302 MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */
1303 MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */
1304 MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */
1305 MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */
1306 MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */
1307 MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */
1308 MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */
1309 MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */
1310 MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */
1311 MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */
1312 MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */
1313 MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */
1314 MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */
1315 MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */
1316 MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */
1317 0, /* TT_MAC_LANGID_BURMESE */
1318 MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */
1319 MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */
1320 MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */
1321 MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */
1322 0, /* TT_MAC_LANGID_TAGALOG */
1323 MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
1324 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
1325 MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */
1326 MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */
1327 0, /* TT_MAC_LANGID_GALLA */
1328 0, /* TT_MAC_LANGID_SOMALI */
1329 MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */
1330 0, /* TT_MAC_LANGID_RUANDA */
1331 0, /* TT_MAC_LANGID_RUNDI */
1332 0, /* TT_MAC_LANGID_CHEWA */
1333 MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */
1334 MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */
1335 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
1336 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
1337 MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */
1338 MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */
1339 MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */
1340 0, /* TT_MAC_LANGID_LATIN */
1341 MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */
1342 0, /* TT_MAC_LANGID_GUARANI */
1343 0, /* TT_MAC_LANGID_AYMARA */
1344 MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */
1345 MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */
1346 0, /* TT_MAC_LANGID_DZONGKHA */
1347 0, /* TT_MAC_LANGID_JAVANESE */
1348 0, /* TT_MAC_LANGID_SUNDANESE */
1349 MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */
1350 MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */
1351 MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */
1352 MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */
1353 MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
1354 MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */
1355 MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */
1356 0, /* TT_MAC_LANGID_TONGAN */
1357 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
1358 MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */
1359 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
1362 static inline WORD get_mac_code_page( const FT_SfntName *name )
1364 if (name->encoding_id == TT_MAC_ID_SIMPLIFIED_CHINESE) return 10008; /* special case */
1365 return 10000 + name->encoding_id;
1368 static int match_name_table_language( const FT_SfntName *name, LANGID lang )
1370 LANGID name_lang;
1371 int res = 0;
1373 switch (name->platform_id)
1375 case TT_PLATFORM_MICROSOFT:
1376 res += 5; /* prefer the Microsoft name */
1377 switch (name->encoding_id)
1379 case TT_MS_ID_UNICODE_CS:
1380 case TT_MS_ID_SYMBOL_CS:
1381 name_lang = name->language_id;
1382 break;
1383 default:
1384 return 0;
1386 break;
1387 case TT_PLATFORM_MACINTOSH:
1388 if (!IsValidCodePage( get_mac_code_page( name ))) return 0;
1389 if (name->language_id >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
1390 name_lang = mac_langid_table[name->language_id];
1391 break;
1392 case TT_PLATFORM_APPLE_UNICODE:
1393 res += 2; /* prefer Unicode encodings */
1394 switch (name->encoding_id)
1396 case TT_APPLE_ID_DEFAULT:
1397 case TT_APPLE_ID_ISO_10646:
1398 case TT_APPLE_ID_UNICODE_2_0:
1399 if (name->language_id >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
1400 name_lang = mac_langid_table[name->language_id];
1401 break;
1402 default:
1403 return 0;
1405 break;
1406 default:
1407 return 0;
1409 if (name_lang == lang) res += 30;
1410 else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20;
1411 else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10;
1412 return res;
1415 static WCHAR *copy_name_table_string( const FT_SfntName *name )
1417 WCHAR *ret;
1418 WORD codepage;
1419 int i;
1421 switch (name->platform_id)
1423 case TT_PLATFORM_APPLE_UNICODE:
1424 case TT_PLATFORM_MICROSOFT:
1425 ret = HeapAlloc( GetProcessHeap(), 0, name->string_len + sizeof(WCHAR) );
1426 for (i = 0; i < name->string_len / 2; i++)
1427 ret[i] = (name->string[i * 2] << 8) | name->string[i * 2 + 1];
1428 ret[i] = 0;
1429 return ret;
1430 case TT_PLATFORM_MACINTOSH:
1431 codepage = get_mac_code_page( name );
1432 i = MultiByteToWideChar( codepage, 0, (char *)name->string, name->string_len, NULL, 0 );
1433 ret = HeapAlloc( GetProcessHeap(), 0, (i + 1) * sizeof(WCHAR) );
1434 MultiByteToWideChar( codepage, 0, (char *)name->string, name->string_len, ret, i );
1435 ret[i] = 0;
1436 return ret;
1438 return NULL;
1441 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, LANGID language_id)
1443 FT_SfntName name;
1444 FT_UInt num_names, name_index;
1445 int res, best_lang = 0, best_index = -1;
1447 if (!FT_IS_SFNT(ft_face)) return NULL;
1449 num_names = pFT_Get_Sfnt_Name_Count( ft_face );
1451 for (name_index = 0; name_index < num_names; name_index++)
1453 if (pFT_Get_Sfnt_Name( ft_face, name_index, &name )) continue;
1454 if (name.name_id != name_id) continue;
1455 res = match_name_table_language( &name, language_id );
1456 if (res > best_lang)
1458 best_lang = res;
1459 best_index = name_index;
1463 if (best_index != -1 && !pFT_Get_Sfnt_Name( ft_face, best_index, &name ))
1465 WCHAR *ret = copy_name_table_string( &name );
1466 TRACE( "name %u found platform %u lang %04x %s\n",
1467 name_id, name.platform_id, name.language_id, debugstr_w( ret ));
1468 return ret;
1470 return NULL;
1473 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1475 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1476 if (f1->scalable) return TRUE;
1477 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1478 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1481 static void release_family( Family *family )
1483 if (--family->refcount) return;
1484 assert( list_empty( &family->faces ));
1485 list_remove( &family->entry );
1486 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1487 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1488 HeapFree( GetProcessHeap(), 0, family );
1491 static void release_face( Face *face )
1493 if (--face->refcount) return;
1494 if (face->family)
1496 if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
1497 list_remove( &face->entry );
1498 release_family( face->family );
1500 HeapFree( GetProcessHeap(), 0, face->file );
1501 HeapFree( GetProcessHeap(), 0, face->StyleName );
1502 HeapFree( GetProcessHeap(), 0, face->FullName );
1503 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1504 HeapFree( GetProcessHeap(), 0, face );
1507 static inline int style_order(const Face *face)
1509 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1511 case NTM_REGULAR:
1512 return 0;
1513 case NTM_BOLD:
1514 return 1;
1515 case NTM_ITALIC:
1516 return 2;
1517 case NTM_BOLD | NTM_ITALIC:
1518 return 3;
1519 default:
1520 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1521 debugstr_w(face->family->FamilyName),
1522 debugstr_w(face->StyleName),
1523 face->ntmFlags);
1524 return 9999;
1528 static BOOL insert_face_in_family_list( Face *face, Family *family )
1530 Face *cursor;
1532 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1534 if (faces_equal( face, cursor ))
1536 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1537 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1538 cursor->font_version, face->font_version);
1540 if (face->file && face->dev == cursor->dev && face->ino == cursor->ino)
1542 cursor->refcount++;
1543 TRACE("Font %s already in list, refcount now %d\n",
1544 debugstr_w(face->file), cursor->refcount);
1545 return FALSE;
1547 if (face->font_version <= cursor->font_version)
1549 TRACE("Original font %s is newer so skipping %s\n",
1550 debugstr_w(cursor->file), debugstr_w(face->file));
1551 return FALSE;
1553 else
1555 TRACE("Replacing original %s with %s\n",
1556 debugstr_w(cursor->file), debugstr_w(face->file));
1557 list_add_before( &cursor->entry, &face->entry );
1558 face->family = family;
1559 family->refcount++;
1560 face->refcount++;
1561 release_face( cursor );
1562 return TRUE;
1565 else
1566 TRACE("Adding new %s\n", debugstr_w(face->file));
1568 if (style_order( face ) < style_order( cursor )) break;
1571 list_add_before( &cursor->entry, &face->entry );
1572 face->family = family;
1573 family->refcount++;
1574 face->refcount++;
1575 return TRUE;
1578 /****************************************************************
1579 * NB This function stores the ptrs to the strings to save copying.
1580 * Don't free them after calling.
1582 static Family *create_family( WCHAR *name, WCHAR *english_name )
1584 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1585 family->refcount = 1;
1586 family->FamilyName = name;
1587 family->EnglishName = english_name;
1588 list_init( &family->faces );
1589 family->replacement = &family->faces;
1590 list_add_tail( &font_list, &family->entry );
1592 return family;
1595 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1597 DWORD type, size = sizeof(DWORD);
1599 if (RegQueryValueExW(hkey, value, NULL, &type, (BYTE *)data, &size) ||
1600 type != REG_DWORD || size != sizeof(DWORD))
1602 *data = 0;
1603 return ERROR_BAD_CONFIGURATION;
1605 return ERROR_SUCCESS;
1608 static inline LONG reg_load_ftlong(HKEY hkey, const WCHAR *value, FT_Long *data)
1610 DWORD dw;
1611 LONG ret = reg_load_dword(hkey, value, &dw);
1612 *data = dw;
1613 return ret;
1616 static inline LONG reg_load_ftshort(HKEY hkey, const WCHAR *value, FT_Short *data)
1618 DWORD dw;
1619 LONG ret = reg_load_dword(hkey, value, &dw);
1620 *data = dw;
1621 return ret;
1624 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1626 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1629 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1631 DWORD needed, strike_index = 0;
1632 HKEY hkey_strike;
1634 /* If we have a File Name key then this is a real font, not just the parent
1635 key of a bunch of non-scalable strikes */
1636 needed = buffer_size;
1637 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1639 Face *face;
1640 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1641 face->cached_enum_data = NULL;
1642 face->family = NULL;
1644 face->refcount = 1;
1645 face->file = strdupW( buffer );
1646 face->StyleName = strdupW(face_name);
1648 needed = buffer_size;
1649 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1650 face->FullName = strdupW( buffer );
1651 else
1652 face->FullName = NULL;
1654 reg_load_ftlong(hkey_face, face_index_value, &face->face_index);
1655 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1656 reg_load_ftlong(hkey_face, face_version_value, &face->font_version);
1657 reg_load_dword(hkey_face, face_flags_value, &face->flags);
1659 needed = sizeof(face->fs);
1660 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1662 if(reg_load_ftshort(hkey_face, face_height_value, &face->size.height) != ERROR_SUCCESS)
1664 face->scalable = TRUE;
1665 memset(&face->size, 0, sizeof(face->size));
1667 else
1669 face->scalable = FALSE;
1670 reg_load_ftshort(hkey_face, face_width_value, &face->size.width);
1671 reg_load_ftlong(hkey_face, face_size_value, &face->size.size);
1672 reg_load_ftlong(hkey_face, face_x_ppem_value, &face->size.x_ppem);
1673 reg_load_ftlong(hkey_face, face_y_ppem_value, &face->size.y_ppem);
1674 reg_load_ftshort(hkey_face, face_internal_leading_value, &face->size.internal_leading);
1676 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1677 face->size.height, face->size.width, face->size.size >> 6,
1678 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1681 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1682 face->fs.fsCsb[0], face->fs.fsCsb[1],
1683 face->fs.fsUsb[0], face->fs.fsUsb[1],
1684 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1686 if (insert_face_in_family_list(face, family))
1687 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1689 release_face( face );
1692 /* load bitmap strikes */
1694 needed = buffer_size;
1695 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1697 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1699 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1700 RegCloseKey(hkey_strike);
1702 needed = buffer_size;
1706 /* move vertical fonts after their horizontal counterpart */
1707 /* assumes that font_list is already sorted by family name */
1708 static void reorder_vertical_fonts(void)
1710 Family *family, *next, *vert_family;
1711 struct list *ptr, *vptr;
1712 struct list vertical_families = LIST_INIT( vertical_families );
1714 LIST_FOR_EACH_ENTRY_SAFE( family, next, &font_list, Family, entry )
1716 if (family->FamilyName[0] != '@') continue;
1717 list_remove( &family->entry );
1718 list_add_tail( &vertical_families, &family->entry );
1721 ptr = list_head( &font_list );
1722 vptr = list_head( &vertical_families );
1723 while (ptr && vptr)
1725 family = LIST_ENTRY( ptr, Family, entry );
1726 vert_family = LIST_ENTRY( vptr, Family, entry );
1727 if (strcmpiW( family->FamilyName, vert_family->FamilyName + 1 ) > 0)
1729 list_remove( vptr );
1730 list_add_before( ptr, vptr );
1731 vptr = list_head( &vertical_families );
1733 else ptr = list_next( &font_list, ptr );
1735 list_move_tail( &font_list, &vertical_families );
1738 static void load_font_list_from_cache(HKEY hkey_font_cache)
1740 DWORD size, family_index = 0;
1741 Family *family;
1742 HKEY hkey_family;
1743 WCHAR buffer[4096];
1745 size = sizeof(buffer);
1746 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1748 WCHAR *english_family = NULL;
1749 WCHAR *family_name = strdupW( buffer );
1750 DWORD face_index = 0;
1752 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1753 TRACE("opened family key %s\n", debugstr_w(family_name));
1754 size = sizeof(buffer);
1755 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1756 english_family = strdupW( buffer );
1758 family = create_family(family_name, english_family);
1760 if(english_family)
1762 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1763 subst->from.name = strdupW(english_family);
1764 subst->from.charset = -1;
1765 subst->to.name = strdupW(family_name);
1766 subst->to.charset = -1;
1767 add_font_subst(&font_subst_list, subst, 0);
1770 size = sizeof(buffer);
1771 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1773 WCHAR *face_name = strdupW( buffer );
1774 HKEY hkey_face;
1776 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1778 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1779 RegCloseKey(hkey_face);
1781 HeapFree( GetProcessHeap(), 0, face_name );
1782 size = sizeof(buffer);
1784 RegCloseKey(hkey_family);
1785 release_family( family );
1786 size = sizeof(buffer);
1789 reorder_vertical_fonts();
1792 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1794 LONG ret;
1795 HKEY hkey_wine_fonts;
1797 /* We don't want to create the fonts key as volatile, so open this first */
1798 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1799 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1800 if(ret != ERROR_SUCCESS)
1802 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1803 return ret;
1806 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1807 KEY_ALL_ACCESS, NULL, hkey, disposition);
1808 RegCloseKey(hkey_wine_fonts);
1809 return ret;
1812 static void add_face_to_cache(Face *face)
1814 HKEY hkey_family, hkey_face;
1815 WCHAR *face_key_name;
1817 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1818 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1819 if(face->family->EnglishName)
1820 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1821 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1823 if(face->scalable)
1824 face_key_name = face->StyleName;
1825 else
1827 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1828 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1829 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1831 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1832 &hkey_face, NULL);
1833 if(!face->scalable)
1834 HeapFree(GetProcessHeap(), 0, face_key_name);
1836 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1837 (strlenW(face->file) + 1) * sizeof(WCHAR));
1838 if (face->FullName)
1839 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1840 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1842 reg_save_dword(hkey_face, face_index_value, face->face_index);
1843 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1844 reg_save_dword(hkey_face, face_version_value, face->font_version);
1845 if (face->flags) reg_save_dword(hkey_face, face_flags_value, face->flags);
1847 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1849 if(!face->scalable)
1851 reg_save_dword(hkey_face, face_height_value, face->size.height);
1852 reg_save_dword(hkey_face, face_width_value, face->size.width);
1853 reg_save_dword(hkey_face, face_size_value, face->size.size);
1854 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1855 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1856 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1858 RegCloseKey(hkey_face);
1859 RegCloseKey(hkey_family);
1862 static void remove_face_from_cache( Face *face )
1864 HKEY hkey_family;
1866 RegOpenKeyExW( hkey_font_cache, face->family->FamilyName, 0, KEY_ALL_ACCESS, &hkey_family );
1868 if (face->scalable)
1870 RegDeleteKeyW( hkey_family, face->StyleName );
1872 else
1874 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1875 WCHAR *face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1876 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1877 RegDeleteKeyW( hkey_family, face_key_name );
1878 HeapFree(GetProcessHeap(), 0, face_key_name);
1880 RegCloseKey(hkey_family);
1883 static WCHAR *prepend_at(WCHAR *family)
1885 WCHAR *str;
1887 if (!family)
1888 return NULL;
1890 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1891 str[0] = '@';
1892 strcpyW(str + 1, family);
1893 HeapFree(GetProcessHeap(), 0, family);
1894 return str;
1897 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1899 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT) );
1900 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1902 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1903 if (!*name)
1905 *name = *english;
1906 *english = NULL;
1908 else if (!strcmpiW( *name, *english ))
1910 HeapFree( GetProcessHeap(), 0, *english );
1911 *english = NULL;
1914 if (vertical)
1916 *name = prepend_at( *name );
1917 *english = prepend_at( *english );
1921 static Family *get_family( FT_Face ft_face, BOOL vertical )
1923 Family *family;
1924 WCHAR *name, *english_name;
1926 get_family_names( ft_face, &name, &english_name, vertical );
1928 family = find_family_from_name( name );
1930 if (!family)
1932 family = create_family( name, english_name );
1933 if (english_name)
1935 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1936 subst->from.name = strdupW( english_name );
1937 subst->from.charset = -1;
1938 subst->to.name = strdupW( name );
1939 subst->to.charset = -1;
1940 add_font_subst( &font_subst_list, subst, 0 );
1943 else
1945 HeapFree( GetProcessHeap(), 0, name );
1946 HeapFree( GetProcessHeap(), 0, english_name );
1947 family->refcount++;
1950 return family;
1953 static inline FT_Fixed get_font_version( FT_Face ft_face )
1955 FT_Fixed version = 0;
1956 TT_Header *header;
1958 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1959 if (header) version = header->Font_Revision;
1961 return version;
1964 static inline DWORD get_ntm_flags( FT_Face ft_face )
1966 DWORD flags = 0;
1967 FT_ULong table_size = 0;
1968 FT_WinFNT_HeaderRec winfnt_header;
1970 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1971 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1973 /* fixup the flag for our fake-bold implementation. */
1974 if (!FT_IS_SCALABLE( ft_face ) &&
1975 !pFT_Get_WinFNT_Header( ft_face, &winfnt_header ) &&
1976 winfnt_header.weight > FW_NORMAL )
1977 flags |= NTM_BOLD;
1979 if (flags == 0) flags = NTM_REGULAR;
1981 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1982 flags |= NTM_PS_OPENTYPE;
1984 return flags;
1987 static inline void get_bitmap_size( FT_Face ft_face, Bitmap_Size *face_size )
1989 My_FT_Bitmap_Size *size;
1990 FT_WinFNT_HeaderRec winfnt_header;
1992 size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1993 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1994 size->height, size->width, size->size >> 6,
1995 size->x_ppem >> 6, size->y_ppem >> 6);
1996 face_size->height = size->height;
1997 face_size->width = size->width;
1998 face_size->size = size->size;
1999 face_size->x_ppem = size->x_ppem;
2000 face_size->y_ppem = size->y_ppem;
2002 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header )) {
2003 face_size->internal_leading = winfnt_header.internal_leading;
2004 if (winfnt_header.external_leading > 0 &&
2005 (face_size->height ==
2006 winfnt_header.pixel_height + winfnt_header.external_leading))
2007 face_size->height = winfnt_header.pixel_height;
2011 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
2013 TT_OS2 *os2;
2014 FT_UInt dummy;
2015 CHARSETINFO csi;
2016 FT_WinFNT_HeaderRec winfnt_header;
2017 int i;
2019 memset( fs, 0, sizeof(*fs) );
2021 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
2022 if (os2)
2024 fs->fsUsb[0] = os2->ulUnicodeRange1;
2025 fs->fsUsb[1] = os2->ulUnicodeRange2;
2026 fs->fsUsb[2] = os2->ulUnicodeRange3;
2027 fs->fsUsb[3] = os2->ulUnicodeRange4;
2029 if (os2->version == 0)
2031 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
2032 fs->fsCsb[0] = FS_LATIN1;
2033 else
2034 fs->fsCsb[0] = FS_SYMBOL;
2036 else
2038 fs->fsCsb[0] = os2->ulCodePageRange1;
2039 fs->fsCsb[1] = os2->ulCodePageRange2;
2042 else
2044 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
2046 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
2047 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
2048 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
2049 *fs = csi.fs;
2053 if (fs->fsCsb[0] == 0)
2055 /* let's see if we can find any interesting cmaps */
2056 for (i = 0; i < ft_face->num_charmaps; i++)
2058 switch (ft_face->charmaps[i]->encoding)
2060 case FT_ENCODING_UNICODE:
2061 case FT_ENCODING_APPLE_ROMAN:
2062 fs->fsCsb[0] |= FS_LATIN1;
2063 break;
2064 case FT_ENCODING_MS_SYMBOL:
2065 fs->fsCsb[0] |= FS_SYMBOL;
2066 break;
2067 default:
2068 break;
2074 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
2075 DWORD flags )
2077 struct stat st;
2078 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
2080 face->refcount = 1;
2081 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
2082 if (!face->StyleName) face->StyleName = towstr( CP_ACP, ft_face->style_name );
2084 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
2085 if (flags & ADDFONT_VERTICAL_FONT)
2086 face->FullName = prepend_at( face->FullName );
2088 face->dev = 0;
2089 face->ino = 0;
2090 if (file)
2092 face->file = towstr( CP_UNIXCP, file );
2093 face->font_data_ptr = NULL;
2094 face->font_data_size = 0;
2095 if (!stat( file, &st ))
2097 face->dev = st.st_dev;
2098 face->ino = st.st_ino;
2101 else
2103 face->file = NULL;
2104 face->font_data_ptr = font_data_ptr;
2105 face->font_data_size = font_data_size;
2108 face->face_index = face_index;
2109 get_fontsig( ft_face, &face->fs );
2110 face->ntmFlags = get_ntm_flags( ft_face );
2111 face->font_version = get_font_version( ft_face );
2113 if (FT_IS_SCALABLE( ft_face ))
2115 memset( &face->size, 0, sizeof(face->size) );
2116 face->scalable = TRUE;
2118 else
2120 get_bitmap_size( ft_face, &face->size );
2121 face->scalable = FALSE;
2124 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
2125 face->flags = flags;
2126 face->family = NULL;
2127 face->cached_enum_data = NULL;
2129 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
2130 face->fs.fsCsb[0], face->fs.fsCsb[1],
2131 face->fs.fsUsb[0], face->fs.fsUsb[1],
2132 face->fs.fsUsb[2], face->fs.fsUsb[3]);
2134 return face;
2137 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
2138 FT_Long face_index, DWORD flags )
2140 Face *face;
2141 Family *family;
2143 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags );
2144 family = get_family( ft_face, flags & ADDFONT_VERTICAL_FONT );
2145 if (strlenW(family->FamilyName) >= LF_FACESIZE)
2147 WARN("Ignoring %s because name is too long\n", debugstr_w(family->FamilyName));
2148 release_face( face );
2149 release_family( family );
2150 return;
2153 if (insert_face_in_family_list( face, family ))
2155 if (flags & ADDFONT_ADD_TO_CACHE)
2156 add_face_to_cache( face );
2158 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
2159 debugstr_w(face->StyleName));
2161 release_face( face );
2162 release_family( family );
2165 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
2166 FT_Long face_index, BOOL allow_bitmap )
2168 FT_Error err;
2169 TT_OS2 *pOS2;
2170 FT_Face ft_face;
2172 if (file)
2174 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
2175 err = pFT_New_Face(library, file, face_index, &ft_face);
2177 else
2179 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
2180 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
2183 if (err != 0)
2185 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
2186 return NULL;
2189 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
2190 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
2192 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
2193 goto fail;
2196 if (!FT_IS_SFNT( ft_face ))
2198 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
2200 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
2201 goto fail;
2204 else
2206 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
2207 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
2208 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
2210 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
2211 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
2212 goto fail;
2215 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
2216 we don't want to load these. */
2217 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
2219 FT_ULong len = 0;
2221 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
2223 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
2224 goto fail;
2229 if (!ft_face->family_name || !ft_face->style_name)
2231 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
2232 goto fail;
2235 return ft_face;
2236 fail:
2237 pFT_Done_Face( ft_face );
2238 return NULL;
2241 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
2243 FT_Face ft_face;
2244 FT_Long face_index = 0, num_faces;
2245 INT ret = 0;
2247 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
2248 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
2250 #ifdef HAVE_CARBON_CARBON_H
2251 if(file)
2253 char **mac_list = expand_mac_font(file);
2254 if(mac_list)
2256 BOOL had_one = FALSE;
2257 char **cursor;
2258 for(cursor = mac_list; *cursor; cursor++)
2260 had_one = TRUE;
2261 AddFontToList(*cursor, NULL, 0, flags);
2262 HeapFree(GetProcessHeap(), 0, *cursor);
2264 HeapFree(GetProcessHeap(), 0, mac_list);
2265 if(had_one)
2266 return 1;
2269 #endif /* HAVE_CARBON_CARBON_H */
2271 do {
2272 const DWORD FS_DBCS_MASK = FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB;
2273 FONTSIGNATURE fs;
2275 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_ALLOW_BITMAP );
2276 if (!ft_face) return 0;
2278 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
2280 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
2281 pFT_Done_Face(ft_face);
2282 return 0;
2285 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags);
2286 ++ret;
2288 get_fontsig(ft_face, &fs);
2289 if (fs.fsCsb[0] & FS_DBCS_MASK)
2291 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index,
2292 flags | ADDFONT_VERTICAL_FONT);
2293 ++ret;
2296 num_faces = ft_face->num_faces;
2297 pFT_Done_Face(ft_face);
2298 } while(num_faces > ++face_index);
2299 return ret;
2302 static int remove_font_resource( const char *file, DWORD flags )
2304 Family *family, *family_next;
2305 Face *face, *face_next;
2306 struct stat st;
2307 int count = 0;
2309 if (stat( file, &st ) == -1) return 0;
2310 LIST_FOR_EACH_ENTRY_SAFE( family, family_next, &font_list, Family, entry )
2312 family->refcount++;
2313 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, Face, entry )
2315 if (!face->file) continue;
2316 if (LOWORD(face->flags) != LOWORD(flags)) continue;
2317 if (st.st_dev == face->dev && st.st_ino == face->ino)
2319 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount );
2320 release_face( face );
2321 count++;
2324 release_family( family );
2326 return count;
2329 static void DumpFontList(void)
2331 Family *family;
2332 Face *face;
2334 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2335 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
2336 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2337 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
2338 if(!face->scalable)
2339 TRACE(" %d", face->size.height);
2340 TRACE("\n");
2345 static BOOL map_font_family(const WCHAR *orig, const WCHAR *repl)
2347 Family *family = find_family_from_any_name(repl);
2348 if (family != NULL)
2350 Family *new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2351 if (new_family != NULL)
2353 TRACE("mapping %s to %s\n", debugstr_w(repl), debugstr_w(orig));
2354 new_family->FamilyName = strdupW(orig);
2355 new_family->EnglishName = NULL;
2356 list_init(&new_family->faces);
2357 new_family->replacement = &family->faces;
2358 list_add_tail(&font_list, &new_family->entry);
2359 return TRUE;
2362 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(repl));
2363 return FALSE;
2366 /***********************************************************
2367 * The replacement list is a way to map an entire font
2368 * family onto another family. For example adding
2370 * [HKCU\Software\Wine\Fonts\Replacements]
2371 * "Wingdings"="Winedings"
2373 * would enumerate the Winedings font both as Winedings and
2374 * Wingdings. However if a real Wingdings font is present the
2375 * replacement does not take place.
2378 static void LoadReplaceList(void)
2380 HKEY hkey;
2381 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2382 LPWSTR value;
2383 LPVOID data;
2385 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2386 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
2388 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2389 &valuelen, &datalen, NULL, NULL);
2391 valuelen++; /* returned value doesn't include room for '\0' */
2392 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2393 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2395 dlen = datalen;
2396 vlen = valuelen;
2397 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data, &dlen) == ERROR_SUCCESS)
2399 /* "NewName"="Oldname" */
2400 if(!find_family_from_any_name(value))
2402 if (type == REG_MULTI_SZ)
2404 WCHAR *replace = data;
2405 while(*replace)
2407 if (map_font_family(value, replace))
2408 break;
2409 replace += strlenW(replace) + 1;
2412 else if (type == REG_SZ)
2413 map_font_family(value, data);
2415 else
2416 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2418 /* reset dlen and vlen */
2419 dlen = datalen;
2420 vlen = valuelen;
2422 HeapFree(GetProcessHeap(), 0, data);
2423 HeapFree(GetProcessHeap(), 0, value);
2424 RegCloseKey(hkey);
2428 static const WCHAR *font_links_list[] =
2430 Lucida_Sans_Unicode,
2431 Microsoft_Sans_Serif,
2432 Tahoma
2435 static const struct font_links_defaults_list
2437 /* Keyed off substitution for "MS Shell Dlg" */
2438 const WCHAR *shelldlg;
2439 /* Maximum of four substitutes, plus terminating NULL pointer */
2440 const WCHAR *substitutes[5];
2441 } font_links_defaults_list[] =
2443 /* Non East-Asian */
2444 { Tahoma, /* FIXME unverified ordering */
2445 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2447 /* Below lists are courtesy of
2448 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2450 /* Japanese */
2451 { MS_UI_Gothic,
2452 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2454 /* Chinese Simplified */
2455 { SimSun,
2456 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2458 /* Korean */
2459 { Gulim,
2460 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2462 /* Chinese Traditional */
2463 { PMingLiU,
2464 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2469 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2471 SYSTEM_LINKS *font_link;
2473 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2475 if(!strcmpiW(font_link->font_name, name))
2476 return font_link;
2479 return NULL;
2482 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2484 const WCHAR *value;
2485 int i;
2486 FontSubst *psub;
2487 Family *family;
2488 Face *face;
2489 const WCHAR *file;
2491 if (values)
2493 SYSTEM_LINKS *font_link;
2495 psub = get_font_subst(&font_subst_list, name, -1);
2496 /* Don't store fonts that are only substitutes for other fonts */
2497 if(psub)
2499 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2500 return;
2503 font_link = find_font_link(name);
2504 if (font_link == NULL)
2506 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2507 font_link->font_name = strdupW(name);
2508 list_init(&font_link->links);
2509 list_add_tail(&system_links, &font_link->entry);
2512 memset(&font_link->fs, 0, sizeof font_link->fs);
2513 for (i = 0; values[i] != NULL; i++)
2515 const struct list *face_list;
2516 CHILD_FONT *child_font;
2518 value = values[i];
2519 if (!strcmpiW(name,value))
2520 continue;
2521 psub = get_font_subst(&font_subst_list, value, -1);
2522 if(psub)
2523 value = psub->to.name;
2524 family = find_family_from_name(value);
2525 if (!family)
2526 continue;
2527 file = NULL;
2528 /* Use first extant filename for this Family */
2529 face_list = get_face_list_from_family(family);
2530 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2532 if (!face->file)
2533 continue;
2534 file = strrchrW(face->file, '/');
2535 if (!file)
2536 file = face->file;
2537 else
2538 file++;
2539 break;
2541 if (!file)
2542 continue;
2543 face = find_face_from_filename(file, value);
2544 if(!face)
2546 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2547 continue;
2550 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2551 child_font->face = face;
2552 child_font->font = NULL;
2553 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2554 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2555 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2556 child_font->face->face_index);
2557 list_add_tail(&font_link->links, &child_font->entry);
2559 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2565 /*************************************************************
2566 * init_system_links
2568 static BOOL init_system_links(void)
2570 HKEY hkey;
2571 BOOL ret = FALSE;
2572 DWORD type, max_val, max_data, val_len, data_len, index;
2573 WCHAR *value, *data;
2574 WCHAR *entry, *next;
2575 SYSTEM_LINKS *font_link, *system_font_link;
2576 CHILD_FONT *child_font;
2577 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2578 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2579 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2580 Face *face;
2581 FontSubst *psub;
2582 UINT i, j;
2584 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2586 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2587 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2588 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2589 val_len = max_val + 1;
2590 data_len = max_data;
2591 index = 0;
2592 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2594 psub = get_font_subst(&font_subst_list, value, -1);
2595 /* Don't store fonts that are only substitutes for other fonts */
2596 if(psub)
2598 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2599 goto next;
2601 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2602 font_link->font_name = strdupW(value);
2603 memset(&font_link->fs, 0, sizeof font_link->fs);
2604 list_init(&font_link->links);
2605 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2607 WCHAR *face_name;
2608 CHILD_FONT *child_font;
2610 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2612 next = entry + strlenW(entry) + 1;
2614 face_name = strchrW(entry, ',');
2615 if(face_name)
2617 *face_name++ = 0;
2618 while(isspaceW(*face_name))
2619 face_name++;
2621 psub = get_font_subst(&font_subst_list, face_name, -1);
2622 if(psub)
2623 face_name = psub->to.name;
2625 face = find_face_from_filename(entry, face_name);
2626 if(!face)
2628 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2629 continue;
2632 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2633 child_font->face = face;
2634 child_font->font = NULL;
2635 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2636 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2637 TRACE("Adding file %s index %ld\n",
2638 debugstr_w(child_font->face->file), child_font->face->face_index);
2639 list_add_tail(&font_link->links, &child_font->entry);
2641 list_add_tail(&system_links, &font_link->entry);
2642 next:
2643 val_len = max_val + 1;
2644 data_len = max_data;
2647 HeapFree(GetProcessHeap(), 0, value);
2648 HeapFree(GetProcessHeap(), 0, data);
2649 RegCloseKey(hkey);
2653 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2654 if (!psub) {
2655 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2656 goto skip_internal;
2659 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2661 const FontSubst *psub2;
2662 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2664 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2666 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2667 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2669 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2670 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2672 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2674 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2678 skip_internal:
2680 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2681 that Tahoma has */
2683 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2684 system_font_link->font_name = strdupW(System);
2685 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2686 list_init(&system_font_link->links);
2688 face = find_face_from_filename(tahoma_ttf, Tahoma);
2689 if(face)
2691 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2692 child_font->face = face;
2693 child_font->font = NULL;
2694 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2695 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2696 TRACE("Found Tahoma in %s index %ld\n",
2697 debugstr_w(child_font->face->file), child_font->face->face_index);
2698 list_add_tail(&system_font_link->links, &child_font->entry);
2700 font_link = find_font_link(Tahoma);
2701 if (font_link != NULL)
2703 CHILD_FONT *font_link_entry;
2704 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2706 CHILD_FONT *new_child;
2707 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2708 new_child->face = font_link_entry->face;
2709 new_child->font = NULL;
2710 new_child->face->refcount++;
2711 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2712 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2713 list_add_tail(&system_font_link->links, &new_child->entry);
2716 list_add_tail(&system_links, &system_font_link->entry);
2717 return ret;
2720 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2722 DIR *dir;
2723 struct dirent *dent;
2724 char path[MAX_PATH];
2726 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2728 dir = opendir(dirname);
2729 if(!dir) {
2730 WARN("Can't open directory %s\n", debugstr_a(dirname));
2731 return FALSE;
2733 while((dent = readdir(dir)) != NULL) {
2734 struct stat statbuf;
2736 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2737 continue;
2739 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2741 sprintf(path, "%s/%s", dirname, dent->d_name);
2743 if(stat(path, &statbuf) == -1)
2745 WARN("Can't stat %s\n", debugstr_a(path));
2746 continue;
2748 if(S_ISDIR(statbuf.st_mode))
2749 ReadFontDir(path, external_fonts);
2750 else
2752 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2753 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2754 AddFontToList(path, NULL, 0, addfont_flags);
2757 closedir(dir);
2758 return TRUE;
2761 #ifdef SONAME_LIBFONTCONFIG
2763 static BOOL fontconfig_enabled;
2765 static UINT parse_aa_pattern( FcPattern *pattern )
2767 FcBool antialias;
2768 int rgba;
2769 UINT aa_flags = 0;
2771 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2772 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2774 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2776 switch (rgba)
2778 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2779 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2780 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2781 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2782 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2785 return aa_flags;
2788 static void init_fontconfig(void)
2790 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2792 if (!fc_handle)
2794 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2795 return;
2798 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2799 LOAD_FUNCPTR(FcConfigSubstitute);
2800 LOAD_FUNCPTR(FcFontList);
2801 LOAD_FUNCPTR(FcFontSetDestroy);
2802 LOAD_FUNCPTR(FcInit);
2803 LOAD_FUNCPTR(FcObjectSetAdd);
2804 LOAD_FUNCPTR(FcObjectSetCreate);
2805 LOAD_FUNCPTR(FcObjectSetDestroy);
2806 LOAD_FUNCPTR(FcPatternCreate);
2807 LOAD_FUNCPTR(FcPatternDestroy);
2808 LOAD_FUNCPTR(FcPatternGetBool);
2809 LOAD_FUNCPTR(FcPatternGetInteger);
2810 LOAD_FUNCPTR(FcPatternGetString);
2811 #undef LOAD_FUNCPTR
2813 if (pFcInit())
2815 FcPattern *pattern = pFcPatternCreate();
2816 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2817 default_aa_flags = parse_aa_pattern( pattern );
2818 pFcPatternDestroy( pattern );
2819 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2820 fontconfig_enabled = TRUE;
2824 static void load_fontconfig_fonts(void)
2826 FcPattern *pat;
2827 FcObjectSet *os;
2828 FcFontSet *fontset;
2829 int i, len;
2830 char *file;
2831 const char *ext;
2833 if (!fontconfig_enabled) return;
2835 pat = pFcPatternCreate();
2836 os = pFcObjectSetCreate();
2837 pFcObjectSetAdd(os, FC_FILE);
2838 pFcObjectSetAdd(os, FC_SCALABLE);
2839 pFcObjectSetAdd(os, FC_ANTIALIAS);
2840 pFcObjectSetAdd(os, FC_RGBA);
2841 fontset = pFcFontList(NULL, pat, os);
2842 if(!fontset) return;
2843 for(i = 0; i < fontset->nfont; i++) {
2844 FcBool scalable;
2845 DWORD aa_flags;
2847 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2848 continue;
2850 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2852 /* We're just interested in OT/TT fonts for now, so this hack just
2853 picks up the scalable fonts without extensions .pf[ab] to save time
2854 loading every other font */
2856 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2858 TRACE("not scalable\n");
2859 continue;
2862 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2863 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2865 len = strlen( file );
2866 if(len < 4) continue;
2867 ext = &file[ len - 3 ];
2868 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2869 AddFontToList(file, NULL, 0,
2870 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2872 pFcFontSetDestroy(fontset);
2873 pFcObjectSetDestroy(os);
2874 pFcPatternDestroy(pat);
2877 #elif defined(HAVE_CARBON_CARBON_H)
2879 static void load_mac_font_callback(const void *value, void *context)
2881 CFStringRef pathStr = value;
2882 CFIndex len;
2883 char* path;
2885 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2886 path = HeapAlloc(GetProcessHeap(), 0, len);
2887 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2889 TRACE("font file %s\n", path);
2890 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2892 HeapFree(GetProcessHeap(), 0, path);
2895 static void load_mac_fonts(void)
2897 CFStringRef removeDupesKey;
2898 CFBooleanRef removeDupesValue;
2899 CFDictionaryRef options;
2900 CTFontCollectionRef col;
2901 CFArrayRef descs;
2902 CFMutableSetRef paths;
2903 CFIndex i;
2905 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2906 removeDupesValue = kCFBooleanTrue;
2907 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2908 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2909 col = CTFontCollectionCreateFromAvailableFonts(options);
2910 if (options) CFRelease(options);
2911 if (!col)
2913 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2914 return;
2917 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2918 CFRelease(col);
2919 if (!descs)
2921 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2922 return;
2925 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2926 if (!paths)
2928 WARN("CFSetCreateMutable failed\n");
2929 CFRelease(descs);
2930 return;
2933 for (i = 0; i < CFArrayGetCount(descs); i++)
2935 CTFontDescriptorRef desc;
2936 CFURLRef url;
2937 CFStringRef ext;
2938 CFStringRef path;
2940 desc = CFArrayGetValueAtIndex(descs, i);
2942 #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2943 url = CTFontDescriptorCopyAttribute(desc, kCTFontURLAttribute);
2944 #else
2945 /* CTFontDescriptor doesn't support kCTFontURLAttribute prior to 10.6, so
2946 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2948 CTFontRef font;
2949 ATSFontRef atsFont;
2950 OSStatus status;
2951 FSRef fsref;
2953 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2954 if (!font) continue;
2956 atsFont = CTFontGetPlatformFont(font, NULL);
2957 if (!atsFont)
2959 CFRelease(font);
2960 continue;
2963 status = ATSFontGetFileReference(atsFont, &fsref);
2964 CFRelease(font);
2965 if (status != noErr) continue;
2967 url = CFURLCreateFromFSRef(NULL, &fsref);
2969 #endif
2970 if (!url) continue;
2972 ext = CFURLCopyPathExtension(url);
2973 if (ext)
2975 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2976 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2977 CFRelease(ext);
2978 if (skip)
2980 CFRelease(url);
2981 continue;
2985 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2986 CFRelease(url);
2987 if (!path) continue;
2989 CFSetAddValue(paths, path);
2990 CFRelease(path);
2993 CFRelease(descs);
2995 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2996 CFRelease(paths);
2999 #endif
3001 static char *get_font_dir(void)
3003 const char *build_dir, *data_dir;
3004 char *name = NULL;
3006 if ((data_dir = wine_get_data_dir()))
3008 if (!(name = HeapAlloc( GetProcessHeap(), 0, strlen(data_dir) + 1 + sizeof(WINE_FONT_DIR) )))
3009 return NULL;
3010 strcpy( name, data_dir );
3011 strcat( name, "/" );
3012 strcat( name, WINE_FONT_DIR );
3014 else if ((build_dir = wine_get_build_dir()))
3016 if (!(name = HeapAlloc( GetProcessHeap(), 0, strlen(build_dir) + sizeof("/fonts") )))
3017 return NULL;
3018 strcpy( name, build_dir );
3019 strcat( name, "/fonts" );
3021 return name;
3024 static char *get_data_dir_path( LPCWSTR file )
3026 char *unix_name = NULL;
3027 char *font_dir = get_font_dir();
3029 if (font_dir)
3031 INT len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
3033 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(font_dir) + len + 1 );
3034 strcpy(unix_name, font_dir);
3035 strcat(unix_name, "/");
3037 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
3038 HeapFree( GetProcessHeap(), 0, font_dir );
3040 return unix_name;
3043 static BOOL load_font_from_data_dir(LPCWSTR file)
3045 BOOL ret = FALSE;
3046 char *unix_name = get_data_dir_path( file );
3048 if (unix_name)
3050 EnterCriticalSection( &freetype_cs );
3051 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3052 LeaveCriticalSection( &freetype_cs );
3053 HeapFree(GetProcessHeap(), 0, unix_name);
3055 return ret;
3058 static char *get_winfonts_dir_path(LPCWSTR file)
3060 static const WCHAR slashW[] = {'\\','\0'};
3061 WCHAR windowsdir[MAX_PATH];
3063 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3064 strcatW(windowsdir, fontsW);
3065 strcatW(windowsdir, slashW);
3066 strcatW(windowsdir, file);
3067 return wine_get_unix_file_name( windowsdir );
3070 static void load_system_fonts(void)
3072 HKEY hkey;
3073 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
3074 const WCHAR * const *value;
3075 DWORD dlen, type;
3076 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3077 char *unixname;
3079 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
3080 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3081 strcatW(windowsdir, fontsW);
3082 for(value = SystemFontValues; *value; value++) {
3083 dlen = sizeof(data);
3084 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
3085 type == REG_SZ) {
3086 BOOL added = FALSE;
3088 sprintfW(pathW, fmtW, windowsdir, data);
3089 if((unixname = wine_get_unix_file_name(pathW))) {
3090 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3091 HeapFree(GetProcessHeap(), 0, unixname);
3093 if (!added)
3094 load_font_from_data_dir(data);
3097 RegCloseKey(hkey);
3101 /*************************************************************
3103 * This adds registry entries for any externally loaded fonts
3104 * (fonts from fontconfig or FontDirs). It also deletes entries
3105 * of no longer existing fonts.
3108 static void update_reg_entries(void)
3110 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
3111 LPWSTR valueW;
3112 DWORD len;
3113 Family *family;
3114 Face *face;
3115 WCHAR *file, *path;
3116 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
3118 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
3119 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
3120 ERR("Can't create Windows font reg key\n");
3121 goto end;
3124 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
3125 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
3126 ERR("Can't create Windows font reg key\n");
3127 goto end;
3130 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
3131 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
3132 ERR("Can't create external font reg key\n");
3133 goto end;
3136 /* enumerate the fonts and add external ones to the two keys */
3138 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
3139 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
3140 char *buffer;
3141 WCHAR *name;
3143 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
3145 name = face->FullName ? face->FullName : family->FamilyName;
3147 len = strlenW(name) + 1;
3148 if (face->scalable)
3149 len += sizeof(TrueType) / sizeof(WCHAR);
3151 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3152 strcpyW(valueW, name);
3154 if (face->scalable)
3155 strcatW(valueW, TrueType);
3157 buffer = strWtoA( CP_UNIXCP, face->file );
3158 path = wine_get_dos_file_name( buffer );
3159 HeapFree( GetProcessHeap(), 0, buffer );
3161 if (path)
3162 file = path;
3163 else if ((file = strrchrW(face->file, '/')))
3164 file++;
3165 else
3166 file = face->file;
3168 len = strlenW(file) + 1;
3169 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3170 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3171 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3173 HeapFree(GetProcessHeap(), 0, path);
3174 HeapFree(GetProcessHeap(), 0, valueW);
3177 end:
3178 if(external_key) RegCloseKey(external_key);
3179 if(win9x_key) RegCloseKey(win9x_key);
3180 if(winnt_key) RegCloseKey(winnt_key);
3183 static void delete_external_font_keys(void)
3185 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
3186 DWORD dlen, vlen, datalen, valuelen, i, type;
3187 LPWSTR valueW;
3188 LPVOID data;
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 * sizeof(WCHAR));
3215 dlen = datalen * sizeof(WCHAR);
3216 vlen = valuelen;
3217 i = 0;
3218 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
3219 &dlen) == ERROR_SUCCESS) {
3221 RegDeleteValueW(winnt_key, valueW);
3222 RegDeleteValueW(win9x_key, valueW);
3223 /* reset dlen and vlen */
3224 dlen = datalen;
3225 vlen = valuelen;
3227 HeapFree(GetProcessHeap(), 0, data);
3228 HeapFree(GetProcessHeap(), 0, valueW);
3230 /* Delete the old external fonts key */
3231 RegCloseKey(external_key);
3232 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
3234 end:
3235 if(win9x_key) RegCloseKey(win9x_key);
3236 if(winnt_key) RegCloseKey(winnt_key);
3239 /*************************************************************
3240 * WineEngAddFontResourceEx
3243 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3245 INT ret = 0;
3247 GDI_CheckNotLock();
3249 if (ft_handle) /* do it only if we have freetype up and running */
3251 char *unixname;
3253 EnterCriticalSection( &freetype_cs );
3255 if((unixname = wine_get_unix_file_name(file)))
3257 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3259 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3260 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
3261 HeapFree(GetProcessHeap(), 0, unixname);
3263 if (!ret && !strchrW(file, '\\')) {
3264 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
3265 if ((unixname = get_winfonts_dir_path( file )))
3267 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3268 HeapFree(GetProcessHeap(), 0, unixname);
3270 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
3271 if (!ret && (unixname = get_data_dir_path( file )))
3273 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3274 HeapFree(GetProcessHeap(), 0, unixname);
3278 LeaveCriticalSection( &freetype_cs );
3280 return ret;
3283 /*************************************************************
3284 * WineEngAddFontMemResourceEx
3287 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3289 GDI_CheckNotLock();
3291 if (ft_handle) /* do it only if we have freetype up and running */
3293 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
3295 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
3296 memcpy(pFontCopy, pbFont, cbFont);
3298 EnterCriticalSection( &freetype_cs );
3299 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3300 LeaveCriticalSection( &freetype_cs );
3302 if (*pcFonts == 0)
3304 TRACE("AddFontToList failed\n");
3305 HeapFree(GetProcessHeap(), 0, pFontCopy);
3306 return 0;
3308 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
3309 * For now return something unique but quite random
3311 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
3312 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
3315 *pcFonts = 0;
3316 return 0;
3319 /*************************************************************
3320 * WineEngRemoveFontResourceEx
3323 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3325 INT ret = 0;
3327 GDI_CheckNotLock();
3329 if (ft_handle) /* do it only if we have freetype up and running */
3331 char *unixname;
3333 EnterCriticalSection( &freetype_cs );
3335 if ((unixname = wine_get_unix_file_name(file)))
3337 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3339 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3340 ret = remove_font_resource( unixname, addfont_flags );
3341 HeapFree(GetProcessHeap(), 0, unixname);
3343 if (!ret && !strchrW(file, '\\'))
3345 if ((unixname = get_winfonts_dir_path( file )))
3347 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3348 HeapFree(GetProcessHeap(), 0, unixname);
3350 if (!ret && (unixname = get_data_dir_path( file )))
3352 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3353 HeapFree(GetProcessHeap(), 0, unixname);
3357 LeaveCriticalSection( &freetype_cs );
3359 return ret;
3362 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
3364 WCHAR *fullname;
3365 char *unix_name;
3366 int file_len;
3368 if (!font_file) return NULL;
3370 file_len = strlenW( font_file );
3372 if (font_path && font_path[0])
3374 int path_len = strlenW( font_path );
3375 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
3376 if (!fullname) return NULL;
3377 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
3378 fullname[path_len] = '\\';
3379 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
3381 else
3383 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
3384 if (!len) return NULL;
3385 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3386 if (!fullname) return NULL;
3387 GetFullPathNameW( font_file, len, fullname, NULL );
3390 unix_name = wine_get_unix_file_name( fullname );
3391 HeapFree( GetProcessHeap(), 0, fullname );
3392 return unix_name;
3395 #include <pshpack1.h>
3396 struct fontdir
3398 WORD num_of_resources;
3399 WORD res_id;
3400 WORD dfVersion;
3401 DWORD dfSize;
3402 CHAR dfCopyright[60];
3403 WORD dfType;
3404 WORD dfPoints;
3405 WORD dfVertRes;
3406 WORD dfHorizRes;
3407 WORD dfAscent;
3408 WORD dfInternalLeading;
3409 WORD dfExternalLeading;
3410 BYTE dfItalic;
3411 BYTE dfUnderline;
3412 BYTE dfStrikeOut;
3413 WORD dfWeight;
3414 BYTE dfCharSet;
3415 WORD dfPixWidth;
3416 WORD dfPixHeight;
3417 BYTE dfPitchAndFamily;
3418 WORD dfAvgWidth;
3419 WORD dfMaxWidth;
3420 BYTE dfFirstChar;
3421 BYTE dfLastChar;
3422 BYTE dfDefaultChar;
3423 BYTE dfBreakChar;
3424 WORD dfWidthBytes;
3425 DWORD dfDevice;
3426 DWORD dfFace;
3427 DWORD dfReserved;
3428 CHAR szFaceName[LF_FACESIZE];
3431 #include <poppack.h>
3433 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
3434 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
3436 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
3438 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3439 Face *face;
3440 WCHAR *name, *english_name;
3441 ENUMLOGFONTEXW elf;
3442 NEWTEXTMETRICEXW ntm;
3443 DWORD type;
3445 if (!ft_face) return FALSE;
3446 face = create_face( ft_face, 0, unix_name, NULL, 0, 0 );
3447 get_family_names( ft_face, &name, &english_name, FALSE );
3448 pFT_Done_Face( ft_face );
3450 GetEnumStructs( face, name, &elf, &ntm, &type );
3451 release_face( face );
3452 HeapFree( GetProcessHeap(), 0, name );
3453 HeapFree( GetProcessHeap(), 0, english_name );
3455 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3457 memset( fd, 0, sizeof(*fd) );
3459 fd->num_of_resources = 1;
3460 fd->res_id = 0;
3461 fd->dfVersion = 0x200;
3462 fd->dfSize = sizeof(*fd);
3463 strcpy( fd->dfCopyright, "Wine fontdir" );
3464 fd->dfType = 0x4003; /* 0x0080 set if private */
3465 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3466 fd->dfVertRes = 72;
3467 fd->dfHorizRes = 72;
3468 fd->dfAscent = ntm.ntmTm.tmAscent;
3469 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3470 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3471 fd->dfItalic = ntm.ntmTm.tmItalic;
3472 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3473 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3474 fd->dfWeight = ntm.ntmTm.tmWeight;
3475 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3476 fd->dfPixWidth = 0;
3477 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3478 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3479 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3480 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3481 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3482 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3483 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3484 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3485 fd->dfWidthBytes = 0;
3486 fd->dfDevice = 0;
3487 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3488 fd->dfReserved = 0;
3489 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3491 return TRUE;
3494 #define NE_FFLAGS_LIBMODULE 0x8000
3495 #define NE_OSFLAGS_WINDOWS 0x02
3497 static const char dos_string[0x40] = "This is a TrueType resource file";
3498 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3500 #include <pshpack2.h>
3502 struct ne_typeinfo
3504 WORD type_id;
3505 WORD count;
3506 DWORD res;
3509 struct ne_nameinfo
3511 WORD off;
3512 WORD len;
3513 WORD flags;
3514 WORD id;
3515 DWORD res;
3518 struct rsrc_tab
3520 WORD align;
3521 struct ne_typeinfo fontdir_type;
3522 struct ne_nameinfo fontdir_name;
3523 struct ne_typeinfo scalable_type;
3524 struct ne_nameinfo scalable_name;
3525 WORD end_of_rsrc;
3526 BYTE fontdir_res_name[8];
3529 #include <poppack.h>
3531 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3533 BOOL ret = FALSE;
3534 HANDLE file;
3535 DWORD size, written;
3536 BYTE *ptr, *start;
3537 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3538 char *font_fileA, *last_part, *ext;
3539 IMAGE_DOS_HEADER dos;
3540 IMAGE_OS2_HEADER ne =
3542 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3543 0, 0, 0, 0, 0, 0,
3544 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3545 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3547 struct rsrc_tab rsrc_tab =
3550 { 0x8007, 1, 0 },
3551 { 0, 0, 0x0c50, 0x2c, 0 },
3552 { 0x80cc, 1, 0 },
3553 { 0, 0, 0x0c50, 0x8001, 0 },
3555 { 7,'F','O','N','T','D','I','R'}
3558 memset( &dos, 0, sizeof(dos) );
3559 dos.e_magic = IMAGE_DOS_SIGNATURE;
3560 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3562 /* import name is last part\0, resident name is last part without extension
3563 non-resident name is "FONTRES:" + lfFaceName */
3565 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3566 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3567 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3569 last_part = strrchr( font_fileA, '\\' );
3570 if (last_part) last_part++;
3571 else last_part = font_fileA;
3572 import_name_len = strlen( last_part ) + 1;
3574 ext = strchr( last_part, '.' );
3575 if (ext) res_name_len = ext - last_part;
3576 else res_name_len = import_name_len - 1;
3578 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3580 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3581 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3582 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3583 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3584 ne.ne_cbenttab = 2;
3585 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3587 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3588 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3589 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3590 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3592 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3593 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3595 if (!ptr)
3597 HeapFree( GetProcessHeap(), 0, font_fileA );
3598 return FALSE;
3601 memcpy( ptr, &dos, sizeof(dos) );
3602 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3603 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3605 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3606 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3608 ptr = start + dos.e_lfanew + ne.ne_restab;
3609 *ptr++ = res_name_len;
3610 memcpy( ptr, last_part, res_name_len );
3612 ptr = start + dos.e_lfanew + ne.ne_imptab;
3613 *ptr++ = import_name_len;
3614 memcpy( ptr, last_part, import_name_len );
3616 ptr = start + ne.ne_nrestab;
3617 *ptr++ = non_res_name_len;
3618 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3619 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3621 ptr = start + (rsrc_tab.scalable_name.off << 4);
3622 memcpy( ptr, font_fileA, font_file_len );
3624 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3625 memcpy( ptr, fontdir, fontdir->dfSize );
3627 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3628 if (file != INVALID_HANDLE_VALUE)
3630 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3631 ret = TRUE;
3632 CloseHandle( file );
3635 HeapFree( GetProcessHeap(), 0, start );
3636 HeapFree( GetProcessHeap(), 0, font_fileA );
3638 return ret;
3641 /*************************************************************
3642 * WineEngCreateScalableFontResource
3645 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3646 LPCWSTR font_file, LPCWSTR font_path )
3648 char *unix_name = get_ttf_file_name( font_file, font_path );
3649 struct fontdir fontdir;
3650 BOOL ret = FALSE;
3652 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3653 SetLastError( ERROR_INVALID_PARAMETER );
3654 else
3656 if (hidden) fontdir.dfType |= 0x80;
3657 ret = create_fot( resource, font_file, &fontdir );
3660 HeapFree( GetProcessHeap(), 0, unix_name );
3661 return ret;
3664 static const struct nls_update_font_list
3666 UINT ansi_cp, oem_cp;
3667 const char *oem, *fixed, *system;
3668 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3669 /* these are for font substitutes */
3670 const char *shelldlg, *tmsrmn;
3671 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3672 *helv_0, *tmsrmn_0;
3673 const struct subst
3675 const char *from, *to;
3676 } arial_0, courier_new_0, times_new_roman_0;
3677 } nls_update_font_list[] =
3679 /* Latin 1 (United States) */
3680 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3681 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3682 "Tahoma","Times New Roman",
3683 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3684 { 0 }, { 0 }, { 0 }
3686 /* Latin 1 (Multilingual) */
3687 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3688 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3689 "Tahoma","Times New Roman", /* FIXME unverified */
3690 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3691 { 0 }, { 0 }, { 0 }
3693 /* Eastern Europe */
3694 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3695 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3696 "Tahoma","Times New Roman", /* FIXME unverified */
3697 "Fixedsys,238", "System,238",
3698 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3699 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3700 { "Arial CE,0", "Arial,238" },
3701 { "Courier New CE,0", "Courier New,238" },
3702 { "Times New Roman CE,0", "Times New Roman,238" }
3704 /* Cyrillic */
3705 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3706 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3707 "Tahoma","Times New Roman", /* FIXME unverified */
3708 "Fixedsys,204", "System,204",
3709 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3710 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3711 { "Arial Cyr,0", "Arial,204" },
3712 { "Courier New Cyr,0", "Courier New,204" },
3713 { "Times New Roman Cyr,0", "Times New Roman,204" }
3715 /* Greek */
3716 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3717 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3718 "Tahoma","Times New Roman", /* FIXME unverified */
3719 "Fixedsys,161", "System,161",
3720 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3721 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3722 { "Arial Greek,0", "Arial,161" },
3723 { "Courier New Greek,0", "Courier New,161" },
3724 { "Times New Roman Greek,0", "Times New Roman,161" }
3726 /* Turkish */
3727 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3728 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3729 "Tahoma","Times New Roman", /* FIXME unverified */
3730 "Fixedsys,162", "System,162",
3731 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3732 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3733 { "Arial Tur,0", "Arial,162" },
3734 { "Courier New Tur,0", "Courier New,162" },
3735 { "Times New Roman Tur,0", "Times New Roman,162" }
3737 /* Hebrew */
3738 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3739 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3740 "Tahoma","Times New Roman", /* FIXME unverified */
3741 "Fixedsys,177", "System,177",
3742 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3743 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3744 { 0 }, { 0 }, { 0 }
3746 /* Arabic */
3747 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3748 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3749 "Microsoft Sans Serif","Times New Roman",
3750 "Fixedsys,178", "System,178",
3751 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3752 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3753 { 0 }, { 0 }, { 0 }
3755 /* Baltic */
3756 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3757 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3758 "Tahoma","Times New Roman", /* FIXME unverified */
3759 "Fixedsys,186", "System,186",
3760 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3761 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3762 { "Arial Baltic,0", "Arial,186" },
3763 { "Courier New Baltic,0", "Courier New,186" },
3764 { "Times New Roman Baltic,0", "Times New Roman,186" }
3766 /* Vietnamese */
3767 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3768 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3769 "Tahoma","Times New Roman", /* FIXME unverified */
3770 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3771 { 0 }, { 0 }, { 0 }
3773 /* Thai */
3774 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3775 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3776 "Tahoma","Times New Roman", /* FIXME unverified */
3777 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3778 { 0 }, { 0 }, { 0 }
3780 /* Japanese */
3781 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3782 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3783 "MS UI Gothic","MS Serif",
3784 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3785 { 0 }, { 0 }, { 0 }
3787 /* Chinese Simplified */
3788 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3789 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3790 "SimSun", "NSimSun",
3791 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3792 { 0 }, { 0 }, { 0 }
3794 /* Korean */
3795 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3796 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3797 "Gulim", "Batang",
3798 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3799 { 0 }, { 0 }, { 0 }
3801 /* Chinese Traditional */
3802 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3803 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3804 "PMingLiU", "MingLiU",
3805 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3806 { 0 }, { 0 }, { 0 }
3810 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3812 return ( ansi_cp == 932 /* CP932 for Japanese */
3813 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3814 || ansi_cp == 949 /* CP949 for Korean */
3815 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3818 static inline HKEY create_fonts_NT_registry_key(void)
3820 HKEY hkey = 0;
3822 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3823 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3824 return hkey;
3827 static inline HKEY create_fonts_9x_registry_key(void)
3829 HKEY hkey = 0;
3831 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3832 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3833 return hkey;
3836 static inline HKEY create_config_fonts_registry_key(void)
3838 HKEY hkey = 0;
3840 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3841 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3842 return hkey;
3845 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3847 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3849 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3850 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3851 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3852 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3855 static void set_value_key(HKEY hkey, const char *name, const char *value)
3857 if (value)
3858 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3859 else if (name)
3860 RegDeleteValueA(hkey, name);
3863 static void update_font_association_info(UINT current_ansi_codepage)
3865 static const char *font_assoc_reg_key = "System\\CurrentControlSet\\Control\\FontAssoc";
3866 static const char *assoc_charset_subkey = "Associated Charset";
3868 if (is_dbcs_ansi_cp(current_ansi_codepage))
3870 HKEY hkey;
3871 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, font_assoc_reg_key, &hkey) == ERROR_SUCCESS)
3873 HKEY hsubkey;
3874 if (RegCreateKeyA(hkey, assoc_charset_subkey, &hsubkey) == ERROR_SUCCESS)
3876 switch (current_ansi_codepage)
3878 case 932:
3879 set_value_key(hsubkey, "ANSI(00)", "NO");
3880 set_value_key(hsubkey, "OEM(FF)", "NO");
3881 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3882 break;
3883 case 936:
3884 case 949:
3885 case 950:
3886 set_value_key(hsubkey, "ANSI(00)", "YES");
3887 set_value_key(hsubkey, "OEM(FF)", "YES");
3888 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3889 break;
3891 RegCloseKey(hsubkey);
3894 /* TODO: Associated DefaultFonts */
3896 RegCloseKey(hkey);
3899 else
3900 RegDeleteTreeA(HKEY_LOCAL_MACHINE, font_assoc_reg_key);
3903 static void set_multi_value_key(HKEY hkey, const WCHAR *name, const WCHAR *value, DWORD len)
3905 if (value)
3906 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (const BYTE *)value, len);
3907 else if (name)
3908 RegDeleteValueW(hkey, name);
3911 static void update_font_system_link_info(UINT current_ansi_codepage)
3913 static const WCHAR system_link_simplified_chinese[] =
3914 {'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3915 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3916 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3917 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3918 '\0'};
3919 static const WCHAR system_link_traditional_chinese[] =
3920 {'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3921 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3922 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3923 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3924 '\0'};
3925 static const WCHAR system_link_japanese[] =
3926 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3927 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3928 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3929 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3930 '\0'};
3931 static const WCHAR system_link_korean[] =
3932 {'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3933 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3934 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3935 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3936 '\0'};
3937 static const WCHAR system_link_non_cjk[] =
3938 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3939 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3940 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3941 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3942 '\0'};
3943 HKEY hkey;
3945 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
3947 const WCHAR *link;
3948 DWORD len;
3950 switch (current_ansi_codepage)
3952 case 932:
3953 link = system_link_japanese;
3954 len = sizeof(system_link_japanese);
3955 break;
3956 case 936:
3957 link = system_link_simplified_chinese;
3958 len = sizeof(system_link_simplified_chinese);
3959 break;
3960 case 949:
3961 link = system_link_korean;
3962 len = sizeof(system_link_korean);
3963 break;
3964 case 950:
3965 link = system_link_traditional_chinese;
3966 len = sizeof(system_link_traditional_chinese);
3967 break;
3968 default:
3969 link = system_link_non_cjk;
3970 len = sizeof(system_link_non_cjk);
3972 set_multi_value_key(hkey, Lucida_Sans_Unicode, link, len);
3973 set_multi_value_key(hkey, Microsoft_Sans_Serif, link, len);
3974 set_multi_value_key(hkey, Tahoma, link, len);
3975 RegCloseKey(hkey);
3979 static void update_font_info(void)
3981 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3982 char buf[40], cpbuf[40];
3983 DWORD len, type;
3984 HKEY hkey = 0;
3985 UINT i, ansi_cp = 0, oem_cp = 0;
3986 DWORD screen_dpi = 96, font_dpi = 0;
3987 BOOL done = FALSE;
3989 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3990 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3991 &hkey) == ERROR_SUCCESS)
3993 reg_load_dword(hkey, logpixels, &screen_dpi);
3994 RegCloseKey(hkey);
3997 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3998 return;
4000 reg_load_dword(hkey, logpixels, &font_dpi);
4002 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
4003 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
4004 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
4005 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
4006 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
4008 /* Setup Default_Fallback usage for DBCS ANSI codepages */
4009 if (is_dbcs_ansi_cp(ansi_cp))
4010 use_default_fallback = TRUE;
4012 buf[0] = 0;
4013 len = sizeof(buf);
4014 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
4016 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
4018 RegCloseKey(hkey);
4019 return;
4021 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
4022 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
4024 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
4025 ansi_cp, oem_cp, screen_dpi);
4027 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
4028 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
4029 RegCloseKey(hkey);
4031 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
4033 HKEY hkey;
4035 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
4036 nls_update_font_list[i].oem_cp == oem_cp)
4038 hkey = create_config_fonts_registry_key();
4039 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
4040 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
4041 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
4042 RegCloseKey(hkey);
4044 hkey = create_fonts_NT_registry_key();
4045 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
4046 RegCloseKey(hkey);
4048 hkey = create_fonts_9x_registry_key();
4049 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
4050 RegCloseKey(hkey);
4052 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
4054 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
4055 strlen(nls_update_font_list[i].shelldlg)+1);
4056 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
4057 strlen(nls_update_font_list[i].tmsrmn)+1);
4059 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
4060 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
4061 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
4062 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
4063 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
4064 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
4065 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
4066 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
4068 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
4069 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
4070 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
4072 RegCloseKey(hkey);
4074 done = TRUE;
4076 else
4078 /* Delete the FontSubstitutes from other locales */
4079 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
4081 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
4082 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
4083 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
4084 RegCloseKey(hkey);
4088 if (!done)
4089 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
4091 /* update locale dependent font association info and font system link info in registry.
4092 update only when codepages changed, not logpixels. */
4093 if (strcmp(buf, cpbuf) != 0)
4095 update_font_association_info(ansi_cp);
4096 update_font_system_link_info(ansi_cp);
4100 static BOOL init_freetype(void)
4102 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
4103 if(!ft_handle) {
4104 WINE_MESSAGE(
4105 "Wine cannot find the FreeType font library. To enable Wine to\n"
4106 "use TrueType fonts please install a version of FreeType greater than\n"
4107 "or equal to 2.0.5.\n"
4108 "http://www.freetype.org\n");
4109 return FALSE;
4112 #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;}
4114 LOAD_FUNCPTR(FT_Done_Face)
4115 LOAD_FUNCPTR(FT_Get_Char_Index)
4116 LOAD_FUNCPTR(FT_Get_First_Char)
4117 LOAD_FUNCPTR(FT_Get_Next_Char)
4118 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
4119 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
4120 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
4121 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
4122 LOAD_FUNCPTR(FT_Init_FreeType)
4123 LOAD_FUNCPTR(FT_Library_Version)
4124 LOAD_FUNCPTR(FT_Load_Glyph)
4125 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
4126 LOAD_FUNCPTR(FT_Matrix_Multiply)
4127 #ifndef FT_MULFIX_INLINED
4128 LOAD_FUNCPTR(FT_MulFix)
4129 #endif
4130 LOAD_FUNCPTR(FT_New_Face)
4131 LOAD_FUNCPTR(FT_New_Memory_Face)
4132 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
4133 LOAD_FUNCPTR(FT_Outline_Get_CBox)
4134 LOAD_FUNCPTR(FT_Outline_Transform)
4135 LOAD_FUNCPTR(FT_Outline_Translate)
4136 LOAD_FUNCPTR(FT_Render_Glyph)
4137 LOAD_FUNCPTR(FT_Select_Charmap)
4138 LOAD_FUNCPTR(FT_Set_Charmap)
4139 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
4140 LOAD_FUNCPTR(FT_Vector_Length)
4141 LOAD_FUNCPTR(FT_Vector_Transform)
4142 LOAD_FUNCPTR(FT_Vector_Unit)
4143 #undef LOAD_FUNCPTR
4144 /* Don't warn if these ones are missing */
4145 pFT_Outline_Embolden = wine_dlsym(ft_handle, "FT_Outline_Embolden", NULL, 0);
4146 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
4147 #ifdef FT_LCD_FILTER_H
4148 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
4149 #endif
4151 if(pFT_Init_FreeType(&library) != 0) {
4152 ERR("Can't init FreeType library\n");
4153 wine_dlclose(ft_handle, NULL, 0);
4154 ft_handle = NULL;
4155 return FALSE;
4157 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
4159 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
4160 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
4161 ((FT_Version.minor << 8) & 0x00ff00) |
4162 ((FT_Version.patch ) & 0x0000ff);
4164 font_driver = &freetype_funcs;
4165 return TRUE;
4167 sym_not_found:
4168 WINE_MESSAGE(
4169 "Wine cannot find certain functions that it needs inside the FreeType\n"
4170 "font library. To enable Wine to use TrueType fonts please upgrade\n"
4171 "FreeType to at least version 2.1.4.\n"
4172 "http://www.freetype.org\n");
4173 wine_dlclose(ft_handle, NULL, 0);
4174 ft_handle = NULL;
4175 return FALSE;
4178 static void init_font_list(void)
4180 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
4181 static const WCHAR pathW[] = {'P','a','t','h',0};
4182 HKEY hkey;
4183 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
4184 WCHAR windowsdir[MAX_PATH];
4185 char *unixname;
4187 delete_external_font_keys();
4189 /* load the system bitmap fonts */
4190 load_system_fonts();
4192 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
4193 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
4194 strcatW(windowsdir, fontsW);
4195 if((unixname = wine_get_unix_file_name(windowsdir)))
4197 ReadFontDir(unixname, FALSE);
4198 HeapFree(GetProcessHeap(), 0, unixname);
4201 /* load the wine fonts */
4202 if ((unixname = get_font_dir()))
4204 ReadFontDir(unixname, TRUE);
4205 HeapFree(GetProcessHeap(), 0, unixname);
4208 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
4209 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
4210 full path as the entry. Also look for any .fon fonts, since ReadFontDir
4211 will skip these. */
4212 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
4213 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
4214 &hkey) == ERROR_SUCCESS)
4216 LPWSTR data, valueW;
4217 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
4218 &valuelen, &datalen, NULL, NULL);
4220 valuelen++; /* returned value doesn't include room for '\0' */
4221 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
4222 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
4223 if (valueW && data)
4225 dlen = datalen * sizeof(WCHAR);
4226 vlen = valuelen;
4227 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
4228 &dlen) == ERROR_SUCCESS)
4230 if(data[0] && (data[1] == ':'))
4232 if((unixname = wine_get_unix_file_name(data)))
4234 AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
4235 HeapFree(GetProcessHeap(), 0, unixname);
4238 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
4240 WCHAR pathW[MAX_PATH];
4241 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
4242 BOOL added = FALSE;
4244 sprintfW(pathW, fmtW, windowsdir, data);
4245 if((unixname = wine_get_unix_file_name(pathW)))
4247 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
4248 HeapFree(GetProcessHeap(), 0, unixname);
4250 if (!added)
4251 load_font_from_data_dir(data);
4253 /* reset dlen and vlen */
4254 dlen = datalen;
4255 vlen = valuelen;
4258 HeapFree(GetProcessHeap(), 0, data);
4259 HeapFree(GetProcessHeap(), 0, valueW);
4260 RegCloseKey(hkey);
4263 #ifdef SONAME_LIBFONTCONFIG
4264 load_fontconfig_fonts();
4265 #elif defined(HAVE_CARBON_CARBON_H)
4266 load_mac_fonts();
4267 #elif defined(__ANDROID__)
4268 ReadFontDir("/system/fonts", TRUE);
4269 #endif
4271 /* then look in any directories that we've specified in the config file */
4272 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
4273 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
4275 DWORD len;
4276 LPWSTR valueW;
4277 LPSTR valueA, ptr;
4279 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
4281 len += sizeof(WCHAR);
4282 valueW = HeapAlloc( GetProcessHeap(), 0, len );
4283 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
4285 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
4286 valueA = HeapAlloc( GetProcessHeap(), 0, len );
4287 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
4288 TRACE( "got font path %s\n", debugstr_a(valueA) );
4289 ptr = valueA;
4290 while (ptr)
4292 const char* home;
4293 LPSTR next = strchr( ptr, ':' );
4294 if (next) *next++ = 0;
4295 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
4296 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
4298 strcpy( unixname, home );
4299 strcat( unixname, ptr + 1 );
4300 ReadFontDir( unixname, TRUE );
4301 HeapFree( GetProcessHeap(), 0, unixname );
4303 else
4304 ReadFontDir( ptr, TRUE );
4305 ptr = next;
4307 HeapFree( GetProcessHeap(), 0, valueA );
4309 HeapFree( GetProcessHeap(), 0, valueW );
4311 RegCloseKey(hkey);
4315 static BOOL move_to_front(const WCHAR *name)
4317 Family *family, *cursor2;
4318 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
4320 if(!strcmpiW(family->FamilyName, name))
4322 list_remove(&family->entry);
4323 list_add_head(&font_list, &family->entry);
4324 return TRUE;
4327 return FALSE;
4330 static BOOL set_default(const WCHAR **name_list)
4332 while (*name_list)
4334 if (move_to_front(*name_list)) return TRUE;
4335 name_list++;
4338 return FALSE;
4341 static void reorder_font_list(void)
4343 set_default( default_serif_list );
4344 set_default( default_fixed_list );
4345 set_default( default_sans_list );
4348 /*************************************************************
4349 * WineEngInit
4351 * Initialize FreeType library and create a list of available faces
4353 BOOL WineEngInit(void)
4355 HKEY hkey;
4356 DWORD disposition;
4357 HANDLE font_mutex;
4359 /* update locale dependent font info in registry */
4360 update_font_info();
4362 if(!init_freetype()) return FALSE;
4364 #ifdef SONAME_LIBFONTCONFIG
4365 init_fontconfig();
4366 #endif
4368 if (!RegOpenKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, KEY_READ, &hkey))
4370 static const WCHAR antialias_fake_bold_or_italic[] = { 'A','n','t','i','a','l','i','a','s','F','a','k','e',
4371 'B','o','l','d','O','r','I','t','a','l','i','c',0 };
4372 static const WCHAR true_options[] = { 'y','Y','t','T','1',0 };
4373 DWORD type, size;
4374 WCHAR buffer[20];
4376 size = sizeof(buffer);
4377 if (!RegQueryValueExW(hkey, antialias_fake_bold_or_italic, NULL, &type, (BYTE*)buffer, &size) &&
4378 type == REG_SZ && size >= 1)
4380 antialias_fakes = (strchrW(true_options, buffer[0]) != NULL);
4382 RegCloseKey(hkey);
4385 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
4387 ERR("Failed to create font mutex\n");
4388 return FALSE;
4390 WaitForSingleObject(font_mutex, INFINITE);
4392 create_font_cache_key(&hkey_font_cache, &disposition);
4394 if(disposition == REG_CREATED_NEW_KEY)
4395 init_font_list();
4396 else
4397 load_font_list_from_cache(hkey_font_cache);
4399 reorder_font_list();
4401 DumpFontList();
4402 LoadSubstList();
4403 DumpSubstList();
4404 LoadReplaceList();
4406 if(disposition == REG_CREATED_NEW_KEY)
4407 update_reg_entries();
4409 init_system_links();
4411 ReleaseMutex(font_mutex);
4412 return TRUE;
4415 /* Some fonts have large usWinDescent values, as a result of storing signed short
4416 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
4417 some font generation tools. */
4418 static inline USHORT get_fixed_windescent(USHORT windescent)
4420 return abs((SHORT)windescent);
4423 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
4425 TT_OS2 *pOS2;
4426 TT_HoriHeader *pHori;
4428 LONG ppem;
4429 const LONG MAX_PPEM = (1 << 16) - 1;
4431 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4432 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4434 if(height == 0) height = 16;
4436 /* Calc. height of EM square:
4438 * For +ve lfHeight we have
4439 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
4440 * Re-arranging gives:
4441 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4443 * For -ve lfHeight we have
4444 * |lfHeight| = ppem
4445 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4446 * with il = winAscent + winDescent - units_per_em]
4450 if(height > 0) {
4451 USHORT windescent = get_fixed_windescent(pOS2->usWinDescent);
4452 if(pOS2->usWinAscent + windescent == 0)
4453 ppem = MulDiv(ft_face->units_per_EM, height,
4454 pHori->Ascender - pHori->Descender);
4455 else
4456 ppem = MulDiv(ft_face->units_per_EM, height,
4457 pOS2->usWinAscent + windescent);
4458 if(ppem > MAX_PPEM) {
4459 WARN("Ignoring too large height %d, ppem %d\n", height, ppem);
4460 ppem = 1;
4463 else if(height >= -MAX_PPEM)
4464 ppem = -height;
4465 else {
4466 WARN("Ignoring too large height %d\n", height);
4467 ppem = 1;
4470 return ppem;
4473 static struct font_mapping *map_font_file( const char *name )
4475 struct font_mapping *mapping;
4476 struct stat st;
4477 int fd;
4479 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
4480 if (fstat( fd, &st ) == -1) goto error;
4482 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
4484 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
4486 mapping->refcount++;
4487 close( fd );
4488 return mapping;
4491 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
4492 goto error;
4494 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
4495 close( fd );
4497 if (mapping->data == MAP_FAILED)
4499 HeapFree( GetProcessHeap(), 0, mapping );
4500 return NULL;
4502 mapping->refcount = 1;
4503 mapping->dev = st.st_dev;
4504 mapping->ino = st.st_ino;
4505 mapping->size = st.st_size;
4506 list_add_tail( &mappings_list, &mapping->entry );
4507 return mapping;
4509 error:
4510 close( fd );
4511 return NULL;
4514 static void unmap_font_file( struct font_mapping *mapping )
4516 if (!--mapping->refcount)
4518 list_remove( &mapping->entry );
4519 munmap( mapping->data, mapping->size );
4520 HeapFree( GetProcessHeap(), 0, mapping );
4524 static LONG load_VDMX(GdiFont*, LONG);
4526 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
4528 FT_Error err;
4529 FT_Face ft_face;
4530 void *data_ptr;
4531 DWORD data_size;
4533 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
4535 if (face->file)
4537 char *filename = strWtoA( CP_UNIXCP, face->file );
4538 font->mapping = map_font_file( filename );
4539 HeapFree( GetProcessHeap(), 0, filename );
4540 if (!font->mapping)
4542 WARN("failed to map %s\n", debugstr_w(face->file));
4543 return 0;
4545 data_ptr = font->mapping->data;
4546 data_size = font->mapping->size;
4548 else
4550 data_ptr = face->font_data_ptr;
4551 data_size = face->font_data_size;
4554 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
4555 if(err) {
4556 ERR("FT_New_Face rets %d\n", err);
4557 return 0;
4560 /* set it here, as load_VDMX needs it */
4561 font->ft_face = ft_face;
4563 if(FT_IS_SCALABLE(ft_face)) {
4564 FT_ULong len;
4565 DWORD header;
4567 /* load the VDMX table if we have one */
4568 font->ppem = load_VDMX(font, height);
4569 if(font->ppem == 0)
4570 font->ppem = calc_ppem_for_height(ft_face, height);
4571 TRACE("height %d => ppem %d\n", height, font->ppem);
4573 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
4574 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
4576 /* see if it's a TTC */
4577 len = sizeof(header);
4578 if (!pFT_Load_Sfnt_Table(ft_face, 0, 0, (void*)&header, &len)) {
4579 if (header == MS_TTCF_TAG)
4581 len = sizeof(font->ttc_item_offset);
4582 if (pFT_Load_Sfnt_Table(ft_face, 0, (3 + face->face_index) * sizeof(DWORD),
4583 (void*)&font->ttc_item_offset, &len))
4584 font->ttc_item_offset = 0;
4585 else
4586 font->ttc_item_offset = GET_BE_DWORD(font->ttc_item_offset);
4589 } else {
4590 font->ppem = height;
4591 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
4592 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
4594 return ft_face;
4598 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
4600 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4601 a single face with the requested charset. The idea is to check if
4602 the selected font supports the current ANSI codepage, if it does
4603 return the corresponding charset, else return the first charset */
4605 CHARSETINFO csi;
4606 int acp = GetACP(), i;
4607 DWORD fs0;
4609 *cp = acp;
4610 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
4612 const SYSTEM_LINKS *font_link;
4614 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4615 return csi.ciCharset;
4617 font_link = find_font_link(family_name);
4618 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4619 return csi.ciCharset;
4622 for(i = 0; i < 32; i++) {
4623 fs0 = 1L << i;
4624 if(face->fs.fsCsb[0] & fs0) {
4625 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4626 *cp = csi.ciACP;
4627 return csi.ciCharset;
4629 else
4630 FIXME("TCI failing on %x\n", fs0);
4634 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4635 face->fs.fsCsb[0], debugstr_w(face->file));
4636 *cp = acp;
4637 return DEFAULT_CHARSET;
4640 static GdiFont *alloc_font(void)
4642 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4643 ret->refcount = 1;
4644 ret->gmsize = 1;
4645 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4646 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4647 ret->potm = NULL;
4648 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4649 ret->total_kern_pairs = (DWORD)-1;
4650 ret->kern_pairs = NULL;
4651 ret->instance_id = alloc_font_handle(ret);
4652 list_init(&ret->child_fonts);
4653 return ret;
4656 static void free_font(GdiFont *font)
4658 CHILD_FONT *child, *child_next;
4659 DWORD i;
4661 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
4663 list_remove(&child->entry);
4664 if(child->font)
4665 free_font(child->font);
4666 release_face( child->face );
4667 HeapFree(GetProcessHeap(), 0, child);
4670 HeapFree(GetProcessHeap(), 0, font->fileinfo);
4671 free_font_handle(font->instance_id);
4672 if (font->ft_face) pFT_Done_Face(font->ft_face);
4673 if (font->mapping) unmap_font_file( font->mapping );
4674 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4675 HeapFree(GetProcessHeap(), 0, font->potm);
4676 HeapFree(GetProcessHeap(), 0, font->name);
4677 for (i = 0; i < font->gmsize; i++)
4678 HeapFree(GetProcessHeap(),0,font->gm[i]);
4679 HeapFree(GetProcessHeap(), 0, font->gm);
4680 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4681 HeapFree(GetProcessHeap(), 0, font);
4685 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4687 FT_Face ft_face = font->ft_face;
4688 FT_ULong len;
4689 FT_Error err;
4691 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4693 if(!buf)
4694 len = 0;
4695 else
4696 len = cbData;
4698 /* if font is a member of TTC, 'ttcf' tag allows reading from beginning of TTC file,
4699 0 tag means to read from start of collection member data. */
4700 if (font->ttc_item_offset)
4702 if (table == MS_TTCF_TAG)
4703 table = 0;
4704 else if (table == 0)
4705 offset += font->ttc_item_offset;
4708 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4710 /* make sure value of len is the value freetype says it needs */
4711 if (buf && len)
4713 FT_ULong needed = 0;
4714 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4715 if( !err && needed < len) len = needed;
4717 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4718 if (err)
4720 table = RtlUlongByteSwap( table );
4721 TRACE("Can't find table %s\n", debugstr_an((char*)&table, 4));
4722 return GDI_ERROR;
4724 return len;
4727 /*************************************************************
4728 * load_VDMX
4730 * load the vdmx entry for the specified height
4735 typedef struct {
4736 WORD version;
4737 WORD numRecs;
4738 WORD numRatios;
4739 } VDMX_Header;
4741 typedef struct {
4742 BYTE bCharSet;
4743 BYTE xRatio;
4744 BYTE yStartRatio;
4745 BYTE yEndRatio;
4746 } Ratios;
4748 typedef struct {
4749 WORD recs;
4750 BYTE startsz;
4751 BYTE endsz;
4752 } VDMX_group;
4754 typedef struct {
4755 WORD yPelHeight;
4756 WORD yMax;
4757 WORD yMin;
4758 } VDMX_vTable;
4760 static LONG load_VDMX(GdiFont *font, LONG height)
4762 VDMX_Header hdr;
4763 VDMX_group group;
4764 BYTE devXRatio, devYRatio;
4765 USHORT numRecs, numRatios;
4766 DWORD result, offset = -1;
4767 LONG ppem = 0;
4768 int i;
4770 result = get_font_data(font, MS_VDMX_TAG, 0, &hdr, sizeof(hdr));
4772 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4773 return ppem;
4775 /* FIXME: need the real device aspect ratio */
4776 devXRatio = 1;
4777 devYRatio = 1;
4779 numRecs = GET_BE_WORD(hdr.numRecs);
4780 numRatios = GET_BE_WORD(hdr.numRatios);
4782 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr.version), numRecs, numRatios);
4783 for(i = 0; i < numRatios; i++) {
4784 Ratios ratio;
4786 offset = sizeof(hdr) + (i * sizeof(Ratios));
4787 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4788 offset = -1;
4790 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4792 if (!ratio.bCharSet) continue;
4794 if((ratio.xRatio == 0 &&
4795 ratio.yStartRatio == 0 &&
4796 ratio.yEndRatio == 0) ||
4797 (devXRatio == ratio.xRatio &&
4798 devYRatio >= ratio.yStartRatio &&
4799 devYRatio <= ratio.yEndRatio))
4801 WORD group_offset;
4803 offset = sizeof(hdr) + numRatios * sizeof(ratio) + i * sizeof(group_offset);
4804 get_font_data(font, MS_VDMX_TAG, offset, &group_offset, sizeof(group_offset));
4805 offset = GET_BE_WORD(group_offset);
4806 break;
4810 if(offset == -1) return 0;
4812 if(get_font_data(font, MS_VDMX_TAG, offset, &group, sizeof(group)) != GDI_ERROR) {
4813 USHORT recs;
4814 BYTE startsz, endsz;
4815 WORD *vTable;
4817 recs = GET_BE_WORD(group.recs);
4818 startsz = group.startsz;
4819 endsz = group.endsz;
4821 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4823 vTable = HeapAlloc(GetProcessHeap(), 0, recs * sizeof(VDMX_vTable));
4824 result = get_font_data(font, MS_VDMX_TAG, offset + sizeof(group), vTable, recs * sizeof(VDMX_vTable));
4825 if(result == GDI_ERROR) {
4826 FIXME("Failed to retrieve vTable\n");
4827 goto end;
4830 if(height > 0) {
4831 for(i = 0; i < recs; i++) {
4832 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4833 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4834 ppem = GET_BE_WORD(vTable[i * 3]);
4836 if(yMax + -yMin == height) {
4837 font->yMax = yMax;
4838 font->yMin = yMin;
4839 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4840 break;
4842 if(yMax + -yMin > height) {
4843 if(--i < 0) {
4844 ppem = 0;
4845 goto end; /* failed */
4847 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4848 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4849 ppem = GET_BE_WORD(vTable[i * 3]);
4850 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4851 break;
4854 if(!font->yMax) {
4855 ppem = 0;
4856 TRACE("ppem not found for height %d\n", height);
4858 } else {
4859 ppem = -height;
4860 if(ppem < startsz || ppem > endsz)
4862 ppem = 0;
4863 goto end;
4866 for(i = 0; i < recs; i++) {
4867 USHORT yPelHeight;
4868 yPelHeight = GET_BE_WORD(vTable[i * 3]);
4870 if(yPelHeight > ppem)
4872 ppem = 0;
4873 break; /* failed */
4876 if(yPelHeight == ppem) {
4877 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4878 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4879 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
4880 break;
4884 end:
4885 HeapFree(GetProcessHeap(), 0, vTable);
4888 return ppem;
4891 static void dump_gdi_font_list(void)
4893 GdiFont *font;
4895 TRACE("---------- Font Cache ----------\n");
4896 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct tagGdiFont, entry )
4897 TRACE("font=%p ref=%u %s %d\n", font, font->refcount,
4898 debugstr_w(font->font_desc.lf.lfFaceName), font->font_desc.lf.lfHeight);
4901 static void grab_font( GdiFont *font )
4903 if (!font->refcount++)
4905 list_remove( &font->unused_entry );
4906 unused_font_count--;
4910 static void release_font( GdiFont *font )
4912 if (!font) return;
4913 if (!--font->refcount)
4915 TRACE( "font %p\n", font );
4917 /* add it to the unused list */
4918 list_add_head( &unused_gdi_font_list, &font->unused_entry );
4919 if (unused_font_count > UNUSED_CACHE_SIZE)
4921 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct tagGdiFont, unused_entry );
4922 TRACE( "freeing %p\n", font );
4923 list_remove( &font->entry );
4924 list_remove( &font->unused_entry );
4925 free_font( font );
4927 else unused_font_count++;
4929 if (TRACE_ON(font)) dump_gdi_font_list();
4933 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4935 if(font->font_desc.hash != fd->hash) return TRUE;
4936 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4937 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4938 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4939 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4942 static void calc_hash(FONT_DESC *pfd)
4944 DWORD hash = 0, *ptr, two_chars;
4945 WORD *pwc;
4946 unsigned int i;
4948 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4949 hash ^= *ptr;
4950 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4951 hash ^= *ptr;
4952 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4953 two_chars = *ptr;
4954 pwc = (WCHAR *)&two_chars;
4955 if(!*pwc) break;
4956 *pwc = toupperW(*pwc);
4957 pwc++;
4958 *pwc = toupperW(*pwc);
4959 hash ^= two_chars;
4960 if(!*pwc) break;
4962 hash ^= !pfd->can_use_bitmap;
4963 pfd->hash = hash;
4966 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4968 GdiFont *ret;
4969 FONT_DESC fd;
4971 fd.lf = *plf;
4972 fd.matrix = *pmat;
4973 fd.can_use_bitmap = can_use_bitmap;
4974 calc_hash(&fd);
4976 /* try the in-use list */
4977 LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
4979 if(fontcmp(ret, &fd)) continue;
4980 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4981 list_remove( &ret->entry );
4982 list_add_head( &gdi_font_list, &ret->entry );
4983 grab_font( ret );
4984 return ret;
4986 return NULL;
4989 static void add_to_cache(GdiFont *font)
4991 static DWORD cache_num = 1;
4993 font->cache_num = cache_num++;
4994 list_add_head(&gdi_font_list, &font->entry);
4995 TRACE( "font %p\n", font );
4998 /*************************************************************
4999 * create_child_font_list
5001 static BOOL create_child_font_list(GdiFont *font)
5003 BOOL ret = FALSE;
5004 SYSTEM_LINKS *font_link;
5005 CHILD_FONT *font_link_entry, *new_child;
5006 FontSubst *psub;
5007 WCHAR* font_name;
5009 psub = get_font_subst(&font_subst_list, font->name, -1);
5010 font_name = psub ? psub->to.name : font->name;
5011 font_link = find_font_link(font_name);
5012 if (font_link != NULL)
5014 TRACE("found entry in system list\n");
5015 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5017 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
5018 new_child->face = font_link_entry->face;
5019 new_child->font = NULL;
5020 new_child->face->refcount++;
5021 list_add_tail(&font->child_fonts, &new_child->entry);
5022 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
5024 ret = TRUE;
5027 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
5028 * Sans Serif. This is how asian windows get default fallbacks for fonts
5030 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
5031 font->charset != OEM_CHARSET &&
5032 strcmpiW(font_name,szDefaultFallbackLink) != 0)
5034 font_link = find_font_link(szDefaultFallbackLink);
5035 if (font_link != NULL)
5037 TRACE("found entry in default fallback list\n");
5038 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5040 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
5041 new_child->face = font_link_entry->face;
5042 new_child->font = NULL;
5043 new_child->face->refcount++;
5044 list_add_tail(&font->child_fonts, &new_child->entry);
5045 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
5047 ret = TRUE;
5051 return ret;
5054 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
5056 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
5058 if (pFT_Set_Charmap)
5060 FT_Int i;
5061 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
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);
5103 return ft_err == FT_Err_Ok;
5106 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
5110 /*************************************************************
5111 * freetype_CreateDC
5113 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
5114 LPCWSTR output, const DEVMODEW *devmode )
5116 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
5118 if (!physdev) return FALSE;
5119 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
5120 return TRUE;
5124 /*************************************************************
5125 * freetype_DeleteDC
5127 static BOOL freetype_DeleteDC( PHYSDEV dev )
5129 struct freetype_physdev *physdev = get_freetype_dev( dev );
5130 release_font( physdev->font );
5131 HeapFree( GetProcessHeap(), 0, physdev );
5132 return TRUE;
5135 static FT_Encoding pick_charmap( FT_Face face, int charset )
5137 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
5138 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
5139 const FT_Encoding *encs = regular_order;
5141 if (charset == SYMBOL_CHARSET) encs = symbol_order;
5143 while (*encs != 0)
5145 if (select_charmap( face, *encs )) break;
5146 encs++;
5148 return *encs;
5151 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
5153 DWORD size;
5154 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
5155 WORD *alloced = NULL, *ptr = buf;
5156 WORD num_recs, version;
5157 BOOL ret = FALSE;
5159 *flags = 0;
5160 size = get_font_data( font, MS_GASP_TAG, 0, NULL, 0 );
5161 if (size == GDI_ERROR) return FALSE;
5162 if (size < 4 * sizeof(WORD)) return FALSE;
5163 if (size > sizeof(buf))
5165 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
5166 if (!ptr) return FALSE;
5169 get_font_data( font, MS_GASP_TAG, 0, ptr, size );
5171 version = GET_BE_WORD( *ptr++ );
5172 num_recs = GET_BE_WORD( *ptr++ );
5174 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
5176 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
5177 goto done;
5180 while (num_recs--)
5182 *flags = GET_BE_WORD( *(ptr + 1) );
5183 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
5184 ptr += 2;
5186 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
5187 ret = TRUE;
5189 done:
5190 HeapFree( GetProcessHeap(), 0, alloced );
5191 return ret;
5194 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5196 const GSUB_ScriptList *script;
5197 const GSUB_Script *deflt = NULL;
5198 int i;
5199 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5201 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5202 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5204 const GSUB_Script *scr;
5205 int offset;
5207 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5208 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5210 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5211 return scr;
5212 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5213 deflt = scr;
5215 return deflt;
5218 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5220 int i;
5221 int offset;
5222 const GSUB_LangSys *Lang;
5224 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5226 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5228 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5229 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5231 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5232 return Lang;
5234 offset = GET_BE_WORD(script->DefaultLangSys);
5235 if (offset)
5237 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5238 return Lang;
5240 return NULL;
5243 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5245 int i;
5246 const GSUB_FeatureList *feature;
5247 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5249 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5250 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5252 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5253 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5255 const GSUB_Feature *feat;
5256 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5257 return feat;
5260 return NULL;
5263 static const char* get_opentype_script(const GdiFont *font)
5266 * I am not sure if this is the correct way to generate our script tag
5269 switch (font->charset)
5271 case ANSI_CHARSET: return "latn";
5272 case BALTIC_CHARSET: return "latn"; /* ?? */
5273 case CHINESEBIG5_CHARSET: return "hani";
5274 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5275 case GB2312_CHARSET: return "hani";
5276 case GREEK_CHARSET: return "grek";
5277 case HANGUL_CHARSET: return "hang";
5278 case RUSSIAN_CHARSET: return "cyrl";
5279 case SHIFTJIS_CHARSET: return "kana";
5280 case TURKISH_CHARSET: return "latn"; /* ?? */
5281 case VIETNAMESE_CHARSET: return "latn";
5282 case JOHAB_CHARSET: return "latn"; /* ?? */
5283 case ARABIC_CHARSET: return "arab";
5284 case HEBREW_CHARSET: return "hebr";
5285 case THAI_CHARSET: return "thai";
5286 default: return "latn";
5290 static const VOID * get_GSUB_vert_feature(const GdiFont *font)
5292 const GSUB_Header *header;
5293 const GSUB_Script *script;
5294 const GSUB_LangSys *language;
5295 const GSUB_Feature *feature;
5297 if (!font->GSUB_Table)
5298 return NULL;
5300 header = font->GSUB_Table;
5302 script = GSUB_get_script_table(header, get_opentype_script(font));
5303 if (!script)
5305 TRACE("Script not found\n");
5306 return NULL;
5308 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5309 if (!language)
5311 TRACE("Language not found\n");
5312 return NULL;
5314 feature = GSUB_get_feature(header, language, "vrt2");
5315 if (!feature)
5316 feature = GSUB_get_feature(header, language, "vert");
5317 if (!feature)
5319 TRACE("vrt2/vert feature not found\n");
5320 return NULL;
5322 return feature;
5325 static void fill_fileinfo_from_face( GdiFont *font, Face *face )
5327 WIN32_FILE_ATTRIBUTE_DATA info;
5328 int len;
5330 if (!face->file)
5332 font->fileinfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*font->fileinfo));
5333 return;
5336 len = strlenW(face->file);
5337 font->fileinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*font->fileinfo) + len * sizeof(WCHAR));
5338 if (GetFileAttributesExW(face->file, GetFileExInfoStandard, &info))
5340 font->fileinfo->writetime = info.ftLastWriteTime;
5341 font->fileinfo->size.QuadPart = (LONGLONG)info.nFileSizeHigh << 32 | info.nFileSizeLow;
5342 strcpyW(font->fileinfo->path, face->file);
5344 else
5345 memset(font->fileinfo, 0, sizeof(*font->fileinfo) + len * sizeof(WCHAR));
5348 /*************************************************************
5349 * freetype_SelectFont
5351 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
5353 struct freetype_physdev *physdev = get_freetype_dev( dev );
5354 GdiFont *ret;
5355 Face *face, *best, *best_bitmap;
5356 Family *family, *last_resort_family;
5357 const struct list *face_list;
5358 INT height, width = 0;
5359 unsigned int score = 0, new_score;
5360 signed int diff = 0, newdiff;
5361 BOOL bd, it, can_use_bitmap, want_vertical;
5362 LOGFONTW lf;
5363 CHARSETINFO csi;
5364 FMAT2 dcmat;
5365 FontSubst *psub = NULL;
5366 DC *dc = get_physdev_dc( dev );
5367 const SYSTEM_LINKS *font_link;
5369 if (!hfont) /* notification that the font has been changed by another driver */
5371 release_font( physdev->font );
5372 physdev->font = NULL;
5373 return 0;
5376 GetObjectW( hfont, sizeof(lf), &lf );
5377 lf.lfWidth = abs(lf.lfWidth);
5379 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
5381 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
5382 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
5383 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
5384 lf.lfEscapement);
5386 if(dc->GraphicsMode == GM_ADVANCED)
5388 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
5389 /* Try to avoid not necessary glyph transformations */
5390 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
5392 lf.lfHeight *= fabs(dcmat.eM11);
5393 lf.lfWidth *= fabs(dcmat.eM11);
5394 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
5397 else
5399 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
5400 font scaling abilities. */
5401 dcmat.eM11 = dcmat.eM22 = 1.0;
5402 dcmat.eM21 = dcmat.eM12 = 0;
5403 lf.lfOrientation = lf.lfEscapement;
5404 if (dc->vport2WorldValid)
5406 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
5407 lf.lfOrientation = -lf.lfOrientation;
5408 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
5409 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
5413 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
5414 dcmat.eM21, dcmat.eM22);
5416 GDI_CheckNotLock();
5417 EnterCriticalSection( &freetype_cs );
5419 /* check the cache first */
5420 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5421 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
5422 goto done;
5425 TRACE("not in cache\n");
5426 ret = alloc_font();
5428 ret->font_desc.matrix = dcmat;
5429 ret->font_desc.lf = lf;
5430 ret->font_desc.can_use_bitmap = can_use_bitmap;
5431 calc_hash(&ret->font_desc);
5433 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
5434 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
5435 original value lfCharSet. Note this is a special case for
5436 Symbol and doesn't happen at least for "Wingdings*" */
5438 if(!strcmpiW(lf.lfFaceName, SymbolW))
5439 lf.lfCharSet = SYMBOL_CHARSET;
5441 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
5442 switch(lf.lfCharSet) {
5443 case DEFAULT_CHARSET:
5444 csi.fs.fsCsb[0] = 0;
5445 break;
5446 default:
5447 FIXME("Untranslated charset %d\n", lf.lfCharSet);
5448 csi.fs.fsCsb[0] = 0;
5449 break;
5453 family = NULL;
5454 if(lf.lfFaceName[0] != '\0') {
5455 CHILD_FONT *font_link_entry;
5456 LPWSTR FaceName = lf.lfFaceName;
5458 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
5460 if(psub) {
5461 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
5462 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
5463 if (psub->to.charset != -1)
5464 lf.lfCharSet = psub->to.charset;
5467 /* We want a match on name and charset or just name if
5468 charset was DEFAULT_CHARSET. If the latter then
5469 we fixup the returned charset later in get_nearest_charset
5470 where we'll either use the charset of the current ansi codepage
5471 or if that's unavailable the first charset that the font supports.
5473 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5474 if (!strcmpiW(family->FamilyName, FaceName) ||
5475 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
5477 font_link = find_font_link(family->FamilyName);
5478 face_list = get_face_list_from_family(family);
5479 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5480 if (!(face->scalable || can_use_bitmap))
5481 continue;
5482 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5483 goto found;
5484 if (font_link != NULL &&
5485 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5486 goto found;
5487 if (!csi.fs.fsCsb[0])
5488 goto found;
5493 /* Search by full face name. */
5494 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5495 face_list = get_face_list_from_family(family);
5496 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5497 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
5498 (face->scalable || can_use_bitmap))
5500 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5501 goto found_face;
5502 font_link = find_font_link(family->FamilyName);
5503 if (font_link != NULL &&
5504 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5505 goto found_face;
5511 * Try check the SystemLink list first for a replacement font.
5512 * We may find good replacements there.
5514 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
5516 if(!strcmpiW(font_link->font_name, FaceName) ||
5517 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
5519 TRACE("found entry in system list\n");
5520 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5522 const SYSTEM_LINKS *links;
5524 face = font_link_entry->face;
5525 if (!(face->scalable || can_use_bitmap))
5526 continue;
5527 family = face->family;
5528 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5529 goto found;
5530 links = find_font_link(family->FamilyName);
5531 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
5532 goto found;
5538 psub = NULL; /* substitution is no more relevant */
5540 /* If requested charset was DEFAULT_CHARSET then try using charset
5541 corresponding to the current ansi codepage */
5542 if (!csi.fs.fsCsb[0])
5544 INT acp = GetACP();
5545 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
5546 FIXME("TCI failed on codepage %d\n", acp);
5547 csi.fs.fsCsb[0] = 0;
5548 } else
5549 lf.lfCharSet = csi.ciCharset;
5552 want_vertical = (lf.lfFaceName[0] == '@');
5554 /* Face families are in the top 4 bits of lfPitchAndFamily,
5555 so mask with 0xF0 before testing */
5557 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
5558 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
5559 strcpyW(lf.lfFaceName, defFixed);
5560 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
5561 strcpyW(lf.lfFaceName, defSerif);
5562 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
5563 strcpyW(lf.lfFaceName, defSans);
5564 else
5565 strcpyW(lf.lfFaceName, defSans);
5566 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5567 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
5568 font_link = find_font_link(family->FamilyName);
5569 face_list = get_face_list_from_family(family);
5570 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5571 if (!(face->scalable || can_use_bitmap))
5572 continue;
5573 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5574 goto found;
5575 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5576 goto found;
5581 last_resort_family = NULL;
5582 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5583 font_link = find_font_link(family->FamilyName);
5584 face_list = get_face_list_from_family(family);
5585 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5586 if(!(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical &&
5587 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5588 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
5589 if(face->scalable)
5590 goto found;
5591 if(can_use_bitmap && !last_resort_family)
5592 last_resort_family = family;
5597 if(last_resort_family) {
5598 family = last_resort_family;
5599 csi.fs.fsCsb[0] = 0;
5600 goto found;
5603 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5604 face_list = get_face_list_from_family(family);
5605 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5606 if(face->scalable && !(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical) {
5607 csi.fs.fsCsb[0] = 0;
5608 WARN("just using first face for now\n");
5609 goto found;
5611 if(can_use_bitmap && !last_resort_family)
5612 last_resort_family = family;
5615 if(!last_resort_family) {
5616 FIXME("can't find a single appropriate font - bailing\n");
5617 free_font(ret);
5618 ret = NULL;
5619 goto done;
5622 WARN("could only find a bitmap font - this will probably look awful!\n");
5623 family = last_resort_family;
5624 csi.fs.fsCsb[0] = 0;
5626 found:
5627 it = lf.lfItalic ? 1 : 0;
5628 bd = lf.lfWeight > 550 ? 1 : 0;
5630 height = lf.lfHeight;
5632 face = best = best_bitmap = NULL;
5633 font_link = find_font_link(family->FamilyName);
5634 face_list = get_face_list_from_family(family);
5635 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5637 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5638 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
5639 !csi.fs.fsCsb[0])
5641 BOOL italic, bold;
5643 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
5644 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
5645 new_score = (italic ^ it) + (bold ^ bd);
5646 if(!best || new_score <= score)
5648 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5649 italic, bold, it, bd);
5650 score = new_score;
5651 best = face;
5652 if(best->scalable && score == 0) break;
5653 if(!best->scalable)
5655 if(height > 0)
5656 newdiff = height - (signed int)(best->size.height);
5657 else
5658 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
5659 if(!best_bitmap || new_score < score ||
5660 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
5662 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
5663 diff = newdiff;
5664 best_bitmap = best;
5665 if(score == 0 && diff == 0) break;
5671 if(best)
5672 face = best->scalable ? best : best_bitmap;
5673 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
5674 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
5676 found_face:
5677 height = lf.lfHeight;
5679 ret->fs = face->fs;
5681 if(csi.fs.fsCsb[0]) {
5682 ret->charset = lf.lfCharSet;
5683 ret->codepage = csi.ciACP;
5685 else
5686 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
5688 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
5689 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
5691 ret->aveWidth = height ? lf.lfWidth : 0;
5693 if(!face->scalable) {
5694 /* Windows uses integer scaling factors for bitmap fonts */
5695 INT scale, scaled_height;
5696 GdiFont *cachedfont;
5698 /* FIXME: rotation of bitmap fonts is ignored */
5699 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
5700 if (ret->aveWidth)
5701 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
5702 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
5703 dcmat.eM11 = dcmat.eM22 = 1.0;
5704 /* As we changed the matrix, we need to search the cache for the font again,
5705 * otherwise we might explode the cache. */
5706 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5707 TRACE("Found cached font after non-scalable matrix rescale!\n");
5708 free_font( ret );
5709 ret = cachedfont;
5710 goto done;
5712 calc_hash(&ret->font_desc);
5714 if (height != 0) height = diff;
5715 height += face->size.height;
5717 scale = (height + face->size.height - 1) / face->size.height;
5718 scaled_height = scale * face->size.height;
5719 /* Only jump to the next height if the difference <= 25% original height */
5720 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
5721 /* The jump between unscaled and doubled is delayed by 1 */
5722 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
5723 ret->scale_y = scale;
5725 width = face->size.x_ppem >> 6;
5726 height = face->size.y_ppem >> 6;
5728 else
5729 ret->scale_y = 1.0;
5730 TRACE("font scale y: %f\n", ret->scale_y);
5732 ret->ft_face = OpenFontFace(ret, face, width, height);
5734 if (!ret->ft_face)
5736 free_font( ret );
5737 ret = NULL;
5738 goto done;
5741 fill_fileinfo_from_face( ret, face );
5742 ret->ntmFlags = face->ntmFlags;
5744 pick_charmap( ret->ft_face, ret->charset );
5746 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
5747 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
5748 ret->underline = lf.lfUnderline ? 0xff : 0;
5749 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
5750 create_child_font_list(ret);
5752 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
5754 int length = get_font_data(ret, MS_GSUB_TAG , 0, NULL, 0);
5755 if (length != GDI_ERROR)
5757 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
5758 get_font_data(ret, MS_GSUB_TAG , 0, ret->GSUB_Table, length);
5759 TRACE("Loaded GSUB table of %i bytes\n",length);
5760 ret->vert_feature = get_GSUB_vert_feature(ret);
5761 if (!ret->vert_feature)
5763 TRACE("Vertical feature not found\n");
5764 HeapFree(GetProcessHeap(), 0, ret->GSUB_Table);
5765 ret->GSUB_Table = NULL;
5769 ret->aa_flags = HIWORD( face->flags );
5771 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
5773 add_to_cache(ret);
5774 done:
5775 if (ret)
5777 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
5779 switch (lf.lfQuality)
5781 case NONANTIALIASED_QUALITY:
5782 case ANTIALIASED_QUALITY:
5783 next->funcs->pSelectFont( dev, hfont, aa_flags );
5784 break;
5785 case CLEARTYPE_QUALITY:
5786 case CLEARTYPE_NATURAL_QUALITY:
5787 default:
5788 if (!*aa_flags) *aa_flags = ret->aa_flags;
5789 next->funcs->pSelectFont( dev, hfont, aa_flags );
5791 /* fixup the antialiasing flags for that font */
5792 switch (*aa_flags)
5794 case WINE_GGO_HRGB_BITMAP:
5795 case WINE_GGO_HBGR_BITMAP:
5796 case WINE_GGO_VRGB_BITMAP:
5797 case WINE_GGO_VBGR_BITMAP:
5798 if (is_subpixel_rendering_enabled()) break;
5799 *aa_flags = GGO_GRAY4_BITMAP;
5800 /* fall through */
5801 case GGO_GRAY2_BITMAP:
5802 case GGO_GRAY4_BITMAP:
5803 case GGO_GRAY8_BITMAP:
5804 case WINE_GGO_GRAY16_BITMAP:
5805 if ((!antialias_fakes || (!ret->fake_bold && !ret->fake_italic)) && is_hinting_enabled())
5807 WORD gasp_flags;
5808 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
5810 TRACE( "font %s %d aa disabled by GASP\n",
5811 debugstr_w(lf.lfFaceName), lf.lfHeight );
5812 *aa_flags = GGO_BITMAP;
5817 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5818 release_font( physdev->font );
5819 physdev->font = ret;
5821 LeaveCriticalSection( &freetype_cs );
5822 return ret ? hfont : 0;
5825 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5827 HRSRC rsrc;
5828 HGLOBAL hMem;
5829 WCHAR *p;
5830 int i;
5832 id += IDS_FIRST_SCRIPT;
5833 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5834 if (!rsrc) return 0;
5835 hMem = LoadResource( gdi32_module, rsrc );
5836 if (!hMem) return 0;
5838 p = LockResource( hMem );
5839 id &= 0x000f;
5840 while (id--) p += *p + 1;
5842 i = min(LF_FACESIZE - 1, *p);
5843 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5844 buffer[i] = 0;
5845 return i;
5848 static inline BOOL is_complex_script_ansi_cp(UINT ansi_cp)
5850 return (ansi_cp == 874 /* Thai */
5851 || ansi_cp == 1255 /* Hebrew */
5852 || ansi_cp == 1256 /* Arabic */
5856 /***************************************************
5857 * create_enum_charset_list
5859 * This function creates charset enumeration list because in DEFAULT_CHARSET
5860 * case, the ANSI codepage's charset takes precedence over other charsets.
5861 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
5862 * This function works as a filter other than DEFAULT_CHARSET case.
5864 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5866 CHARSETINFO csi;
5867 DWORD n = 0;
5869 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5870 csi.fs.fsCsb[0] != 0) {
5871 list->element[n].mask = csi.fs.fsCsb[0];
5872 list->element[n].charset = csi.ciCharset;
5873 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5874 n++;
5876 else { /* charset is DEFAULT_CHARSET or invalid. */
5877 INT acp, i;
5878 DWORD mask = 0;
5880 /* Set the current codepage's charset as the first element. */
5881 acp = GetACP();
5882 if (!is_complex_script_ansi_cp(acp) &&
5883 TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5884 csi.fs.fsCsb[0] != 0) {
5885 list->element[n].mask = csi.fs.fsCsb[0];
5886 list->element[n].charset = csi.ciCharset;
5887 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5888 mask |= csi.fs.fsCsb[0];
5889 n++;
5892 /* Fill out left elements. */
5893 for (i = 0; i < 32; i++) {
5894 FONTSIGNATURE fs;
5895 fs.fsCsb[0] = 1L << i;
5896 fs.fsCsb[1] = 0;
5897 if (fs.fsCsb[0] & mask)
5898 continue; /* skip, already added. */
5899 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5900 continue; /* skip, this is an invalid fsCsb bit. */
5902 list->element[n].mask = fs.fsCsb[0];
5903 list->element[n].charset = csi.ciCharset;
5904 load_script_name( i, list->element[n].name );
5905 mask |= fs.fsCsb[0];
5906 n++;
5909 /* add catch all mask for remaining bits */
5910 if (~mask)
5912 list->element[n].mask = ~mask;
5913 list->element[n].charset = DEFAULT_CHARSET;
5914 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5915 n++;
5918 list->total = n;
5920 return n;
5923 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
5924 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5926 GdiFont *font;
5927 LONG width, height;
5929 if (face->cached_enum_data)
5931 TRACE("Cached\n");
5932 *pelf = face->cached_enum_data->elf;
5933 *pntm = face->cached_enum_data->ntm;
5934 *ptype = face->cached_enum_data->type;
5935 return;
5938 font = alloc_font();
5940 if(face->scalable) {
5941 height = 100;
5942 width = 0;
5943 } else {
5944 height = face->size.y_ppem >> 6;
5945 width = face->size.x_ppem >> 6;
5947 font->scale_y = 1.0;
5949 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5951 free_font(font);
5952 return;
5955 font->name = strdupW( family_name );
5956 font->ntmFlags = face->ntmFlags;
5958 if (get_outline_text_metrics(font))
5960 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5962 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5963 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5964 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5966 lstrcpynW(pelf->elfLogFont.lfFaceName,
5967 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5968 LF_FACESIZE);
5969 lstrcpynW(pelf->elfFullName,
5970 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5971 LF_FULLFACESIZE);
5972 lstrcpynW(pelf->elfStyle,
5973 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5974 LF_FACESIZE);
5976 else
5978 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5980 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5981 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5982 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5984 lstrcpynW(pelf->elfLogFont.lfFaceName, family_name, LF_FACESIZE);
5985 if (face->FullName)
5986 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5987 else
5988 lstrcpynW(pelf->elfFullName, family_name, LF_FULLFACESIZE);
5989 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5992 pntm->ntmTm.ntmFlags = face->ntmFlags;
5993 pntm->ntmFontSig = face->fs;
5995 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5997 pelf->elfLogFont.lfEscapement = 0;
5998 pelf->elfLogFont.lfOrientation = 0;
5999 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
6000 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
6001 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
6002 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
6003 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
6004 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
6005 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
6006 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
6007 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
6008 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
6009 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
6011 *ptype = 0;
6012 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
6013 *ptype |= TRUETYPE_FONTTYPE;
6014 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
6015 *ptype |= DEVICE_FONTTYPE;
6016 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
6017 *ptype |= RASTER_FONTTYPE;
6019 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
6020 if (face->cached_enum_data)
6022 face->cached_enum_data->elf = *pelf;
6023 face->cached_enum_data->ntm = *pntm;
6024 face->cached_enum_data->type = *ptype;
6027 free_font(font);
6030 static BOOL family_matches(Family *family, const WCHAR *face_name)
6032 Face *face;
6033 const struct list *face_list;
6035 if (!strcmpiW(face_name, family->FamilyName)) return TRUE;
6037 face_list = get_face_list_from_family(family);
6038 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
6039 if (face->FullName && !strcmpiW(face_name, face->FullName)) return TRUE;
6041 return FALSE;
6044 static BOOL face_matches(const WCHAR *family_name, Face *face, const WCHAR *face_name)
6046 if (!strcmpiW(face_name, family_name)) return TRUE;
6048 return (face->FullName && !strcmpiW(face_name, face->FullName));
6051 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
6052 FONTENUMPROCW proc, LPARAM lparam, const WCHAR *subst)
6054 ENUMLOGFONTEXW elf;
6055 NEWTEXTMETRICEXW ntm;
6056 DWORD type = 0;
6057 DWORD i;
6059 GetEnumStructs(face, face->family->FamilyName, &elf, &ntm, &type);
6060 for(i = 0; i < list->total; i++) {
6061 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
6062 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
6063 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
6064 i = list->total; /* break out of loop after enumeration */
6066 else
6068 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
6069 /* use the DEFAULT_CHARSET case only if no other charset is present */
6070 if (list->element[i].charset == DEFAULT_CHARSET &&
6071 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
6072 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
6073 strcpyW(elf.elfScript, list->element[i].name);
6074 if (!elf.elfScript[0])
6075 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
6077 /* Font Replacement */
6078 if (family != face->family)
6080 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
6081 if (face->FullName)
6082 strcpyW(elf.elfFullName, face->FullName);
6083 else
6084 strcpyW(elf.elfFullName, family->FamilyName);
6086 if (subst)
6087 strcpyW(elf.elfLogFont.lfFaceName, subst);
6088 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
6089 debugstr_w(elf.elfLogFont.lfFaceName),
6090 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
6091 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
6092 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
6093 ntm.ntmTm.ntmFlags);
6094 /* release section before callback (FIXME) */
6095 LeaveCriticalSection( &freetype_cs );
6096 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
6097 EnterCriticalSection( &freetype_cs );
6099 return TRUE;
6102 /*************************************************************
6103 * freetype_EnumFonts
6105 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
6107 Family *family;
6108 Face *face;
6109 const struct list *face_list;
6110 LOGFONTW lf;
6111 struct enum_charset_list enum_charsets;
6113 if (!plf)
6115 lf.lfCharSet = DEFAULT_CHARSET;
6116 lf.lfPitchAndFamily = 0;
6117 lf.lfFaceName[0] = 0;
6118 plf = &lf;
6121 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
6123 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
6125 GDI_CheckNotLock();
6126 EnterCriticalSection( &freetype_cs );
6127 if(plf->lfFaceName[0]) {
6128 WCHAR *face_name = plf->lfFaceName;
6129 FontSubst *psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
6131 if(psub) {
6132 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
6133 debugstr_w(psub->to.name));
6134 face_name = psub->to.name;
6137 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
6138 if (!family_matches(family, face_name)) continue;
6139 face_list = get_face_list_from_family(family);
6140 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
6141 if (!face_matches(family->FamilyName, face, face_name)) continue;
6142 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam, psub ? psub->from.name : NULL)) return FALSE;
6145 } else {
6146 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
6147 face_list = get_face_list_from_family(family);
6148 face = LIST_ENTRY(list_head(face_list), Face, entry);
6149 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam, NULL)) return FALSE;
6152 LeaveCriticalSection( &freetype_cs );
6153 return TRUE;
6156 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
6158 pt->x.value = vec->x >> 6;
6159 pt->x.fract = (vec->x & 0x3f) << 10;
6160 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
6161 pt->y.value = vec->y >> 6;
6162 pt->y.fract = (vec->y & 0x3f) << 10;
6163 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
6166 /***************************************************
6167 * According to the MSDN documentation on WideCharToMultiByte,
6168 * certain codepages cannot set the default_used parameter.
6169 * This returns TRUE if the codepage can set that parameter, false else
6170 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
6172 static BOOL codepage_sets_default_used(UINT codepage)
6174 switch (codepage)
6176 case CP_UTF7:
6177 case CP_UTF8:
6178 case CP_SYMBOL:
6179 return FALSE;
6180 default:
6181 return TRUE;
6186 * GSUB Table handling functions
6189 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
6191 const GSUB_CoverageFormat1* cf1;
6193 cf1 = table;
6195 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
6197 int count = GET_BE_WORD(cf1->GlyphCount);
6198 int i;
6199 TRACE("Coverage Format 1, %i glyphs\n",count);
6200 for (i = 0; i < count; i++)
6201 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
6202 return i;
6203 return -1;
6205 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
6207 const GSUB_CoverageFormat2* cf2;
6208 int i;
6209 int count;
6210 cf2 = (const GSUB_CoverageFormat2*)cf1;
6212 count = GET_BE_WORD(cf2->RangeCount);
6213 TRACE("Coverage Format 2, %i ranges\n",count);
6214 for (i = 0; i < count; i++)
6216 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
6217 return -1;
6218 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
6219 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
6221 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
6222 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
6225 return -1;
6227 else
6228 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
6230 return -1;
6233 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
6235 int i;
6236 int offset;
6237 const GSUB_LookupList *lookup;
6238 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
6240 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
6241 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
6243 const GSUB_LookupTable *look;
6244 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
6245 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
6246 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
6247 if (GET_BE_WORD(look->LookupType) != 1)
6248 FIXME("We only handle SubType 1\n");
6249 else
6251 int j;
6253 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
6255 const GSUB_SingleSubstFormat1 *ssf1;
6256 offset = GET_BE_WORD(look->SubTable[j]);
6257 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
6258 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
6260 int offset = GET_BE_WORD(ssf1->Coverage);
6261 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
6262 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
6264 TRACE(" Glyph 0x%x ->",glyph);
6265 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
6266 TRACE(" 0x%x\n",glyph);
6269 else
6271 const GSUB_SingleSubstFormat2 *ssf2;
6272 INT index;
6273 INT offset;
6275 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
6276 offset = GET_BE_WORD(ssf1->Coverage);
6277 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
6278 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
6279 TRACE(" Coverage index %i\n",index);
6280 if (index != -1)
6282 TRACE(" Glyph is 0x%x ->",glyph);
6283 glyph = GET_BE_WORD(ssf2->Substitute[index]);
6284 TRACE("0x%x\n",glyph);
6290 return glyph;
6294 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
6296 const GSUB_Header *header;
6297 const GSUB_Feature *feature;
6299 if (!font->GSUB_Table)
6300 return glyph;
6302 header = font->GSUB_Table;
6303 feature = font->vert_feature;
6305 return GSUB_apply_feature(header, feature, glyph);
6308 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
6310 FT_UInt glyphId;
6312 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
6313 WCHAR wc = (WCHAR)glyph;
6314 BOOL default_used;
6315 BOOL *default_used_pointer;
6316 FT_UInt ret;
6317 char buf;
6318 default_used_pointer = NULL;
6319 default_used = FALSE;
6320 if (codepage_sets_default_used(font->codepage))
6321 default_used_pointer = &default_used;
6322 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
6324 if (font->codepage == CP_SYMBOL && wc < 0x100)
6325 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
6326 else
6327 ret = 0;
6329 else
6330 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
6331 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6332 return ret;
6335 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
6337 if (glyph < 0x100) glyph += 0xf000;
6338 /* there is a number of old pre-Unicode "broken" TTFs, which
6339 do have symbols at U+00XX instead of U+f0XX */
6340 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
6341 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
6343 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
6345 return glyphId;
6348 /* helper for freetype_GetGlyphIndices */
6349 static FT_UInt get_gdi_glyph_index(const GdiFont *font, UINT glyph)
6351 WCHAR wc = (WCHAR)glyph;
6352 BOOL default_used = FALSE;
6353 BOOL *default_used_pointer = NULL;
6354 FT_UInt ret;
6355 char buf;
6357 if(font->ft_face->charmap->encoding != FT_ENCODING_NONE)
6358 return get_glyph_index(font, glyph);
6360 if (codepage_sets_default_used(font->codepage))
6361 default_used_pointer = &default_used;
6362 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer)
6363 || default_used)
6365 if (font->codepage == CP_SYMBOL && wc < 0x100)
6366 ret = (unsigned char)wc;
6367 else
6368 ret = 0;
6370 else
6371 ret = (unsigned char)buf;
6372 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6373 return ret;
6376 static FT_UInt get_default_char_index(GdiFont *font)
6378 FT_UInt default_char;
6380 if (FT_IS_SFNT(font->ft_face))
6382 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
6383 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
6385 else
6387 TEXTMETRICW textm;
6388 get_text_metrics(font, &textm);
6389 default_char = textm.tmDefaultChar;
6392 return default_char;
6395 /*************************************************************
6396 * freetype_GetGlyphIndices
6398 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
6400 struct freetype_physdev *physdev = get_freetype_dev( dev );
6401 int i;
6402 WORD default_char;
6403 BOOL got_default = FALSE;
6405 if (!physdev->font)
6407 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
6408 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
6411 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
6413 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
6414 got_default = TRUE;
6417 GDI_CheckNotLock();
6418 EnterCriticalSection( &freetype_cs );
6420 for(i = 0; i < count; i++)
6422 pgi[i] = get_gdi_glyph_index(physdev->font, lpstr[i]);
6423 if (pgi[i] == 0)
6425 if (!got_default)
6427 default_char = get_default_char_index(physdev->font);
6428 got_default = TRUE;
6430 pgi[i] = default_char;
6432 else
6433 pgi[i] = get_GSUB_vert_glyph(physdev->font, pgi[i]);
6435 LeaveCriticalSection( &freetype_cs );
6436 return count;
6439 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
6441 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
6442 return !memcmp(matrix, &identity, sizeof(FMAT2));
6445 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
6447 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
6448 return !memcmp(matrix, &identity, sizeof(MAT2));
6451 static inline FT_Vector normalize_vector(FT_Vector *vec)
6453 FT_Vector out;
6454 FT_Fixed len;
6455 len = pFT_Vector_Length(vec);
6456 if (len) {
6457 out.x = (vec->x << 6) / len;
6458 out.y = (vec->y << 6) / len;
6460 else
6461 out.x = out.y = 0;
6462 return out;
6465 static BOOL get_bold_glyph_outline(FT_GlyphSlot glyph, LONG ppem, FT_Glyph_Metrics *metrics)
6467 FT_Error err;
6468 FT_Pos strength;
6469 FT_BBox bbox;
6471 if(glyph->format != FT_GLYPH_FORMAT_OUTLINE)
6472 return FALSE;
6473 if(!pFT_Outline_Embolden)
6474 return FALSE;
6476 strength = MulDiv(ppem, 1 << 6, 24);
6477 err = pFT_Outline_Embolden(&glyph->outline, strength);
6478 if(err) {
6479 TRACE("FT_Ouline_Embolden returns %d\n", err);
6480 return FALSE;
6483 pFT_Outline_Get_CBox(&glyph->outline, &bbox);
6484 metrics->width = bbox.xMax - bbox.xMin;
6485 metrics->height = bbox.yMax - bbox.yMin;
6486 metrics->horiBearingX = bbox.xMin;
6487 metrics->horiBearingY = bbox.yMax;
6488 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
6489 metrics->vertBearingY = (metrics->vertAdvance - metrics->height) / 2;
6490 return TRUE;
6493 static inline BYTE get_max_level( UINT format )
6495 switch( format )
6497 case GGO_GRAY2_BITMAP: return 4;
6498 case GGO_GRAY4_BITMAP: return 16;
6499 case GGO_GRAY8_BITMAP: return 64;
6501 return 255;
6504 extern const unsigned short vertical_orientation_table[] DECLSPEC_HIDDEN;
6506 static BOOL check_unicode_tategaki(WCHAR uchar)
6508 unsigned short orientation = vertical_orientation_table[vertical_orientation_table[vertical_orientation_table[uchar >> 8]+((uchar >> 4) & 0x0f)]+ (uchar & 0xf)];
6510 /* We only reach this code if typographical substitution did not occur */
6511 /* Type: U or Type: Tu */
6512 return (orientation == 1 || orientation == 3);
6515 static FT_Vector get_advance_metric(GdiFont *incoming_font, GdiFont *font,
6516 const FT_Glyph_Metrics *metrics,
6517 const FT_Matrix *transMat, BOOL vertical_metrics)
6519 FT_Vector adv;
6520 FT_Fixed base_advance, em_scale = 0;
6521 BOOL fixed_pitch_full = FALSE;
6523 if (vertical_metrics)
6524 base_advance = metrics->vertAdvance;
6525 else
6526 base_advance = metrics->horiAdvance;
6528 adv.x = base_advance;
6529 adv.y = 0;
6531 /* In fixed-pitch font, we adjust the fullwidth character advance so that
6532 they have double halfwidth character width. E.g. if the font is 19 ppem,
6533 we return 20 (not 19) for fullwidth characters as we return 10 for
6534 halfwidth characters. */
6535 if(FT_IS_SCALABLE(incoming_font->ft_face) &&
6536 (incoming_font->potm || get_outline_text_metrics(incoming_font)) &&
6537 !(incoming_font->potm->otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
6538 UINT avg_advance;
6539 em_scale = MulDiv(incoming_font->ppem, 1 << 16,
6540 incoming_font->ft_face->units_per_EM);
6541 avg_advance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
6542 fixed_pitch_full = (avg_advance > 0 &&
6543 (base_advance + 63) >> 6 ==
6544 pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale));
6545 if (fixed_pitch_full && !transMat)
6546 adv.x = (avg_advance * 2) << 6;
6549 if (transMat) {
6550 pFT_Vector_Transform(&adv, transMat);
6551 if (fixed_pitch_full && adv.y == 0) {
6552 FT_Vector vec;
6553 vec.x = incoming_font->ntmAvgWidth;
6554 vec.y = 0;
6555 pFT_Vector_Transform(&vec, transMat);
6556 adv.x = (pFT_MulFix(vec.x, em_scale) * 2) << 6;
6560 if (font->fake_bold) {
6561 if (!transMat)
6562 adv.x += 1 << 6;
6563 else {
6564 FT_Vector fake_bold_adv, vec = { 1 << 6, 0 };
6565 pFT_Vector_Transform(&vec, transMat);
6566 fake_bold_adv = normalize_vector(&vec);
6567 adv.x += fake_bold_adv.x;
6568 adv.y += fake_bold_adv.y;
6572 adv.x = (adv.x + 63) & -64;
6573 adv.y = -((adv.y + 63) & -64);
6574 return adv;
6577 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
6579 TTPOLYGONHEADER *pph;
6580 TTPOLYCURVE *ppc;
6581 unsigned int needed = 0, point = 0, contour, first_pt;
6582 unsigned int pph_start, cpfx;
6583 DWORD type;
6585 for (contour = 0; contour < outline->n_contours; contour++)
6587 /* Ignore contours containing one point */
6588 if (point == outline->contours[contour])
6590 point++;
6591 continue;
6594 pph_start = needed;
6595 pph = (TTPOLYGONHEADER *)(buf + needed);
6596 first_pt = point;
6597 if (buf)
6599 pph->dwType = TT_POLYGON_TYPE;
6600 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6602 needed += sizeof(*pph);
6603 point++;
6604 while (point <= outline->contours[contour])
6606 ppc = (TTPOLYCURVE *)(buf + needed);
6607 type = outline->tags[point] & FT_Curve_Tag_On ?
6608 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6609 cpfx = 0;
6612 if (buf)
6613 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6614 cpfx++;
6615 point++;
6616 } while (point <= outline->contours[contour] &&
6617 (outline->tags[point] & FT_Curve_Tag_On) ==
6618 (outline->tags[point-1] & FT_Curve_Tag_On));
6619 /* At the end of a contour Windows adds the start point, but
6620 only for Beziers */
6621 if (point > outline->contours[contour] &&
6622 !(outline->tags[point-1] & FT_Curve_Tag_On))
6624 if (buf)
6625 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6626 cpfx++;
6628 else if (point <= outline->contours[contour] &&
6629 outline->tags[point] & FT_Curve_Tag_On)
6631 /* add closing pt for bezier */
6632 if (buf)
6633 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6634 cpfx++;
6635 point++;
6637 if (buf)
6639 ppc->wType = type;
6640 ppc->cpfx = cpfx;
6642 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6644 if (buf)
6645 pph->cb = needed - pph_start;
6647 return needed;
6650 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
6652 /* Convert the quadratic Beziers to cubic Beziers.
6653 The parametric eqn for a cubic Bezier is, from PLRM:
6654 r(t) = at^3 + bt^2 + ct + r0
6655 with the control points:
6656 r1 = r0 + c/3
6657 r2 = r1 + (c + b)/3
6658 r3 = r0 + c + b + a
6660 A quadratic Bezier has the form:
6661 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6663 So equating powers of t leads to:
6664 r1 = 2/3 p1 + 1/3 p0
6665 r2 = 2/3 p1 + 1/3 p2
6666 and of course r0 = p0, r3 = p2
6668 int contour, point = 0, first_pt;
6669 TTPOLYGONHEADER *pph;
6670 TTPOLYCURVE *ppc;
6671 DWORD pph_start, cpfx, type;
6672 FT_Vector cubic_control[4];
6673 unsigned int needed = 0;
6675 for (contour = 0; contour < outline->n_contours; contour++)
6677 pph_start = needed;
6678 pph = (TTPOLYGONHEADER *)(buf + needed);
6679 first_pt = point;
6680 if (buf)
6682 pph->dwType = TT_POLYGON_TYPE;
6683 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6685 needed += sizeof(*pph);
6686 point++;
6687 while (point <= outline->contours[contour])
6689 ppc = (TTPOLYCURVE *)(buf + needed);
6690 type = outline->tags[point] & FT_Curve_Tag_On ?
6691 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6692 cpfx = 0;
6695 if (type == TT_PRIM_LINE)
6697 if (buf)
6698 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6699 cpfx++;
6700 point++;
6702 else
6704 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6705 so cpfx = 3n */
6707 /* FIXME: Possible optimization in endpoint calculation
6708 if there are two consecutive curves */
6709 cubic_control[0] = outline->points[point-1];
6710 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
6712 cubic_control[0].x += outline->points[point].x + 1;
6713 cubic_control[0].y += outline->points[point].y + 1;
6714 cubic_control[0].x >>= 1;
6715 cubic_control[0].y >>= 1;
6717 if (point+1 > outline->contours[contour])
6718 cubic_control[3] = outline->points[first_pt];
6719 else
6721 cubic_control[3] = outline->points[point+1];
6722 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
6724 cubic_control[3].x += outline->points[point].x + 1;
6725 cubic_control[3].y += outline->points[point].y + 1;
6726 cubic_control[3].x >>= 1;
6727 cubic_control[3].y >>= 1;
6730 /* r1 = 1/3 p0 + 2/3 p1
6731 r2 = 1/3 p2 + 2/3 p1 */
6732 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6733 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6734 cubic_control[2] = cubic_control[1];
6735 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6736 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6737 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6738 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6739 if (buf)
6741 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6742 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6743 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6745 cpfx += 3;
6746 point++;
6748 } while (point <= outline->contours[contour] &&
6749 (outline->tags[point] & FT_Curve_Tag_On) ==
6750 (outline->tags[point-1] & FT_Curve_Tag_On));
6751 /* At the end of a contour Windows adds the start point,
6752 but only for Beziers and we've already done that.
6754 if (point <= outline->contours[contour] &&
6755 outline->tags[point] & FT_Curve_Tag_On)
6757 /* This is the closing pt of a bezier, but we've already
6758 added it, so just inc point and carry on */
6759 point++;
6761 if (buf)
6763 ppc->wType = type;
6764 ppc->cpfx = cpfx;
6766 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6768 if (buf)
6769 pph->cb = needed - pph_start;
6771 return needed;
6774 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6776 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
6777 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
6778 const MAT2* lpmat)
6780 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
6781 GLYPHMETRICS gm;
6782 FT_Face ft_face = incoming_font->ft_face;
6783 GdiFont *font = incoming_font;
6784 FT_Glyph_Metrics metrics;
6785 FT_UInt glyph_index;
6786 DWORD width, height, pitch, needed = 0;
6787 FT_Bitmap ft_bitmap;
6788 FT_Error err;
6789 INT left, right, top = 0, bottom = 0;
6790 FT_Vector adv;
6791 INT origin_x = 0, origin_y = 0;
6792 FT_Angle angle = 0;
6793 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
6794 double widthRatio = 1.0;
6795 FT_Matrix transMat = identityMat;
6796 FT_Matrix transMatUnrotated;
6797 FT_Matrix transMatTategaki;
6798 BOOL needsTransform = FALSE;
6799 BOOL tategaki = (font->name[0] == '@');
6800 BOOL vertical_metrics;
6801 UINT original_index;
6803 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
6804 buflen, buf, lpmat);
6806 TRACE("font transform %f %f %f %f\n",
6807 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
6808 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
6810 if(format & GGO_GLYPH_INDEX) {
6811 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
6812 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
6813 as glyph index. "Treasure Adventure Game" depends on this. */
6814 glyph_index = pFT_Get_Char_Index(font->ft_face, glyph);
6815 TRACE("translate glyph index %04x -> %04x\n", glyph, glyph_index);
6816 } else
6817 glyph_index = glyph;
6818 original_index = glyph_index;
6819 format &= ~GGO_GLYPH_INDEX;
6820 /* TODO: Window also turns off tategaki for glyphs passed in by index
6821 if their unicode code points fall outside of the range that is
6822 rotated. */
6823 } else {
6824 BOOL vert;
6825 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index, &vert);
6826 ft_face = font->ft_face;
6827 original_index = glyph_index;
6828 if (!vert && tategaki)
6829 tategaki = check_unicode_tategaki(glyph);
6832 if(format & GGO_UNHINTED) {
6833 load_flags |= FT_LOAD_NO_HINTING;
6834 format &= ~GGO_UNHINTED;
6837 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
6838 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
6839 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
6840 font->gmsize * sizeof(GM*));
6841 } else {
6842 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
6843 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
6845 *lpgm = FONT_GM(font,original_index)->gm;
6846 *abc = FONT_GM(font,original_index)->abc;
6847 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6848 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6849 lpgm->gmCellIncX, lpgm->gmCellIncY);
6850 return 1; /* FIXME */
6854 if (!font->gm[original_index / GM_BLOCK_SIZE])
6855 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
6857 /* Scaling factor */
6858 if (font->aveWidth)
6860 TEXTMETRICW tm;
6862 get_text_metrics(font, &tm);
6864 widthRatio = (double)font->aveWidth;
6865 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6867 else
6868 widthRatio = font->scale_y;
6870 /* Scaling transform */
6871 if (widthRatio != 1.0 || font->scale_y != 1.0)
6873 FT_Matrix scaleMat;
6874 scaleMat.xx = FT_FixedFromFloat(widthRatio);
6875 scaleMat.xy = 0;
6876 scaleMat.yx = 0;
6877 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
6879 pFT_Matrix_Multiply(&scaleMat, &transMat);
6880 needsTransform = TRUE;
6883 /* Slant transform */
6884 if (font->fake_italic) {
6885 FT_Matrix slantMat;
6887 slantMat.xx = (1 << 16);
6888 slantMat.xy = ((1 << 16) >> 2);
6889 slantMat.yx = 0;
6890 slantMat.yy = (1 << 16);
6891 pFT_Matrix_Multiply(&slantMat, &transMat);
6892 needsTransform = TRUE;
6895 /* Rotation transform */
6896 transMatUnrotated = transMat;
6897 transMatTategaki = transMat;
6898 if(font->orientation || tategaki) {
6899 FT_Matrix rotationMat;
6900 FT_Matrix taterotationMat;
6901 FT_Vector vecAngle;
6903 double orient = font->orientation / 10.0;
6904 double tate_orient = 0.f;
6906 if (tategaki)
6907 tate_orient = ((font->orientation+900)%3600)/10.0;
6908 else
6909 tate_orient = font->orientation/10.0;
6911 if (orient)
6913 angle = FT_FixedFromFloat(orient);
6914 pFT_Vector_Unit(&vecAngle, angle);
6915 rotationMat.xx = vecAngle.x;
6916 rotationMat.xy = -vecAngle.y;
6917 rotationMat.yx = -rotationMat.xy;
6918 rotationMat.yy = rotationMat.xx;
6920 pFT_Matrix_Multiply(&rotationMat, &transMat);
6923 if (tate_orient)
6925 angle = FT_FixedFromFloat(tate_orient);
6926 pFT_Vector_Unit(&vecAngle, angle);
6927 taterotationMat.xx = vecAngle.x;
6928 taterotationMat.xy = -vecAngle.y;
6929 taterotationMat.yx = -taterotationMat.xy;
6930 taterotationMat.yy = taterotationMat.xx;
6931 pFT_Matrix_Multiply(&taterotationMat, &transMatTategaki);
6934 needsTransform = TRUE;
6937 /* World transform */
6938 if (!is_identity_FMAT2(&font->font_desc.matrix))
6940 FT_Matrix worldMat;
6941 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
6942 worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21);
6943 worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12);
6944 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
6945 pFT_Matrix_Multiply(&worldMat, &transMat);
6946 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
6947 pFT_Matrix_Multiply(&worldMat, &transMatTategaki);
6948 needsTransform = TRUE;
6951 /* Extra transformation specified by caller */
6952 if (!is_identity_MAT2(lpmat))
6954 FT_Matrix extraMat;
6955 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
6956 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
6957 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
6958 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
6959 pFT_Matrix_Multiply(&extraMat, &transMat);
6960 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
6961 pFT_Matrix_Multiply(&extraMat, &transMatTategaki);
6962 needsTransform = TRUE;
6965 vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face));
6966 /* there is a freetype bug where vertical metrics are only
6967 properly scaled and correct in 2.4.0 or greater */
6968 if ((vertical_metrics) && (FT_Version.major < 2 || (FT_Version.major == 2 && FT_Version.minor < 4)))
6969 vertical_metrics = FALSE;
6971 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
6972 if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
6974 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
6976 if(err) {
6977 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
6978 return GDI_ERROR;
6981 metrics = ft_face->glyph->metrics;
6982 if(font->fake_bold) {
6983 if (!get_bold_glyph_outline(ft_face->glyph, font->ppem, &metrics) && metrics.width)
6984 metrics.width += 1 << 6;
6987 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6988 * by the text metrics. The proper behavior is to clip the glyph metrics to
6989 * fit within the maximums specified in the text metrics. */
6990 if(incoming_font->potm || get_outline_text_metrics(incoming_font) ||
6991 get_bitmap_text_metrics(incoming_font)) {
6992 TEXTMETRICW *ptm = &incoming_font->potm->otmTextMetrics;
6993 top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
6994 bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
6995 metrics.horiBearingY = top;
6996 metrics.height = top - bottom;
6998 /* TODO: Are we supposed to clip the width as well...? */
6999 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
7002 if(!needsTransform) {
7003 left = (INT)(metrics.horiBearingX) & -64;
7004 right = (INT)((metrics.horiBearingX + metrics.width) + 63) & -64;
7005 top = (metrics.horiBearingY + 63) & -64;
7006 bottom = (metrics.horiBearingY - metrics.height) & -64;
7007 adv = get_advance_metric(incoming_font, font, &metrics, NULL, vertical_metrics);
7008 gm.gmCellIncX = adv.x >> 6;
7009 gm.gmCellIncY = 0;
7010 origin_x = left;
7011 origin_y = top;
7012 abc->abcA = origin_x >> 6;
7013 abc->abcB = metrics.width >> 6;
7014 } else {
7015 INT xc, yc;
7016 FT_Vector vec;
7017 FT_Pos lsb;
7019 left = right = 0;
7021 for(xc = 0; xc < 2; xc++) {
7022 for(yc = 0; yc < 2; yc++) {
7023 vec.x = metrics.horiBearingX + xc * metrics.width;
7024 vec.y = metrics.horiBearingY - yc * metrics.height;
7025 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
7026 pFT_Vector_Transform(&vec, &transMatTategaki);
7027 if(xc == 0 && yc == 0) {
7028 left = right = vec.x;
7029 top = bottom = vec.y;
7030 } else {
7031 if(vec.x < left) left = vec.x;
7032 else if(vec.x > right) right = vec.x;
7033 if(vec.y < bottom) bottom = vec.y;
7034 else if(vec.y > top) top = vec.y;
7038 left = left & -64;
7039 right = (right + 63) & -64;
7040 bottom = bottom & -64;
7041 top = (top + 63) & -64;
7043 if (tategaki && (font->potm || get_outline_text_metrics(font)))
7045 if (vertical_metrics)
7046 lsb = metrics.horiBearingY + metrics.vertBearingY;
7047 else
7048 lsb = metrics.vertAdvance + (font->potm->otmDescent << 6);
7049 vec.x = lsb;
7050 vec.y = font->potm->otmDescent << 6;
7051 TRACE ("Vec %ld,%ld\n", vec.x>>6, vec.y>>6);
7052 pFT_Vector_Transform(&vec, &transMat);
7053 origin_x = (vec.x + left) & -64;
7054 origin_y = (vec.y + top + 63) & -64;
7056 else
7058 origin_x = left;
7059 origin_y = top;
7060 lsb = metrics.horiBearingX;
7063 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
7064 adv = get_advance_metric(incoming_font, font, &metrics, &transMat, vertical_metrics);
7065 gm.gmCellIncX = adv.x >> 6;
7066 gm.gmCellIncY = adv.y >> 6;
7068 adv = get_advance_metric(incoming_font, font, &metrics, &transMatUnrotated, vertical_metrics);
7070 vec.x = lsb;
7071 vec.y = 0;
7072 pFT_Vector_Transform(&vec, &transMatUnrotated);
7073 abc->abcA = vec.x >> 6;
7075 vec.x = metrics.width;
7076 vec.y = 0;
7077 pFT_Vector_Transform(&vec, &transMatUnrotated);
7078 if (vec.x >= 0)
7079 abc->abcB = vec.x >> 6;
7080 else
7081 abc->abcB = -vec.x >> 6;
7084 width = (right - left) >> 6;
7085 height = (top - bottom) >> 6;
7086 gm.gmBlackBoxX = width ? width : 1;
7087 gm.gmBlackBoxY = height ? height : 1;
7088 gm.gmptGlyphOrigin.x = origin_x >> 6;
7089 gm.gmptGlyphOrigin.y = origin_y >> 6;
7090 if (!abc->abcB) abc->abcB = 1;
7091 abc->abcC = (adv.x >> 6) - abc->abcA - abc->abcB;
7093 TRACE("%u,%u,%s,%d,%d\n", gm.gmBlackBoxX, gm.gmBlackBoxY,
7094 wine_dbgstr_point(&gm.gmptGlyphOrigin),
7095 gm.gmCellIncX, gm.gmCellIncY);
7097 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
7098 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
7100 FONT_GM(font,original_index)->gm = gm;
7101 FONT_GM(font,original_index)->abc = *abc;
7102 FONT_GM(font,original_index)->init = TRUE;
7105 if(format == GGO_METRICS)
7107 *lpgm = gm;
7108 return 1; /* FIXME */
7111 if(ft_face->glyph->format != ft_glyph_format_outline &&
7112 (format == GGO_NATIVE || format == GGO_BEZIER))
7114 TRACE("loaded a bitmap\n");
7115 return GDI_ERROR;
7118 switch(format) {
7119 case GGO_BITMAP:
7120 pitch = ((width + 31) >> 5) << 2;
7121 needed = pitch * height;
7123 if(!buf || !buflen) break;
7124 if (!needed) return GDI_ERROR; /* empty glyph */
7125 if (needed > buflen)
7126 return GDI_ERROR;
7128 switch(ft_face->glyph->format) {
7129 case ft_glyph_format_bitmap:
7131 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
7132 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
7133 INT h = min( height, ft_face->glyph->bitmap.rows );
7134 while(h--) {
7135 if (!font->fake_bold)
7136 memcpy(dst, src, w);
7137 else {
7138 INT x;
7139 dst[0] = 0;
7140 for (x = 0; x < w; x++) {
7141 dst[x ] = (dst[x] & 0x80) | (src[x] >> 1) | src[x];
7142 if (x+1 < pitch)
7143 dst[x+1] = (src[x] & 0x01) << 7;
7146 src += ft_face->glyph->bitmap.pitch;
7147 dst += pitch;
7149 break;
7152 case ft_glyph_format_outline:
7153 ft_bitmap.width = width;
7154 ft_bitmap.rows = height;
7155 ft_bitmap.pitch = pitch;
7156 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
7157 ft_bitmap.buffer = buf;
7159 if(needsTransform)
7160 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
7162 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
7164 /* Note: FreeType will only set 'black' bits for us. */
7165 memset(buf, 0, needed);
7166 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
7167 break;
7169 default:
7170 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
7171 return GDI_ERROR;
7173 break;
7175 case GGO_GRAY2_BITMAP:
7176 case GGO_GRAY4_BITMAP:
7177 case GGO_GRAY8_BITMAP:
7178 case WINE_GGO_GRAY16_BITMAP:
7180 unsigned int max_level, row, col;
7181 BYTE *start, *ptr;
7183 pitch = (width + 3) / 4 * 4;
7184 needed = pitch * height;
7186 if(!buf || !buflen) break;
7187 if (!needed) return GDI_ERROR; /* empty glyph */
7188 if (needed > buflen)
7189 return GDI_ERROR;
7191 max_level = get_max_level( format );
7193 switch(ft_face->glyph->format) {
7194 case ft_glyph_format_bitmap:
7196 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
7197 INT h = min( height, ft_face->glyph->bitmap.rows );
7198 INT x;
7199 memset( buf, 0, needed );
7200 while(h--) {
7201 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++) {
7202 if (src[x / 8] & masks[x % 8]) {
7203 dst[x] = max_level;
7204 if (font->fake_bold && x+1 < pitch) dst[x+1] = max_level;
7207 src += ft_face->glyph->bitmap.pitch;
7208 dst += pitch;
7210 break;
7212 case ft_glyph_format_outline:
7214 ft_bitmap.width = width;
7215 ft_bitmap.rows = height;
7216 ft_bitmap.pitch = pitch;
7217 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
7218 ft_bitmap.buffer = buf;
7220 if(needsTransform)
7221 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
7223 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
7225 memset(ft_bitmap.buffer, 0, buflen);
7227 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
7229 if (max_level != 255)
7231 for (row = 0, start = buf; row < height; row++)
7233 for (col = 0, ptr = start; col < width; col++, ptr++)
7234 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
7235 start += pitch;
7238 break;
7241 default:
7242 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
7243 return GDI_ERROR;
7245 break;
7248 case WINE_GGO_HRGB_BITMAP:
7249 case WINE_GGO_HBGR_BITMAP:
7250 case WINE_GGO_VRGB_BITMAP:
7251 case WINE_GGO_VBGR_BITMAP:
7252 #ifdef FT_LCD_FILTER_H
7254 switch (ft_face->glyph->format)
7256 case FT_GLYPH_FORMAT_BITMAP:
7258 BYTE *src, *dst;
7259 INT src_pitch, x;
7261 pitch = width * 4;
7262 needed = pitch * height;
7264 if (!buf || !buflen) break;
7265 if (!needed) return GDI_ERROR; /* empty glyph */
7266 if (needed > buflen)
7267 return GDI_ERROR;
7269 memset(buf, 0, buflen);
7270 dst = buf;
7271 src = ft_face->glyph->bitmap.buffer;
7272 src_pitch = ft_face->glyph->bitmap.pitch;
7274 height = min( height, ft_face->glyph->bitmap.rows );
7275 while ( height-- )
7277 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
7279 if ( src[x / 8] & masks[x % 8] )
7281 ((unsigned int *)dst)[x] = ~0u;
7282 if (font->fake_bold && x+1 < width) ((unsigned int *)dst)[x+1] = ~0u;
7285 src += src_pitch;
7286 dst += pitch;
7289 break;
7292 case FT_GLYPH_FORMAT_OUTLINE:
7294 unsigned int *dst;
7295 BYTE *src;
7296 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
7297 INT x_shift, y_shift;
7298 BOOL rgb;
7299 FT_Render_Mode render_mode =
7300 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
7301 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
7303 if (!width || !height)
7305 if (!buf || !buflen) break;
7306 return GDI_ERROR;
7309 if ( render_mode == FT_RENDER_MODE_LCD)
7311 gm.gmBlackBoxX += 2;
7312 gm.gmptGlyphOrigin.x -= 1;
7313 left -= (1 << 6);
7315 else
7317 gm.gmBlackBoxY += 2;
7318 gm.gmptGlyphOrigin.y += 1;
7319 top += (1 << 6);
7322 width = gm.gmBlackBoxX;
7323 height = gm.gmBlackBoxY;
7324 pitch = width * 4;
7325 needed = pitch * height;
7327 if (!buf || !buflen) break;
7328 if (needed > buflen)
7329 return GDI_ERROR;
7331 memset(buf, 0, buflen);
7332 dst = buf;
7333 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
7335 if ( needsTransform )
7336 pFT_Outline_Transform (&ft_face->glyph->outline, &transMatTategaki);
7338 if ( pFT_Library_SetLcdFilter )
7339 pFT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT );
7340 pFT_Render_Glyph (ft_face->glyph, render_mode);
7342 src = ft_face->glyph->bitmap.buffer;
7343 src_pitch = ft_face->glyph->bitmap.pitch;
7344 src_width = ft_face->glyph->bitmap.width;
7345 src_height = ft_face->glyph->bitmap.rows;
7347 if ( render_mode == FT_RENDER_MODE_LCD)
7349 rgb_interval = 1;
7350 hmul = 3;
7351 vmul = 1;
7353 else
7355 rgb_interval = src_pitch;
7356 hmul = 1;
7357 vmul = 3;
7360 x_shift = ft_face->glyph->bitmap_left - (left >> 6);
7361 if ( x_shift < 0 )
7363 src += hmul * -x_shift;
7364 src_width -= hmul * -x_shift;
7366 else if ( x_shift > 0 )
7368 dst += x_shift;
7369 width -= x_shift;
7372 y_shift = (top >> 6) - ft_face->glyph->bitmap_top;
7373 if ( y_shift < 0 )
7375 src += src_pitch * vmul * -y_shift;
7376 src_height -= vmul * -y_shift;
7378 else if ( y_shift > 0 )
7380 dst += y_shift * ( pitch / sizeof(*dst) );
7381 height -= y_shift;
7384 width = min( width, src_width / hmul );
7385 height = min( height, src_height / vmul );
7387 while ( height-- )
7389 for ( x = 0; x < width; x++ )
7391 if ( rgb )
7393 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
7394 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
7395 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
7396 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
7398 else
7400 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
7401 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
7402 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
7403 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
7406 src += src_pitch * vmul;
7407 dst += pitch / sizeof(*dst);
7410 break;
7413 default:
7414 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
7415 return GDI_ERROR;
7418 break;
7420 #else
7421 return GDI_ERROR;
7422 #endif
7424 case GGO_NATIVE:
7426 FT_Outline *outline = &ft_face->glyph->outline;
7428 if(buflen == 0) buf = NULL;
7430 if (needsTransform && buf)
7431 pFT_Outline_Transform(outline, &transMatTategaki);
7433 needed = get_native_glyph_outline(outline, buflen, NULL);
7435 if (!buf || !buflen)
7436 break;
7437 if (needed > buflen)
7438 return GDI_ERROR;
7440 get_native_glyph_outline(outline, buflen, buf);
7441 break;
7443 case GGO_BEZIER:
7445 FT_Outline *outline = &ft_face->glyph->outline;
7446 if(buflen == 0) buf = NULL;
7448 if (needsTransform && buf)
7449 pFT_Outline_Transform(outline, &transMat);
7451 needed = get_bezier_glyph_outline(outline, buflen, NULL);
7453 if (!buf || !buflen)
7454 break;
7455 if (needed > buflen)
7456 return GDI_ERROR;
7458 get_bezier_glyph_outline(outline, buflen, buf);
7459 break;
7462 default:
7463 FIXME("Unsupported format %d\n", format);
7464 return GDI_ERROR;
7466 *lpgm = gm;
7467 return needed;
7470 static BOOL get_bitmap_text_metrics(GdiFont *font)
7472 FT_Face ft_face = font->ft_face;
7473 FT_WinFNT_HeaderRec winfnt_header;
7474 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
7475 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
7476 font->potm->otmSize = size;
7478 #define TM font->potm->otmTextMetrics
7479 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
7481 TM.tmHeight = winfnt_header.pixel_height;
7482 TM.tmAscent = winfnt_header.ascent;
7483 TM.tmDescent = TM.tmHeight - TM.tmAscent;
7484 TM.tmInternalLeading = winfnt_header.internal_leading;
7485 TM.tmExternalLeading = winfnt_header.external_leading;
7486 TM.tmAveCharWidth = winfnt_header.avg_width;
7487 TM.tmMaxCharWidth = winfnt_header.max_width;
7488 TM.tmWeight = winfnt_header.weight;
7489 TM.tmOverhang = 0;
7490 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
7491 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
7492 TM.tmFirstChar = winfnt_header.first_char;
7493 TM.tmLastChar = winfnt_header.last_char;
7494 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
7495 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
7496 TM.tmItalic = winfnt_header.italic;
7497 TM.tmUnderlined = font->underline;
7498 TM.tmStruckOut = font->strikeout;
7499 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
7500 TM.tmCharSet = winfnt_header.charset;
7502 else
7504 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
7505 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
7506 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7507 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
7508 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
7509 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
7510 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
7511 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
7512 TM.tmOverhang = 0;
7513 TM.tmDigitizedAspectX = 96; /* FIXME */
7514 TM.tmDigitizedAspectY = 96; /* FIXME */
7515 TM.tmFirstChar = 1;
7516 TM.tmLastChar = 255;
7517 TM.tmDefaultChar = 32;
7518 TM.tmBreakChar = 32;
7519 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
7520 TM.tmUnderlined = font->underline;
7521 TM.tmStruckOut = font->strikeout;
7522 /* NB inverted meaning of TMPF_FIXED_PITCH */
7523 TM.tmPitchAndFamily = FT_IS_FIXED_WIDTH(ft_face) ? 0 : TMPF_FIXED_PITCH;
7524 TM.tmCharSet = font->charset;
7526 #undef TM
7528 return TRUE;
7532 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
7534 double scale_x, scale_y;
7536 if (font->aveWidth)
7538 scale_x = (double)font->aveWidth;
7539 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7541 else
7542 scale_x = font->scale_y;
7544 scale_x *= fabs(font->font_desc.matrix.eM11);
7545 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7547 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7548 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7550 SCALE_Y(ptm->tmHeight);
7551 SCALE_Y(ptm->tmAscent);
7552 SCALE_Y(ptm->tmDescent);
7553 SCALE_Y(ptm->tmInternalLeading);
7554 SCALE_Y(ptm->tmExternalLeading);
7555 SCALE_Y(ptm->tmOverhang);
7557 SCALE_X(ptm->tmAveCharWidth);
7558 SCALE_X(ptm->tmMaxCharWidth);
7560 #undef SCALE_X
7561 #undef SCALE_Y
7564 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
7566 double scale_x, scale_y;
7568 if (font->aveWidth)
7570 scale_x = (double)font->aveWidth;
7571 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7573 else
7574 scale_x = font->scale_y;
7576 scale_x *= fabs(font->font_desc.matrix.eM11);
7577 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7579 scale_font_metrics(font, &potm->otmTextMetrics);
7581 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7582 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7584 SCALE_Y(potm->otmAscent);
7585 SCALE_Y(potm->otmDescent);
7586 SCALE_Y(potm->otmLineGap);
7587 SCALE_Y(potm->otmsCapEmHeight);
7588 SCALE_Y(potm->otmsXHeight);
7589 SCALE_Y(potm->otmrcFontBox.top);
7590 SCALE_Y(potm->otmrcFontBox.bottom);
7591 SCALE_X(potm->otmrcFontBox.left);
7592 SCALE_X(potm->otmrcFontBox.right);
7593 SCALE_Y(potm->otmMacAscent);
7594 SCALE_Y(potm->otmMacDescent);
7595 SCALE_Y(potm->otmMacLineGap);
7596 SCALE_X(potm->otmptSubscriptSize.x);
7597 SCALE_Y(potm->otmptSubscriptSize.y);
7598 SCALE_X(potm->otmptSubscriptOffset.x);
7599 SCALE_Y(potm->otmptSubscriptOffset.y);
7600 SCALE_X(potm->otmptSuperscriptSize.x);
7601 SCALE_Y(potm->otmptSuperscriptSize.y);
7602 SCALE_X(potm->otmptSuperscriptOffset.x);
7603 SCALE_Y(potm->otmptSuperscriptOffset.y);
7604 SCALE_Y(potm->otmsStrikeoutSize);
7605 SCALE_Y(potm->otmsStrikeoutPosition);
7606 SCALE_Y(potm->otmsUnderscoreSize);
7607 SCALE_Y(potm->otmsUnderscorePosition);
7609 #undef SCALE_X
7610 #undef SCALE_Y
7613 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
7615 if(!font->potm)
7617 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
7619 /* Make sure that the font has sane width/height ratio */
7620 if (font->aveWidth)
7622 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
7624 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
7625 font->aveWidth = 0;
7629 *ptm = font->potm->otmTextMetrics;
7630 scale_font_metrics(font, ptm);
7631 return TRUE;
7634 static BOOL face_has_symbol_charmap(FT_Face ft_face)
7636 int i;
7638 for(i = 0; i < ft_face->num_charmaps; i++)
7640 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
7641 return TRUE;
7643 return FALSE;
7646 static BOOL get_outline_text_metrics(GdiFont *font)
7648 BOOL ret = FALSE;
7649 FT_Face ft_face = font->ft_face;
7650 UINT needed, lenfam, lensty, lenface, lenfull;
7651 TT_OS2 *pOS2;
7652 TT_HoriHeader *pHori;
7653 TT_Postscript *pPost;
7654 FT_Fixed em_scale;
7655 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
7656 char *cp;
7657 INT ascent, descent;
7658 USHORT windescent;
7660 TRACE("font=%p\n", font);
7662 if(!FT_IS_SCALABLE(ft_face))
7663 return FALSE;
7665 needed = sizeof(*font->potm);
7667 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
7668 family_nameW = strdupW(font->name);
7670 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
7671 if (!style_nameW)
7673 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
7674 style_nameW = towstr( CP_ACP, ft_face->style_name );
7676 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
7678 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
7679 if (!face_nameW)
7681 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
7682 face_nameW = strdupW(font->name);
7684 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
7685 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
7687 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
7688 if (!full_nameW)
7690 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
7691 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
7692 full_nameW = strdupW(fake_nameW);
7694 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
7696 /* These names should be read from the TT name table */
7698 /* length of otmpFamilyName */
7699 needed += lenfam;
7701 /* length of otmpFaceName */
7702 needed += lenface;
7704 /* length of otmpStyleName */
7705 needed += lensty;
7707 /* length of otmpFullName */
7708 needed += lenfull;
7711 em_scale = (FT_Fixed)MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
7713 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
7714 if(!pOS2) {
7715 FIXME("Can't find OS/2 table - not TT font?\n");
7716 goto end;
7719 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
7720 if(!pHori) {
7721 FIXME("Can't find HHEA table - not TT font?\n");
7722 goto end;
7725 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
7727 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",
7728 pOS2->usWinAscent, pOS2->usWinDescent,
7729 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
7730 pOS2->xAvgCharWidth,
7731 ft_face->ascender, ft_face->descender, ft_face->height,
7732 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
7733 ft_face->bbox.yMax, ft_face->bbox.yMin);
7735 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
7736 font->potm->otmSize = needed;
7738 #define TM font->potm->otmTextMetrics
7740 windescent = get_fixed_windescent(pOS2->usWinDescent);
7741 if(pOS2->usWinAscent + windescent == 0) {
7742 ascent = pHori->Ascender;
7743 descent = -pHori->Descender;
7744 } else {
7745 ascent = pOS2->usWinAscent;
7746 descent = windescent;
7749 font->ntmCellHeight = ascent + descent;
7750 font->ntmAvgWidth = pOS2->xAvgCharWidth;
7752 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7753 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7755 if(font->yMax) {
7756 TM.tmAscent = font->yMax;
7757 TM.tmDescent = -font->yMin;
7758 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
7759 } else {
7760 TM.tmAscent = SCALE_Y(ascent);
7761 TM.tmDescent = SCALE_Y(descent);
7762 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
7765 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7767 /* MSDN says:
7768 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7770 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
7771 ((ascent + descent) -
7772 (pHori->Ascender - pHori->Descender))));
7774 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
7775 if (TM.tmAveCharWidth == 0) {
7776 TM.tmAveCharWidth = 1;
7778 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
7779 TM.tmWeight = FW_REGULAR;
7780 if (font->fake_bold) {
7781 TM.tmAveCharWidth++;
7782 TM.tmMaxCharWidth++;
7783 TM.tmWeight = FW_BOLD;
7785 else
7787 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
7789 if (pOS2->usWeightClass > FW_MEDIUM)
7790 TM.tmWeight = pOS2->usWeightClass;
7792 else if (pOS2->usWeightClass <= FW_MEDIUM)
7793 TM.tmWeight = pOS2->usWeightClass;
7795 TM.tmOverhang = 0;
7796 TM.tmDigitizedAspectX = 96; /* FIXME */
7797 TM.tmDigitizedAspectY = 96; /* FIXME */
7798 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7799 * symbol range to 0 - f0ff
7802 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
7804 TM.tmFirstChar = 0;
7805 switch(GetACP())
7807 case 1255: /* Hebrew */
7808 TM.tmLastChar = 0xf896;
7809 break;
7810 case 1257: /* Baltic */
7811 TM.tmLastChar = 0xf8fd;
7812 break;
7813 default:
7814 TM.tmLastChar = 0xf0ff;
7816 TM.tmBreakChar = 0x20;
7817 TM.tmDefaultChar = 0x1f;
7819 else
7821 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
7822 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
7824 if(pOS2->usFirstCharIndex <= 1)
7825 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
7826 else if (pOS2->usFirstCharIndex > 0xff)
7827 TM.tmBreakChar = 0x20;
7828 else
7829 TM.tmBreakChar = pOS2->usFirstCharIndex;
7830 TM.tmDefaultChar = TM.tmBreakChar - 1;
7832 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
7833 TM.tmUnderlined = font->underline;
7834 TM.tmStruckOut = font->strikeout;
7836 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7837 if(!FT_IS_FIXED_WIDTH(ft_face) &&
7838 (pOS2->version == 0xFFFFU ||
7839 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
7840 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
7841 else
7842 TM.tmPitchAndFamily = 0;
7844 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
7846 case PAN_FAMILY_SCRIPT:
7847 TM.tmPitchAndFamily |= FF_SCRIPT;
7848 break;
7850 case PAN_FAMILY_DECORATIVE:
7851 TM.tmPitchAndFamily |= FF_DECORATIVE;
7852 break;
7854 case PAN_ANY:
7855 case PAN_NO_FIT:
7856 case PAN_FAMILY_TEXT_DISPLAY:
7857 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
7858 /* which is clearly not what the panose spec says. */
7859 default:
7860 if(TM.tmPitchAndFamily == 0 || /* fixed */
7861 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
7862 TM.tmPitchAndFamily = FF_MODERN;
7863 else
7865 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
7867 case PAN_ANY:
7868 case PAN_NO_FIT:
7869 default:
7870 TM.tmPitchAndFamily |= FF_DONTCARE;
7871 break;
7873 case PAN_SERIF_COVE:
7874 case PAN_SERIF_OBTUSE_COVE:
7875 case PAN_SERIF_SQUARE_COVE:
7876 case PAN_SERIF_OBTUSE_SQUARE_COVE:
7877 case PAN_SERIF_SQUARE:
7878 case PAN_SERIF_THIN:
7879 case PAN_SERIF_BONE:
7880 case PAN_SERIF_EXAGGERATED:
7881 case PAN_SERIF_TRIANGLE:
7882 TM.tmPitchAndFamily |= FF_ROMAN;
7883 break;
7885 case PAN_SERIF_NORMAL_SANS:
7886 case PAN_SERIF_OBTUSE_SANS:
7887 case PAN_SERIF_PERP_SANS:
7888 case PAN_SERIF_FLARED:
7889 case PAN_SERIF_ROUNDED:
7890 TM.tmPitchAndFamily |= FF_SWISS;
7891 break;
7894 break;
7897 if(FT_IS_SCALABLE(ft_face))
7898 TM.tmPitchAndFamily |= TMPF_VECTOR;
7900 if(FT_IS_SFNT(ft_face))
7902 if (font->ntmFlags & NTM_PS_OPENTYPE)
7903 TM.tmPitchAndFamily |= TMPF_DEVICE;
7904 else
7905 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
7908 TM.tmCharSet = font->charset;
7910 font->potm->otmFiller = 0;
7911 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
7912 font->potm->otmfsSelection = pOS2->fsSelection;
7913 if (font->fake_italic)
7914 font->potm->otmfsSelection |= 1;
7915 if (font->fake_bold)
7916 font->potm->otmfsSelection |= 1 << 5;
7917 font->potm->otmfsType = pOS2->fsType;
7918 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
7919 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
7920 font->potm->otmItalicAngle = 0; /* POST table */
7921 font->potm->otmEMSquare = ft_face->units_per_EM;
7922 font->potm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
7923 font->potm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
7924 font->potm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
7925 font->potm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
7926 font->potm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
7927 font->potm->otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
7928 font->potm->otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
7929 font->potm->otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
7930 font->potm->otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
7931 font->potm->otmMacAscent = TM.tmAscent;
7932 font->potm->otmMacDescent = -TM.tmDescent;
7933 font->potm->otmMacLineGap = font->potm->otmLineGap;
7934 font->potm->otmusMinimumPPEM = 0; /* TT Header */
7935 font->potm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
7936 font->potm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
7937 font->potm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
7938 font->potm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
7939 font->potm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
7940 font->potm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
7941 font->potm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
7942 font->potm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
7943 font->potm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
7944 font->potm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
7945 if(!pPost) {
7946 font->potm->otmsUnderscoreSize = 0;
7947 font->potm->otmsUnderscorePosition = 0;
7948 } else {
7949 font->potm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
7950 font->potm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
7952 #undef SCALE_X
7953 #undef SCALE_Y
7954 #undef TM
7956 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7957 cp = (char*)font->potm + sizeof(*font->potm);
7958 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
7959 strcpyW((WCHAR*)cp, family_nameW);
7960 cp += lenfam;
7961 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
7962 strcpyW((WCHAR*)cp, style_nameW);
7963 cp += lensty;
7964 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7965 strcpyW((WCHAR*)cp, face_nameW);
7966 cp += lenface;
7967 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
7968 strcpyW((WCHAR*)cp, full_nameW);
7969 ret = TRUE;
7971 end:
7972 HeapFree(GetProcessHeap(), 0, style_nameW);
7973 HeapFree(GetProcessHeap(), 0, family_nameW);
7974 HeapFree(GetProcessHeap(), 0, face_nameW);
7975 HeapFree(GetProcessHeap(), 0, full_nameW);
7976 return ret;
7979 /*************************************************************
7980 * freetype_GetGlyphOutline
7982 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
7983 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7985 struct freetype_physdev *physdev = get_freetype_dev( dev );
7986 DWORD ret;
7987 ABC abc;
7989 if (!physdev->font)
7991 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
7992 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
7995 GDI_CheckNotLock();
7996 EnterCriticalSection( &freetype_cs );
7997 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
7998 LeaveCriticalSection( &freetype_cs );
7999 return ret;
8002 /*************************************************************
8003 * freetype_GetTextMetrics
8005 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
8007 struct freetype_physdev *physdev = get_freetype_dev( dev );
8008 BOOL ret;
8010 if (!physdev->font)
8012 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
8013 return dev->funcs->pGetTextMetrics( dev, metrics );
8016 GDI_CheckNotLock();
8017 EnterCriticalSection( &freetype_cs );
8018 ret = get_text_metrics( physdev->font, metrics );
8019 LeaveCriticalSection( &freetype_cs );
8020 return ret;
8023 /*************************************************************
8024 * freetype_GetOutlineTextMetrics
8026 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
8028 struct freetype_physdev *physdev = get_freetype_dev( dev );
8029 UINT ret = 0;
8031 if (!physdev->font)
8033 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
8034 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
8037 TRACE("font=%p\n", physdev->font);
8039 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
8041 GDI_CheckNotLock();
8042 EnterCriticalSection( &freetype_cs );
8044 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
8046 if(potm && cbSize >= physdev->font->potm->otmSize)
8048 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
8049 scale_outline_font_metrics(physdev->font, potm);
8051 ret = physdev->font->potm->otmSize;
8053 LeaveCriticalSection( &freetype_cs );
8054 return ret;
8057 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
8059 child->font = alloc_font();
8060 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
8061 if(!child->font->ft_face)
8063 free_font(child->font);
8064 child->font = NULL;
8065 return FALSE;
8068 child->font->font_desc = font->font_desc;
8069 child->font->ntmFlags = child->face->ntmFlags;
8070 child->font->orientation = font->orientation;
8071 child->font->scale_y = font->scale_y;
8072 child->font->name = strdupW(child->face->family->FamilyName);
8073 child->font->base_font = font;
8074 TRACE("created child font %p for base %p\n", child->font, font);
8075 return TRUE;
8078 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL* vert)
8080 FT_UInt g,o;
8081 CHILD_FONT *child_font;
8083 if(font->base_font)
8084 font = font->base_font;
8086 *linked_font = font;
8088 if((*glyph = get_glyph_index(font, c)))
8090 o = *glyph;
8091 *glyph = get_GSUB_vert_glyph(font, *glyph);
8092 *vert = (o != *glyph);
8093 return TRUE;
8096 if (c < 32) goto done; /* don't check linked fonts for control characters */
8098 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
8100 if(!child_font->font)
8101 if(!load_child_font(font, child_font))
8102 continue;
8104 if(!child_font->font->ft_face)
8105 continue;
8106 g = get_glyph_index(child_font->font, c);
8107 o = g;
8108 g = get_GSUB_vert_glyph(child_font->font, g);
8109 if(g)
8111 *glyph = g;
8112 *linked_font = child_font->font;
8113 *vert = (o != g);
8114 return TRUE;
8118 done:
8119 *vert = FALSE;
8120 return FALSE;
8123 /*************************************************************
8124 * freetype_GetCharWidth
8126 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
8128 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8129 UINT c;
8130 GLYPHMETRICS gm;
8131 ABC abc;
8132 struct freetype_physdev *physdev = get_freetype_dev( dev );
8134 if (!physdev->font)
8136 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
8137 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
8140 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
8142 GDI_CheckNotLock();
8143 EnterCriticalSection( &freetype_cs );
8144 for(c = firstChar; c <= lastChar; c++) {
8145 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
8146 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
8148 LeaveCriticalSection( &freetype_cs );
8149 return TRUE;
8152 /*************************************************************
8153 * freetype_GetCharABCWidths
8155 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
8157 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8158 UINT c;
8159 GLYPHMETRICS gm;
8160 struct freetype_physdev *physdev = get_freetype_dev( dev );
8162 if (!physdev->font)
8164 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
8165 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
8168 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
8170 GDI_CheckNotLock();
8171 EnterCriticalSection( &freetype_cs );
8173 for(c = firstChar; c <= lastChar; c++, buffer++)
8174 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
8176 LeaveCriticalSection( &freetype_cs );
8177 return TRUE;
8180 /*************************************************************
8181 * freetype_GetCharABCWidthsI
8183 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
8185 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8186 UINT c;
8187 GLYPHMETRICS gm;
8188 struct freetype_physdev *physdev = get_freetype_dev( dev );
8190 if (!physdev->font)
8192 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
8193 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
8196 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
8197 return FALSE;
8199 GDI_CheckNotLock();
8200 EnterCriticalSection( &freetype_cs );
8202 for(c = 0; c < count; c++, buffer++)
8203 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
8204 &gm, buffer, 0, NULL, &identity );
8206 LeaveCriticalSection( &freetype_cs );
8207 return TRUE;
8210 /*************************************************************
8211 * freetype_GetTextExtentExPoint
8213 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
8215 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8216 INT idx, pos;
8217 ABC abc;
8218 GLYPHMETRICS gm;
8219 struct freetype_physdev *physdev = get_freetype_dev( dev );
8221 if (!physdev->font)
8223 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
8224 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
8227 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
8229 GDI_CheckNotLock();
8230 EnterCriticalSection( &freetype_cs );
8232 for (idx = pos = 0; idx < count; idx++)
8234 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
8235 pos += abc.abcA + abc.abcB + abc.abcC;
8236 dxs[idx] = pos;
8239 LeaveCriticalSection( &freetype_cs );
8240 return TRUE;
8243 /*************************************************************
8244 * freetype_GetTextExtentExPointI
8246 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
8248 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8249 INT idx, pos;
8250 ABC abc;
8251 GLYPHMETRICS gm;
8252 struct freetype_physdev *physdev = get_freetype_dev( dev );
8254 if (!physdev->font)
8256 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
8257 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
8260 TRACE("%p, %p, %d\n", physdev->font, indices, count);
8262 GDI_CheckNotLock();
8263 EnterCriticalSection( &freetype_cs );
8265 for (idx = pos = 0; idx < count; idx++)
8267 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
8268 &gm, &abc, 0, NULL, &identity );
8269 pos += abc.abcA + abc.abcB + abc.abcC;
8270 dxs[idx] = pos;
8273 LeaveCriticalSection( &freetype_cs );
8274 return TRUE;
8277 /*************************************************************
8278 * freetype_GetFontData
8280 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
8282 struct freetype_physdev *physdev = get_freetype_dev( dev );
8284 if (!physdev->font)
8286 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
8287 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
8290 TRACE("font=%p, table=%s, offset=0x%x, buf=%p, cbData=0x%x\n",
8291 physdev->font, debugstr_an((char*)&table, 4), offset, buf, cbData);
8293 return get_font_data( physdev->font, table, offset, buf, cbData );
8296 /*************************************************************
8297 * freetype_GetTextFace
8299 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
8301 INT n;
8302 struct freetype_physdev *physdev = get_freetype_dev( dev );
8304 if (!physdev->font)
8306 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
8307 return dev->funcs->pGetTextFace( dev, count, str );
8310 n = strlenW(physdev->font->name) + 1;
8311 if (str)
8313 lstrcpynW(str, physdev->font->name, count);
8314 n = min(count, n);
8316 return n;
8319 /*************************************************************
8320 * freetype_GetTextCharsetInfo
8322 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
8324 struct freetype_physdev *physdev = get_freetype_dev( dev );
8326 if (!physdev->font)
8328 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
8329 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
8331 if (fs) *fs = physdev->font->fs;
8332 return physdev->font->charset;
8335 /* Retrieve a list of supported Unicode ranges for a given font.
8336 * Can be called with NULL gs to calculate the buffer size. Returns
8337 * the number of ranges found.
8339 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
8341 DWORD num_ranges = 0;
8343 if (face->charmap->encoding == FT_ENCODING_UNICODE)
8345 FT_UInt glyph_code;
8346 FT_ULong char_code, char_code_prev;
8348 glyph_code = 0;
8349 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
8351 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
8352 face->num_glyphs, glyph_code, char_code);
8354 if (!glyph_code) return 0;
8356 if (gs)
8358 gs->ranges[0].wcLow = (USHORT)char_code;
8359 gs->ranges[0].cGlyphs = 0;
8360 gs->cGlyphsSupported = 0;
8363 num_ranges = 1;
8364 while (glyph_code)
8366 if (char_code < char_code_prev)
8368 ERR("expected increasing char code from FT_Get_Next_Char\n");
8369 return 0;
8371 if (char_code - char_code_prev > 1)
8373 num_ranges++;
8374 if (gs)
8376 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
8377 gs->ranges[num_ranges - 1].cGlyphs = 1;
8378 gs->cGlyphsSupported++;
8381 else if (gs)
8383 gs->ranges[num_ranges - 1].cGlyphs++;
8384 gs->cGlyphsSupported++;
8386 char_code_prev = char_code;
8387 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
8390 else
8391 FIXME("encoding %u not supported\n", face->charmap->encoding);
8393 return num_ranges;
8396 /*************************************************************
8397 * freetype_GetFontUnicodeRanges
8399 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
8401 struct freetype_physdev *physdev = get_freetype_dev( dev );
8402 DWORD size, num_ranges;
8404 if (!physdev->font)
8406 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
8407 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
8410 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
8411 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
8412 if (glyphset)
8414 glyphset->cbThis = size;
8415 glyphset->cRanges = num_ranges;
8416 glyphset->flAccel = 0;
8418 return size;
8421 /*************************************************************
8422 * freetype_FontIsLinked
8424 static BOOL freetype_FontIsLinked( PHYSDEV dev )
8426 struct freetype_physdev *physdev = get_freetype_dev( dev );
8427 BOOL ret;
8429 if (!physdev->font)
8431 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
8432 return dev->funcs->pFontIsLinked( dev );
8435 GDI_CheckNotLock();
8436 EnterCriticalSection( &freetype_cs );
8437 ret = !list_empty(&physdev->font->child_fonts);
8438 LeaveCriticalSection( &freetype_cs );
8439 return ret;
8442 /*************************************************************************
8443 * GetRasterizerCaps (GDI32.@)
8445 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8447 lprs->nSize = sizeof(RASTERIZER_STATUS);
8448 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
8449 lprs->nLanguageID = 0;
8450 return TRUE;
8453 /*************************************************************
8454 * freetype_GetFontRealizationInfo
8456 static BOOL freetype_GetFontRealizationInfo( PHYSDEV dev, void *ptr )
8458 struct freetype_physdev *physdev = get_freetype_dev( dev );
8459 struct font_realization_info *info = ptr;
8461 if (!physdev->font)
8463 dev = GET_NEXT_PHYSDEV( dev, pGetFontRealizationInfo );
8464 return dev->funcs->pGetFontRealizationInfo( dev, ptr );
8467 TRACE("(%p, %p)\n", physdev->font, info);
8469 info->flags = 1;
8470 if(FT_IS_SCALABLE(physdev->font->ft_face))
8471 info->flags |= 2;
8473 info->cache_num = physdev->font->cache_num;
8474 info->instance_id = physdev->font->instance_id;
8475 if (info->size == sizeof(*info))
8477 info->unk = 0;
8478 info->face_index = physdev->font->ft_face->face_index;
8479 info->simulations = 0;
8480 if (physdev->font->fake_bold)
8481 info->simulations |= 0x1;
8482 if (physdev->font->fake_italic)
8483 info->simulations |= 0x2;
8486 return TRUE;
8489 /*************************************************************************
8490 * GetFontFileInfo (GDI32.@)
8492 BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_fileinfo *info, DWORD size, DWORD *needed )
8494 struct font_handle_entry *entry = handle_entry( instance_id );
8495 const GdiFont *font;
8497 if (!entry)
8499 SetLastError(ERROR_INVALID_PARAMETER);
8500 return FALSE;
8503 font = entry->obj;
8504 *needed = sizeof(*info) + strlenW(font->fileinfo->path) * sizeof(WCHAR);
8505 if (*needed > size)
8507 SetLastError(ERROR_INSUFFICIENT_BUFFER);
8508 return FALSE;
8511 /* path is included too */
8512 memcpy(info, font->fileinfo, *needed);
8513 return TRUE;
8516 /*************************************************************************
8517 * Kerning support for TrueType fonts
8520 struct TT_kern_table
8522 USHORT version;
8523 USHORT nTables;
8526 struct TT_kern_subtable
8528 USHORT version;
8529 USHORT length;
8530 union
8532 USHORT word;
8533 struct
8535 USHORT horizontal : 1;
8536 USHORT minimum : 1;
8537 USHORT cross_stream: 1;
8538 USHORT override : 1;
8539 USHORT reserved1 : 4;
8540 USHORT format : 8;
8541 } bits;
8542 } coverage;
8545 struct TT_format0_kern_subtable
8547 USHORT nPairs;
8548 USHORT searchRange;
8549 USHORT entrySelector;
8550 USHORT rangeShift;
8553 struct TT_kern_pair
8555 USHORT left;
8556 USHORT right;
8557 short value;
8560 static DWORD parse_format0_kern_subtable(GdiFont *font,
8561 const struct TT_format0_kern_subtable *tt_f0_ks,
8562 const USHORT *glyph_to_char,
8563 KERNINGPAIR *kern_pair, DWORD cPairs)
8565 USHORT i, nPairs;
8566 const struct TT_kern_pair *tt_kern_pair;
8568 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
8570 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
8572 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8573 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
8574 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
8576 if (!kern_pair || !cPairs)
8577 return nPairs;
8579 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
8581 nPairs = min(nPairs, cPairs);
8583 for (i = 0; i < nPairs; i++)
8585 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
8586 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
8587 /* this algorithm appears to better match what Windows does */
8588 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
8589 if (kern_pair->iKernAmount < 0)
8591 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
8592 kern_pair->iKernAmount -= font->ppem;
8594 else if (kern_pair->iKernAmount > 0)
8596 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
8597 kern_pair->iKernAmount += font->ppem;
8599 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
8601 TRACE("left %u right %u value %d\n",
8602 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
8604 kern_pair++;
8606 TRACE("copied %u entries\n", nPairs);
8607 return nPairs;
8610 /*************************************************************
8611 * freetype_GetKerningPairs
8613 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
8615 DWORD length;
8616 void *buf;
8617 const struct TT_kern_table *tt_kern_table;
8618 const struct TT_kern_subtable *tt_kern_subtable;
8619 USHORT i, nTables;
8620 USHORT *glyph_to_char;
8621 GdiFont *font;
8622 struct freetype_physdev *physdev = get_freetype_dev( dev );
8624 if (!(font = physdev->font))
8626 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
8627 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
8630 GDI_CheckNotLock();
8631 EnterCriticalSection( &freetype_cs );
8632 if (font->total_kern_pairs != (DWORD)-1)
8634 if (cPairs && kern_pair)
8636 cPairs = min(cPairs, font->total_kern_pairs);
8637 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8639 else cPairs = font->total_kern_pairs;
8641 LeaveCriticalSection( &freetype_cs );
8642 return cPairs;
8645 font->total_kern_pairs = 0;
8647 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
8649 if (length == GDI_ERROR)
8651 TRACE("no kerning data in the font\n");
8652 LeaveCriticalSection( &freetype_cs );
8653 return 0;
8656 buf = HeapAlloc(GetProcessHeap(), 0, length);
8657 if (!buf)
8659 WARN("Out of memory\n");
8660 LeaveCriticalSection( &freetype_cs );
8661 return 0;
8664 get_font_data(font, MS_KERN_TAG, 0, buf, length);
8666 /* build a glyph index to char code map */
8667 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
8668 if (!glyph_to_char)
8670 WARN("Out of memory allocating a glyph index to char code map\n");
8671 HeapFree(GetProcessHeap(), 0, buf);
8672 LeaveCriticalSection( &freetype_cs );
8673 return 0;
8676 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
8678 FT_UInt glyph_code;
8679 FT_ULong char_code;
8681 glyph_code = 0;
8682 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
8684 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
8685 font->ft_face->num_glyphs, glyph_code, char_code);
8687 while (glyph_code)
8689 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
8691 /* FIXME: This doesn't match what Windows does: it does some fancy
8692 * things with duplicate glyph index to char code mappings, while
8693 * we just avoid overriding existing entries.
8695 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
8696 glyph_to_char[glyph_code] = (USHORT)char_code;
8698 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
8701 else
8703 ULONG n;
8705 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
8706 for (n = 0; n <= 65535; n++)
8707 glyph_to_char[n] = (USHORT)n;
8710 tt_kern_table = buf;
8711 nTables = GET_BE_WORD(tt_kern_table->nTables);
8712 TRACE("version %u, nTables %u\n",
8713 GET_BE_WORD(tt_kern_table->version), nTables);
8715 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
8717 for (i = 0; i < nTables; i++)
8719 struct TT_kern_subtable tt_kern_subtable_copy;
8721 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
8722 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
8723 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
8725 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8726 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
8727 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
8729 /* According to the TrueType specification this is the only format
8730 * that will be properly interpreted by Windows and OS/2
8732 if (tt_kern_subtable_copy.coverage.bits.format == 0)
8734 DWORD new_chunk, old_total = font->total_kern_pairs;
8736 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8737 glyph_to_char, NULL, 0);
8738 font->total_kern_pairs += new_chunk;
8740 if (!font->kern_pairs)
8741 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
8742 font->total_kern_pairs * sizeof(*font->kern_pairs));
8743 else
8744 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
8745 font->total_kern_pairs * sizeof(*font->kern_pairs));
8747 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8748 glyph_to_char, font->kern_pairs + old_total, new_chunk);
8750 else
8751 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
8753 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
8756 HeapFree(GetProcessHeap(), 0, glyph_to_char);
8757 HeapFree(GetProcessHeap(), 0, buf);
8759 if (cPairs && kern_pair)
8761 cPairs = min(cPairs, font->total_kern_pairs);
8762 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8764 else cPairs = font->total_kern_pairs;
8766 LeaveCriticalSection( &freetype_cs );
8767 return cPairs;
8770 static const struct gdi_dc_funcs freetype_funcs =
8772 NULL, /* pAbortDoc */
8773 NULL, /* pAbortPath */
8774 NULL, /* pAlphaBlend */
8775 NULL, /* pAngleArc */
8776 NULL, /* pArc */
8777 NULL, /* pArcTo */
8778 NULL, /* pBeginPath */
8779 NULL, /* pBlendImage */
8780 NULL, /* pChord */
8781 NULL, /* pCloseFigure */
8782 NULL, /* pCreateCompatibleDC */
8783 freetype_CreateDC, /* pCreateDC */
8784 freetype_DeleteDC, /* pDeleteDC */
8785 NULL, /* pDeleteObject */
8786 NULL, /* pDeviceCapabilities */
8787 NULL, /* pEllipse */
8788 NULL, /* pEndDoc */
8789 NULL, /* pEndPage */
8790 NULL, /* pEndPath */
8791 freetype_EnumFonts, /* pEnumFonts */
8792 NULL, /* pEnumICMProfiles */
8793 NULL, /* pExcludeClipRect */
8794 NULL, /* pExtDeviceMode */
8795 NULL, /* pExtEscape */
8796 NULL, /* pExtFloodFill */
8797 NULL, /* pExtSelectClipRgn */
8798 NULL, /* pExtTextOut */
8799 NULL, /* pFillPath */
8800 NULL, /* pFillRgn */
8801 NULL, /* pFlattenPath */
8802 freetype_FontIsLinked, /* pFontIsLinked */
8803 NULL, /* pFrameRgn */
8804 NULL, /* pGdiComment */
8805 NULL, /* pGetBoundsRect */
8806 freetype_GetCharABCWidths, /* pGetCharABCWidths */
8807 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
8808 freetype_GetCharWidth, /* pGetCharWidth */
8809 NULL, /* pGetDeviceCaps */
8810 NULL, /* pGetDeviceGammaRamp */
8811 freetype_GetFontData, /* pGetFontData */
8812 freetype_GetFontRealizationInfo, /* pGetFontRealizationInfo */
8813 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
8814 freetype_GetGlyphIndices, /* pGetGlyphIndices */
8815 freetype_GetGlyphOutline, /* pGetGlyphOutline */
8816 NULL, /* pGetICMProfile */
8817 NULL, /* pGetImage */
8818 freetype_GetKerningPairs, /* pGetKerningPairs */
8819 NULL, /* pGetNearestColor */
8820 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
8821 NULL, /* pGetPixel */
8822 NULL, /* pGetSystemPaletteEntries */
8823 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
8824 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
8825 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
8826 freetype_GetTextFace, /* pGetTextFace */
8827 freetype_GetTextMetrics, /* pGetTextMetrics */
8828 NULL, /* pGradientFill */
8829 NULL, /* pIntersectClipRect */
8830 NULL, /* pInvertRgn */
8831 NULL, /* pLineTo */
8832 NULL, /* pModifyWorldTransform */
8833 NULL, /* pMoveTo */
8834 NULL, /* pOffsetClipRgn */
8835 NULL, /* pOffsetViewportOrg */
8836 NULL, /* pOffsetWindowOrg */
8837 NULL, /* pPaintRgn */
8838 NULL, /* pPatBlt */
8839 NULL, /* pPie */
8840 NULL, /* pPolyBezier */
8841 NULL, /* pPolyBezierTo */
8842 NULL, /* pPolyDraw */
8843 NULL, /* pPolyPolygon */
8844 NULL, /* pPolyPolyline */
8845 NULL, /* pPolygon */
8846 NULL, /* pPolyline */
8847 NULL, /* pPolylineTo */
8848 NULL, /* pPutImage */
8849 NULL, /* pRealizeDefaultPalette */
8850 NULL, /* pRealizePalette */
8851 NULL, /* pRectangle */
8852 NULL, /* pResetDC */
8853 NULL, /* pRestoreDC */
8854 NULL, /* pRoundRect */
8855 NULL, /* pSaveDC */
8856 NULL, /* pScaleViewportExt */
8857 NULL, /* pScaleWindowExt */
8858 NULL, /* pSelectBitmap */
8859 NULL, /* pSelectBrush */
8860 NULL, /* pSelectClipPath */
8861 freetype_SelectFont, /* pSelectFont */
8862 NULL, /* pSelectPalette */
8863 NULL, /* pSelectPen */
8864 NULL, /* pSetArcDirection */
8865 NULL, /* pSetBkColor */
8866 NULL, /* pSetBkMode */
8867 NULL, /* pSetDCBrushColor */
8868 NULL, /* pSetDCPenColor */
8869 NULL, /* pSetDIBColorTable */
8870 NULL, /* pSetDIBitsToDevice */
8871 NULL, /* pSetDeviceClipping */
8872 NULL, /* pSetDeviceGammaRamp */
8873 NULL, /* pSetLayout */
8874 NULL, /* pSetMapMode */
8875 NULL, /* pSetMapperFlags */
8876 NULL, /* pSetPixel */
8877 NULL, /* pSetPolyFillMode */
8878 NULL, /* pSetROP2 */
8879 NULL, /* pSetRelAbs */
8880 NULL, /* pSetStretchBltMode */
8881 NULL, /* pSetTextAlign */
8882 NULL, /* pSetTextCharacterExtra */
8883 NULL, /* pSetTextColor */
8884 NULL, /* pSetTextJustification */
8885 NULL, /* pSetViewportExt */
8886 NULL, /* pSetViewportOrg */
8887 NULL, /* pSetWindowExt */
8888 NULL, /* pSetWindowOrg */
8889 NULL, /* pSetWorldTransform */
8890 NULL, /* pStartDoc */
8891 NULL, /* pStartPage */
8892 NULL, /* pStretchBlt */
8893 NULL, /* pStretchDIBits */
8894 NULL, /* pStrokeAndFillPath */
8895 NULL, /* pStrokePath */
8896 NULL, /* pUnrealizePalette */
8897 NULL, /* pWidenPath */
8898 NULL, /* wine_get_wgl_driver */
8899 GDI_PRIORITY_FONT_DRV /* priority */
8902 #else /* HAVE_FREETYPE */
8904 struct font_fileinfo;
8906 /*************************************************************************/
8908 BOOL WineEngInit(void)
8910 return FALSE;
8913 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8915 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8916 return 1;
8919 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8921 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8922 return TRUE;
8925 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
8927 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
8928 return NULL;
8931 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
8932 LPCWSTR font_file, LPCWSTR font_path )
8934 FIXME("stub\n");
8935 return FALSE;
8938 /*************************************************************************
8939 * GetRasterizerCaps (GDI32.@)
8941 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8943 lprs->nSize = sizeof(RASTERIZER_STATUS);
8944 lprs->wFlags = 0;
8945 lprs->nLanguageID = 0;
8946 return TRUE;
8949 /*************************************************************************
8950 * GetFontFileInfo (GDI32.@)
8952 BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_fileinfo *info, DWORD size, DWORD *needed)
8954 *needed = 0;
8955 return FALSE;
8958 #endif /* HAVE_FREETYPE */