hid: Stub HidP_TranslateUsagesToI8042ScanCodes.
[wine.git] / dlls / gdi32 / freetype.c
blob0e82e5e6ff28baf8958121ef382c9eeca7db66a0
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 CTFontRef font;
2937 ATSFontRef atsFont;
2938 OSStatus status;
2939 FSRef fsref;
2940 CFURLRef url;
2941 CFStringRef ext;
2942 CFStringRef path;
2944 desc = CFArrayGetValueAtIndex(descs, i);
2946 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2947 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2948 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2949 if (!font) continue;
2951 atsFont = CTFontGetPlatformFont(font, NULL);
2952 if (!atsFont)
2954 CFRelease(font);
2955 continue;
2958 status = ATSFontGetFileReference(atsFont, &fsref);
2959 CFRelease(font);
2960 if (status != noErr) continue;
2962 url = CFURLCreateFromFSRef(NULL, &fsref);
2963 if (!url) continue;
2965 ext = CFURLCopyPathExtension(url);
2966 if (ext)
2968 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2969 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2970 CFRelease(ext);
2971 if (skip)
2973 CFRelease(url);
2974 continue;
2978 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2979 CFRelease(url);
2980 if (!path) continue;
2982 CFSetAddValue(paths, path);
2983 CFRelease(path);
2986 CFRelease(descs);
2988 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2989 CFRelease(paths);
2992 #endif
2994 static char *get_font_dir(void)
2996 const char *build_dir, *data_dir;
2997 char *name = NULL;
2999 if ((data_dir = wine_get_data_dir()))
3001 if (!(name = HeapAlloc( GetProcessHeap(), 0, strlen(data_dir) + 1 + sizeof(WINE_FONT_DIR) )))
3002 return NULL;
3003 strcpy( name, data_dir );
3004 strcat( name, "/" );
3005 strcat( name, WINE_FONT_DIR );
3007 else if ((build_dir = wine_get_build_dir()))
3009 if (!(name = HeapAlloc( GetProcessHeap(), 0, strlen(build_dir) + sizeof("/fonts") )))
3010 return NULL;
3011 strcpy( name, build_dir );
3012 strcat( name, "/fonts" );
3014 return name;
3017 static char *get_data_dir_path( LPCWSTR file )
3019 char *unix_name = NULL;
3020 char *font_dir = get_font_dir();
3022 if (font_dir)
3024 INT len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
3026 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(font_dir) + len + 1 );
3027 strcpy(unix_name, font_dir);
3028 strcat(unix_name, "/");
3030 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
3031 HeapFree( GetProcessHeap(), 0, font_dir );
3033 return unix_name;
3036 static BOOL load_font_from_data_dir(LPCWSTR file)
3038 BOOL ret = FALSE;
3039 char *unix_name = get_data_dir_path( file );
3041 if (unix_name)
3043 EnterCriticalSection( &freetype_cs );
3044 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3045 LeaveCriticalSection( &freetype_cs );
3046 HeapFree(GetProcessHeap(), 0, unix_name);
3048 return ret;
3051 static char *get_winfonts_dir_path(LPCWSTR file)
3053 static const WCHAR slashW[] = {'\\','\0'};
3054 WCHAR windowsdir[MAX_PATH];
3056 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3057 strcatW(windowsdir, fontsW);
3058 strcatW(windowsdir, slashW);
3059 strcatW(windowsdir, file);
3060 return wine_get_unix_file_name( windowsdir );
3063 static void load_system_fonts(void)
3065 HKEY hkey;
3066 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
3067 const WCHAR * const *value;
3068 DWORD dlen, type;
3069 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3070 char *unixname;
3072 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
3073 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3074 strcatW(windowsdir, fontsW);
3075 for(value = SystemFontValues; *value; value++) {
3076 dlen = sizeof(data);
3077 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
3078 type == REG_SZ) {
3079 BOOL added = FALSE;
3081 sprintfW(pathW, fmtW, windowsdir, data);
3082 if((unixname = wine_get_unix_file_name(pathW))) {
3083 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3084 HeapFree(GetProcessHeap(), 0, unixname);
3086 if (!added)
3087 load_font_from_data_dir(data);
3090 RegCloseKey(hkey);
3094 /*************************************************************
3096 * This adds registry entries for any externally loaded fonts
3097 * (fonts from fontconfig or FontDirs). It also deletes entries
3098 * of no longer existing fonts.
3101 static void update_reg_entries(void)
3103 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
3104 LPWSTR valueW;
3105 DWORD len;
3106 Family *family;
3107 Face *face;
3108 WCHAR *file, *path;
3109 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
3111 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
3112 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
3113 ERR("Can't create Windows font reg key\n");
3114 goto end;
3117 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
3118 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
3119 ERR("Can't create Windows font reg key\n");
3120 goto end;
3123 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
3124 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
3125 ERR("Can't create external font reg key\n");
3126 goto end;
3129 /* enumerate the fonts and add external ones to the two keys */
3131 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
3132 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
3133 char *buffer;
3134 WCHAR *name;
3136 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
3138 name = face->FullName ? face->FullName : family->FamilyName;
3140 len = strlenW(name) + 1;
3141 if (face->scalable)
3142 len += sizeof(TrueType) / sizeof(WCHAR);
3144 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3145 strcpyW(valueW, name);
3147 if (face->scalable)
3148 strcatW(valueW, TrueType);
3150 buffer = strWtoA( CP_UNIXCP, face->file );
3151 path = wine_get_dos_file_name( buffer );
3152 HeapFree( GetProcessHeap(), 0, buffer );
3154 if (path)
3155 file = path;
3156 else if ((file = strrchrW(face->file, '/')))
3157 file++;
3158 else
3159 file = face->file;
3161 len = strlenW(file) + 1;
3162 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3163 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3164 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3166 HeapFree(GetProcessHeap(), 0, path);
3167 HeapFree(GetProcessHeap(), 0, valueW);
3170 end:
3171 if(external_key) RegCloseKey(external_key);
3172 if(win9x_key) RegCloseKey(win9x_key);
3173 if(winnt_key) RegCloseKey(winnt_key);
3176 static void delete_external_font_keys(void)
3178 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
3179 DWORD dlen, vlen, datalen, valuelen, i, type;
3180 LPWSTR valueW;
3181 LPVOID data;
3183 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
3184 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
3185 ERR("Can't create Windows font reg key\n");
3186 goto end;
3189 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
3190 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
3191 ERR("Can't create Windows font reg key\n");
3192 goto end;
3195 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
3196 ERR("Can't create external font reg key\n");
3197 goto end;
3200 /* Delete all external fonts added last time */
3202 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3203 &valuelen, &datalen, NULL, NULL);
3204 valuelen++; /* returned value doesn't include room for '\0' */
3205 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3206 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3208 dlen = datalen * sizeof(WCHAR);
3209 vlen = valuelen;
3210 i = 0;
3211 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
3212 &dlen) == ERROR_SUCCESS) {
3214 RegDeleteValueW(winnt_key, valueW);
3215 RegDeleteValueW(win9x_key, valueW);
3216 /* reset dlen and vlen */
3217 dlen = datalen;
3218 vlen = valuelen;
3220 HeapFree(GetProcessHeap(), 0, data);
3221 HeapFree(GetProcessHeap(), 0, valueW);
3223 /* Delete the old external fonts key */
3224 RegCloseKey(external_key);
3225 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
3227 end:
3228 if(win9x_key) RegCloseKey(win9x_key);
3229 if(winnt_key) RegCloseKey(winnt_key);
3232 /*************************************************************
3233 * WineEngAddFontResourceEx
3236 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3238 INT ret = 0;
3240 GDI_CheckNotLock();
3242 if (ft_handle) /* do it only if we have freetype up and running */
3244 char *unixname;
3246 EnterCriticalSection( &freetype_cs );
3248 if((unixname = wine_get_unix_file_name(file)))
3250 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3252 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3253 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
3254 HeapFree(GetProcessHeap(), 0, unixname);
3256 if (!ret && !strchrW(file, '\\')) {
3257 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
3258 if ((unixname = get_winfonts_dir_path( file )))
3260 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3261 HeapFree(GetProcessHeap(), 0, unixname);
3263 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
3264 if (!ret && (unixname = get_data_dir_path( file )))
3266 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3267 HeapFree(GetProcessHeap(), 0, unixname);
3271 LeaveCriticalSection( &freetype_cs );
3273 return ret;
3276 /*************************************************************
3277 * WineEngAddFontMemResourceEx
3280 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3282 GDI_CheckNotLock();
3284 if (ft_handle) /* do it only if we have freetype up and running */
3286 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
3288 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
3289 memcpy(pFontCopy, pbFont, cbFont);
3291 EnterCriticalSection( &freetype_cs );
3292 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3293 LeaveCriticalSection( &freetype_cs );
3295 if (*pcFonts == 0)
3297 TRACE("AddFontToList failed\n");
3298 HeapFree(GetProcessHeap(), 0, pFontCopy);
3299 return 0;
3301 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
3302 * For now return something unique but quite random
3304 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
3305 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
3308 *pcFonts = 0;
3309 return 0;
3312 /*************************************************************
3313 * WineEngRemoveFontResourceEx
3316 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3318 INT ret = 0;
3320 GDI_CheckNotLock();
3322 if (ft_handle) /* do it only if we have freetype up and running */
3324 char *unixname;
3326 EnterCriticalSection( &freetype_cs );
3328 if ((unixname = wine_get_unix_file_name(file)))
3330 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3332 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3333 ret = remove_font_resource( unixname, addfont_flags );
3334 HeapFree(GetProcessHeap(), 0, unixname);
3336 if (!ret && !strchrW(file, '\\'))
3338 if ((unixname = get_winfonts_dir_path( file )))
3340 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3341 HeapFree(GetProcessHeap(), 0, unixname);
3343 if (!ret && (unixname = get_data_dir_path( file )))
3345 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3346 HeapFree(GetProcessHeap(), 0, unixname);
3350 LeaveCriticalSection( &freetype_cs );
3352 return ret;
3355 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
3357 WCHAR *fullname;
3358 char *unix_name;
3359 int file_len;
3361 if (!font_file) return NULL;
3363 file_len = strlenW( font_file );
3365 if (font_path && font_path[0])
3367 int path_len = strlenW( font_path );
3368 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
3369 if (!fullname) return NULL;
3370 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
3371 fullname[path_len] = '\\';
3372 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
3374 else
3376 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
3377 if (!len) return NULL;
3378 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3379 if (!fullname) return NULL;
3380 GetFullPathNameW( font_file, len, fullname, NULL );
3383 unix_name = wine_get_unix_file_name( fullname );
3384 HeapFree( GetProcessHeap(), 0, fullname );
3385 return unix_name;
3388 #include <pshpack1.h>
3389 struct fontdir
3391 WORD num_of_resources;
3392 WORD res_id;
3393 WORD dfVersion;
3394 DWORD dfSize;
3395 CHAR dfCopyright[60];
3396 WORD dfType;
3397 WORD dfPoints;
3398 WORD dfVertRes;
3399 WORD dfHorizRes;
3400 WORD dfAscent;
3401 WORD dfInternalLeading;
3402 WORD dfExternalLeading;
3403 BYTE dfItalic;
3404 BYTE dfUnderline;
3405 BYTE dfStrikeOut;
3406 WORD dfWeight;
3407 BYTE dfCharSet;
3408 WORD dfPixWidth;
3409 WORD dfPixHeight;
3410 BYTE dfPitchAndFamily;
3411 WORD dfAvgWidth;
3412 WORD dfMaxWidth;
3413 BYTE dfFirstChar;
3414 BYTE dfLastChar;
3415 BYTE dfDefaultChar;
3416 BYTE dfBreakChar;
3417 WORD dfWidthBytes;
3418 DWORD dfDevice;
3419 DWORD dfFace;
3420 DWORD dfReserved;
3421 CHAR szFaceName[LF_FACESIZE];
3424 #include <poppack.h>
3426 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
3427 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
3429 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
3431 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3432 Face *face;
3433 WCHAR *name, *english_name;
3434 ENUMLOGFONTEXW elf;
3435 NEWTEXTMETRICEXW ntm;
3436 DWORD type;
3438 if (!ft_face) return FALSE;
3439 face = create_face( ft_face, 0, unix_name, NULL, 0, 0 );
3440 get_family_names( ft_face, &name, &english_name, FALSE );
3441 pFT_Done_Face( ft_face );
3443 GetEnumStructs( face, name, &elf, &ntm, &type );
3444 release_face( face );
3445 HeapFree( GetProcessHeap(), 0, name );
3446 HeapFree( GetProcessHeap(), 0, english_name );
3448 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3450 memset( fd, 0, sizeof(*fd) );
3452 fd->num_of_resources = 1;
3453 fd->res_id = 0;
3454 fd->dfVersion = 0x200;
3455 fd->dfSize = sizeof(*fd);
3456 strcpy( fd->dfCopyright, "Wine fontdir" );
3457 fd->dfType = 0x4003; /* 0x0080 set if private */
3458 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3459 fd->dfVertRes = 72;
3460 fd->dfHorizRes = 72;
3461 fd->dfAscent = ntm.ntmTm.tmAscent;
3462 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3463 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3464 fd->dfItalic = ntm.ntmTm.tmItalic;
3465 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3466 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3467 fd->dfWeight = ntm.ntmTm.tmWeight;
3468 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3469 fd->dfPixWidth = 0;
3470 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3471 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3472 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3473 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3474 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3475 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3476 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3477 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3478 fd->dfWidthBytes = 0;
3479 fd->dfDevice = 0;
3480 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3481 fd->dfReserved = 0;
3482 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3484 return TRUE;
3487 #define NE_FFLAGS_LIBMODULE 0x8000
3488 #define NE_OSFLAGS_WINDOWS 0x02
3490 static const char dos_string[0x40] = "This is a TrueType resource file";
3491 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3493 #include <pshpack2.h>
3495 struct ne_typeinfo
3497 WORD type_id;
3498 WORD count;
3499 DWORD res;
3502 struct ne_nameinfo
3504 WORD off;
3505 WORD len;
3506 WORD flags;
3507 WORD id;
3508 DWORD res;
3511 struct rsrc_tab
3513 WORD align;
3514 struct ne_typeinfo fontdir_type;
3515 struct ne_nameinfo fontdir_name;
3516 struct ne_typeinfo scalable_type;
3517 struct ne_nameinfo scalable_name;
3518 WORD end_of_rsrc;
3519 BYTE fontdir_res_name[8];
3522 #include <poppack.h>
3524 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3526 BOOL ret = FALSE;
3527 HANDLE file;
3528 DWORD size, written;
3529 BYTE *ptr, *start;
3530 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3531 char *font_fileA, *last_part, *ext;
3532 IMAGE_DOS_HEADER dos;
3533 IMAGE_OS2_HEADER ne =
3535 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3536 0, 0, 0, 0, 0, 0,
3537 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3538 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3540 struct rsrc_tab rsrc_tab =
3543 { 0x8007, 1, 0 },
3544 { 0, 0, 0x0c50, 0x2c, 0 },
3545 { 0x80cc, 1, 0 },
3546 { 0, 0, 0x0c50, 0x8001, 0 },
3548 { 7,'F','O','N','T','D','I','R'}
3551 memset( &dos, 0, sizeof(dos) );
3552 dos.e_magic = IMAGE_DOS_SIGNATURE;
3553 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3555 /* import name is last part\0, resident name is last part without extension
3556 non-resident name is "FONTRES:" + lfFaceName */
3558 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3559 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3560 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3562 last_part = strrchr( font_fileA, '\\' );
3563 if (last_part) last_part++;
3564 else last_part = font_fileA;
3565 import_name_len = strlen( last_part ) + 1;
3567 ext = strchr( last_part, '.' );
3568 if (ext) res_name_len = ext - last_part;
3569 else res_name_len = import_name_len - 1;
3571 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3573 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3574 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3575 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3576 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3577 ne.ne_cbenttab = 2;
3578 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3580 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3581 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3582 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3583 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3585 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3586 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3588 if (!ptr)
3590 HeapFree( GetProcessHeap(), 0, font_fileA );
3591 return FALSE;
3594 memcpy( ptr, &dos, sizeof(dos) );
3595 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3596 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3598 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3599 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3601 ptr = start + dos.e_lfanew + ne.ne_restab;
3602 *ptr++ = res_name_len;
3603 memcpy( ptr, last_part, res_name_len );
3605 ptr = start + dos.e_lfanew + ne.ne_imptab;
3606 *ptr++ = import_name_len;
3607 memcpy( ptr, last_part, import_name_len );
3609 ptr = start + ne.ne_nrestab;
3610 *ptr++ = non_res_name_len;
3611 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3612 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3614 ptr = start + (rsrc_tab.scalable_name.off << 4);
3615 memcpy( ptr, font_fileA, font_file_len );
3617 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3618 memcpy( ptr, fontdir, fontdir->dfSize );
3620 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3621 if (file != INVALID_HANDLE_VALUE)
3623 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3624 ret = TRUE;
3625 CloseHandle( file );
3628 HeapFree( GetProcessHeap(), 0, start );
3629 HeapFree( GetProcessHeap(), 0, font_fileA );
3631 return ret;
3634 /*************************************************************
3635 * WineEngCreateScalableFontResource
3638 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3639 LPCWSTR font_file, LPCWSTR font_path )
3641 char *unix_name = get_ttf_file_name( font_file, font_path );
3642 struct fontdir fontdir;
3643 BOOL ret = FALSE;
3645 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3646 SetLastError( ERROR_INVALID_PARAMETER );
3647 else
3649 if (hidden) fontdir.dfType |= 0x80;
3650 ret = create_fot( resource, font_file, &fontdir );
3653 HeapFree( GetProcessHeap(), 0, unix_name );
3654 return ret;
3657 static const struct nls_update_font_list
3659 UINT ansi_cp, oem_cp;
3660 const char *oem, *fixed, *system;
3661 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3662 /* these are for font substitutes */
3663 const char *shelldlg, *tmsrmn;
3664 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3665 *helv_0, *tmsrmn_0;
3666 const struct subst
3668 const char *from, *to;
3669 } arial_0, courier_new_0, times_new_roman_0;
3670 } nls_update_font_list[] =
3672 /* Latin 1 (United States) */
3673 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3674 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3675 "Tahoma","Times New Roman",
3676 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3677 { 0 }, { 0 }, { 0 }
3679 /* Latin 1 (Multilingual) */
3680 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3681 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3682 "Tahoma","Times New Roman", /* FIXME unverified */
3683 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3684 { 0 }, { 0 }, { 0 }
3686 /* Eastern Europe */
3687 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3688 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3689 "Tahoma","Times New Roman", /* FIXME unverified */
3690 "Fixedsys,238", "System,238",
3691 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3692 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3693 { "Arial CE,0", "Arial,238" },
3694 { "Courier New CE,0", "Courier New,238" },
3695 { "Times New Roman CE,0", "Times New Roman,238" }
3697 /* Cyrillic */
3698 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3699 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3700 "Tahoma","Times New Roman", /* FIXME unverified */
3701 "Fixedsys,204", "System,204",
3702 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3703 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3704 { "Arial Cyr,0", "Arial,204" },
3705 { "Courier New Cyr,0", "Courier New,204" },
3706 { "Times New Roman Cyr,0", "Times New Roman,204" }
3708 /* Greek */
3709 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3710 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3711 "Tahoma","Times New Roman", /* FIXME unverified */
3712 "Fixedsys,161", "System,161",
3713 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3714 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3715 { "Arial Greek,0", "Arial,161" },
3716 { "Courier New Greek,0", "Courier New,161" },
3717 { "Times New Roman Greek,0", "Times New Roman,161" }
3719 /* Turkish */
3720 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3721 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3722 "Tahoma","Times New Roman", /* FIXME unverified */
3723 "Fixedsys,162", "System,162",
3724 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3725 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3726 { "Arial Tur,0", "Arial,162" },
3727 { "Courier New Tur,0", "Courier New,162" },
3728 { "Times New Roman Tur,0", "Times New Roman,162" }
3730 /* Hebrew */
3731 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3732 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3733 "Tahoma","Times New Roman", /* FIXME unverified */
3734 "Fixedsys,177", "System,177",
3735 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3736 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3737 { 0 }, { 0 }, { 0 }
3739 /* Arabic */
3740 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3741 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3742 "Microsoft Sans Serif","Times New Roman",
3743 "Fixedsys,178", "System,178",
3744 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3745 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3746 { 0 }, { 0 }, { 0 }
3748 /* Baltic */
3749 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3750 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3751 "Tahoma","Times New Roman", /* FIXME unverified */
3752 "Fixedsys,186", "System,186",
3753 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3754 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3755 { "Arial Baltic,0", "Arial,186" },
3756 { "Courier New Baltic,0", "Courier New,186" },
3757 { "Times New Roman Baltic,0", "Times New Roman,186" }
3759 /* Vietnamese */
3760 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3761 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3762 "Tahoma","Times New Roman", /* FIXME unverified */
3763 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3764 { 0 }, { 0 }, { 0 }
3766 /* Thai */
3767 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3768 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3769 "Tahoma","Times New Roman", /* FIXME unverified */
3770 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3771 { 0 }, { 0 }, { 0 }
3773 /* Japanese */
3774 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3775 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3776 "MS UI Gothic","MS Serif",
3777 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3778 { 0 }, { 0 }, { 0 }
3780 /* Chinese Simplified */
3781 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3782 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3783 "SimSun", "NSimSun",
3784 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3785 { 0 }, { 0 }, { 0 }
3787 /* Korean */
3788 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3789 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3790 "Gulim", "Batang",
3791 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3792 { 0 }, { 0 }, { 0 }
3794 /* Chinese Traditional */
3795 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3796 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3797 "PMingLiU", "MingLiU",
3798 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3799 { 0 }, { 0 }, { 0 }
3803 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3805 return ( ansi_cp == 932 /* CP932 for Japanese */
3806 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3807 || ansi_cp == 949 /* CP949 for Korean */
3808 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3811 static inline HKEY create_fonts_NT_registry_key(void)
3813 HKEY hkey = 0;
3815 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3816 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3817 return hkey;
3820 static inline HKEY create_fonts_9x_registry_key(void)
3822 HKEY hkey = 0;
3824 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3825 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3826 return hkey;
3829 static inline HKEY create_config_fonts_registry_key(void)
3831 HKEY hkey = 0;
3833 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3834 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3835 return hkey;
3838 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3840 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3842 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3843 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3844 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3845 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3848 static void set_value_key(HKEY hkey, const char *name, const char *value)
3850 if (value)
3851 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3852 else if (name)
3853 RegDeleteValueA(hkey, name);
3856 static void update_font_association_info(UINT current_ansi_codepage)
3858 static const char *font_assoc_reg_key = "System\\CurrentControlSet\\Control\\FontAssoc";
3859 static const char *assoc_charset_subkey = "Associated Charset";
3861 if (is_dbcs_ansi_cp(current_ansi_codepage))
3863 HKEY hkey;
3864 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, font_assoc_reg_key, &hkey) == ERROR_SUCCESS)
3866 HKEY hsubkey;
3867 if (RegCreateKeyA(hkey, assoc_charset_subkey, &hsubkey) == ERROR_SUCCESS)
3869 switch (current_ansi_codepage)
3871 case 932:
3872 set_value_key(hsubkey, "ANSI(00)", "NO");
3873 set_value_key(hsubkey, "OEM(FF)", "NO");
3874 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3875 break;
3876 case 936:
3877 case 949:
3878 case 950:
3879 set_value_key(hsubkey, "ANSI(00)", "YES");
3880 set_value_key(hsubkey, "OEM(FF)", "YES");
3881 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3882 break;
3884 RegCloseKey(hsubkey);
3887 /* TODO: Associated DefaultFonts */
3889 RegCloseKey(hkey);
3892 else
3893 RegDeleteTreeA(HKEY_LOCAL_MACHINE, font_assoc_reg_key);
3896 static void set_multi_value_key(HKEY hkey, const WCHAR *name, const WCHAR *value, DWORD len)
3898 if (value)
3899 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (const BYTE *)value, len);
3900 else if (name)
3901 RegDeleteValueW(hkey, name);
3904 static void update_font_system_link_info(UINT current_ansi_codepage)
3906 static const WCHAR system_link_simplified_chinese[] =
3907 {'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3908 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3909 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3910 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3911 '\0'};
3912 static const WCHAR system_link_traditional_chinese[] =
3913 {'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3914 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3915 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3916 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3917 '\0'};
3918 static const WCHAR system_link_japanese[] =
3919 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
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 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3923 '\0'};
3924 static const WCHAR system_link_korean[] =
3925 {'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
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 '\0'};
3930 static const WCHAR system_link_non_cjk[] =
3931 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3932 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3933 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3934 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3935 '\0'};
3936 HKEY hkey;
3938 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
3940 const WCHAR *link;
3941 DWORD len;
3943 switch (current_ansi_codepage)
3945 case 932:
3946 link = system_link_japanese;
3947 len = sizeof(system_link_japanese);
3948 break;
3949 case 936:
3950 link = system_link_simplified_chinese;
3951 len = sizeof(system_link_simplified_chinese);
3952 break;
3953 case 949:
3954 link = system_link_korean;
3955 len = sizeof(system_link_korean);
3956 break;
3957 case 950:
3958 link = system_link_traditional_chinese;
3959 len = sizeof(system_link_traditional_chinese);
3960 break;
3961 default:
3962 link = system_link_non_cjk;
3963 len = sizeof(system_link_non_cjk);
3965 set_multi_value_key(hkey, Lucida_Sans_Unicode, link, len);
3966 set_multi_value_key(hkey, Microsoft_Sans_Serif, link, len);
3967 set_multi_value_key(hkey, Tahoma, link, len);
3968 RegCloseKey(hkey);
3972 static void update_font_info(void)
3974 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3975 char buf[40], cpbuf[40];
3976 DWORD len, type;
3977 HKEY hkey = 0;
3978 UINT i, ansi_cp = 0, oem_cp = 0;
3979 DWORD screen_dpi = 96, font_dpi = 0;
3980 BOOL done = FALSE;
3982 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3983 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3984 &hkey) == ERROR_SUCCESS)
3986 reg_load_dword(hkey, logpixels, &screen_dpi);
3987 RegCloseKey(hkey);
3990 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3991 return;
3993 reg_load_dword(hkey, logpixels, &font_dpi);
3995 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3996 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3997 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3998 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3999 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
4001 /* Setup Default_Fallback usage for DBCS ANSI codepages */
4002 if (is_dbcs_ansi_cp(ansi_cp))
4003 use_default_fallback = TRUE;
4005 buf[0] = 0;
4006 len = sizeof(buf);
4007 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
4009 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
4011 RegCloseKey(hkey);
4012 return;
4014 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
4015 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
4017 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
4018 ansi_cp, oem_cp, screen_dpi);
4020 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
4021 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
4022 RegCloseKey(hkey);
4024 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
4026 HKEY hkey;
4028 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
4029 nls_update_font_list[i].oem_cp == oem_cp)
4031 hkey = create_config_fonts_registry_key();
4032 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
4033 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
4034 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
4035 RegCloseKey(hkey);
4037 hkey = create_fonts_NT_registry_key();
4038 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
4039 RegCloseKey(hkey);
4041 hkey = create_fonts_9x_registry_key();
4042 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
4043 RegCloseKey(hkey);
4045 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
4047 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
4048 strlen(nls_update_font_list[i].shelldlg)+1);
4049 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
4050 strlen(nls_update_font_list[i].tmsrmn)+1);
4052 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
4053 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
4054 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
4055 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
4056 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
4057 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
4058 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
4059 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
4061 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
4062 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
4063 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
4065 RegCloseKey(hkey);
4067 done = TRUE;
4069 else
4071 /* Delete the FontSubstitutes from other locales */
4072 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
4074 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
4075 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
4076 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
4077 RegCloseKey(hkey);
4081 if (!done)
4082 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
4084 /* update locale dependent font association info and font system link info in registry.
4085 update only when codepages changed, not logpixels. */
4086 if (strcmp(buf, cpbuf) != 0)
4088 update_font_association_info(ansi_cp);
4089 update_font_system_link_info(ansi_cp);
4093 static BOOL init_freetype(void)
4095 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
4096 if(!ft_handle) {
4097 WINE_MESSAGE(
4098 "Wine cannot find the FreeType font library. To enable Wine to\n"
4099 "use TrueType fonts please install a version of FreeType greater than\n"
4100 "or equal to 2.0.5.\n"
4101 "http://www.freetype.org\n");
4102 return FALSE;
4105 #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;}
4107 LOAD_FUNCPTR(FT_Done_Face)
4108 LOAD_FUNCPTR(FT_Get_Char_Index)
4109 LOAD_FUNCPTR(FT_Get_First_Char)
4110 LOAD_FUNCPTR(FT_Get_Next_Char)
4111 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
4112 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
4113 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
4114 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
4115 LOAD_FUNCPTR(FT_Init_FreeType)
4116 LOAD_FUNCPTR(FT_Library_Version)
4117 LOAD_FUNCPTR(FT_Load_Glyph)
4118 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
4119 LOAD_FUNCPTR(FT_Matrix_Multiply)
4120 #ifndef FT_MULFIX_INLINED
4121 LOAD_FUNCPTR(FT_MulFix)
4122 #endif
4123 LOAD_FUNCPTR(FT_New_Face)
4124 LOAD_FUNCPTR(FT_New_Memory_Face)
4125 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
4126 LOAD_FUNCPTR(FT_Outline_Get_CBox)
4127 LOAD_FUNCPTR(FT_Outline_Transform)
4128 LOAD_FUNCPTR(FT_Outline_Translate)
4129 LOAD_FUNCPTR(FT_Render_Glyph)
4130 LOAD_FUNCPTR(FT_Select_Charmap)
4131 LOAD_FUNCPTR(FT_Set_Charmap)
4132 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
4133 LOAD_FUNCPTR(FT_Vector_Length)
4134 LOAD_FUNCPTR(FT_Vector_Transform)
4135 LOAD_FUNCPTR(FT_Vector_Unit)
4136 #undef LOAD_FUNCPTR
4137 /* Don't warn if these ones are missing */
4138 pFT_Outline_Embolden = wine_dlsym(ft_handle, "FT_Outline_Embolden", NULL, 0);
4139 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
4140 #ifdef FT_LCD_FILTER_H
4141 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
4142 #endif
4144 if(pFT_Init_FreeType(&library) != 0) {
4145 ERR("Can't init FreeType library\n");
4146 wine_dlclose(ft_handle, NULL, 0);
4147 ft_handle = NULL;
4148 return FALSE;
4150 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
4152 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
4153 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
4154 ((FT_Version.minor << 8) & 0x00ff00) |
4155 ((FT_Version.patch ) & 0x0000ff);
4157 font_driver = &freetype_funcs;
4158 return TRUE;
4160 sym_not_found:
4161 WINE_MESSAGE(
4162 "Wine cannot find certain functions that it needs inside the FreeType\n"
4163 "font library. To enable Wine to use TrueType fonts please upgrade\n"
4164 "FreeType to at least version 2.1.4.\n"
4165 "http://www.freetype.org\n");
4166 wine_dlclose(ft_handle, NULL, 0);
4167 ft_handle = NULL;
4168 return FALSE;
4171 static void init_font_list(void)
4173 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
4174 static const WCHAR pathW[] = {'P','a','t','h',0};
4175 HKEY hkey;
4176 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
4177 WCHAR windowsdir[MAX_PATH];
4178 char *unixname;
4180 delete_external_font_keys();
4182 /* load the system bitmap fonts */
4183 load_system_fonts();
4185 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
4186 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
4187 strcatW(windowsdir, fontsW);
4188 if((unixname = wine_get_unix_file_name(windowsdir)))
4190 ReadFontDir(unixname, FALSE);
4191 HeapFree(GetProcessHeap(), 0, unixname);
4194 /* load the wine fonts */
4195 if ((unixname = get_font_dir()))
4197 ReadFontDir(unixname, TRUE);
4198 HeapFree(GetProcessHeap(), 0, unixname);
4201 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
4202 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
4203 full path as the entry. Also look for any .fon fonts, since ReadFontDir
4204 will skip these. */
4205 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
4206 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
4207 &hkey) == ERROR_SUCCESS)
4209 LPWSTR data, valueW;
4210 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
4211 &valuelen, &datalen, NULL, NULL);
4213 valuelen++; /* returned value doesn't include room for '\0' */
4214 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
4215 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
4216 if (valueW && data)
4218 dlen = datalen * sizeof(WCHAR);
4219 vlen = valuelen;
4220 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
4221 &dlen) == ERROR_SUCCESS)
4223 if(data[0] && (data[1] == ':'))
4225 if((unixname = wine_get_unix_file_name(data)))
4227 AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
4228 HeapFree(GetProcessHeap(), 0, unixname);
4231 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
4233 WCHAR pathW[MAX_PATH];
4234 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
4235 BOOL added = FALSE;
4237 sprintfW(pathW, fmtW, windowsdir, data);
4238 if((unixname = wine_get_unix_file_name(pathW)))
4240 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
4241 HeapFree(GetProcessHeap(), 0, unixname);
4243 if (!added)
4244 load_font_from_data_dir(data);
4246 /* reset dlen and vlen */
4247 dlen = datalen;
4248 vlen = valuelen;
4251 HeapFree(GetProcessHeap(), 0, data);
4252 HeapFree(GetProcessHeap(), 0, valueW);
4253 RegCloseKey(hkey);
4256 #ifdef SONAME_LIBFONTCONFIG
4257 load_fontconfig_fonts();
4258 #elif defined(HAVE_CARBON_CARBON_H)
4259 load_mac_fonts();
4260 #elif defined(__ANDROID__)
4261 ReadFontDir("/system/fonts", TRUE);
4262 #endif
4264 /* then look in any directories that we've specified in the config file */
4265 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
4266 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
4268 DWORD len;
4269 LPWSTR valueW;
4270 LPSTR valueA, ptr;
4272 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
4274 len += sizeof(WCHAR);
4275 valueW = HeapAlloc( GetProcessHeap(), 0, len );
4276 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
4278 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
4279 valueA = HeapAlloc( GetProcessHeap(), 0, len );
4280 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
4281 TRACE( "got font path %s\n", debugstr_a(valueA) );
4282 ptr = valueA;
4283 while (ptr)
4285 const char* home;
4286 LPSTR next = strchr( ptr, ':' );
4287 if (next) *next++ = 0;
4288 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
4289 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
4291 strcpy( unixname, home );
4292 strcat( unixname, ptr + 1 );
4293 ReadFontDir( unixname, TRUE );
4294 HeapFree( GetProcessHeap(), 0, unixname );
4296 else
4297 ReadFontDir( ptr, TRUE );
4298 ptr = next;
4300 HeapFree( GetProcessHeap(), 0, valueA );
4302 HeapFree( GetProcessHeap(), 0, valueW );
4304 RegCloseKey(hkey);
4308 static BOOL move_to_front(const WCHAR *name)
4310 Family *family, *cursor2;
4311 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
4313 if(!strcmpiW(family->FamilyName, name))
4315 list_remove(&family->entry);
4316 list_add_head(&font_list, &family->entry);
4317 return TRUE;
4320 return FALSE;
4323 static BOOL set_default(const WCHAR **name_list)
4325 while (*name_list)
4327 if (move_to_front(*name_list)) return TRUE;
4328 name_list++;
4331 return FALSE;
4334 static void reorder_font_list(void)
4336 set_default( default_serif_list );
4337 set_default( default_fixed_list );
4338 set_default( default_sans_list );
4341 /*************************************************************
4342 * WineEngInit
4344 * Initialize FreeType library and create a list of available faces
4346 BOOL WineEngInit(void)
4348 HKEY hkey;
4349 DWORD disposition;
4350 HANDLE font_mutex;
4352 /* update locale dependent font info in registry */
4353 update_font_info();
4355 if(!init_freetype()) return FALSE;
4357 #ifdef SONAME_LIBFONTCONFIG
4358 init_fontconfig();
4359 #endif
4361 if (!RegOpenKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, KEY_READ, &hkey))
4363 static const WCHAR antialias_fake_bold_or_italic[] = { 'A','n','t','i','a','l','i','a','s','F','a','k','e',
4364 'B','o','l','d','O','r','I','t','a','l','i','c',0 };
4365 static const WCHAR true_options[] = { 'y','Y','t','T','1',0 };
4366 DWORD type, size;
4367 WCHAR buffer[20];
4369 size = sizeof(buffer);
4370 if (!RegQueryValueExW(hkey, antialias_fake_bold_or_italic, NULL, &type, (BYTE*)buffer, &size) &&
4371 type == REG_SZ && size >= 1)
4373 antialias_fakes = (strchrW(true_options, buffer[0]) != NULL);
4375 RegCloseKey(hkey);
4378 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
4380 ERR("Failed to create font mutex\n");
4381 return FALSE;
4383 WaitForSingleObject(font_mutex, INFINITE);
4385 create_font_cache_key(&hkey_font_cache, &disposition);
4387 if(disposition == REG_CREATED_NEW_KEY)
4388 init_font_list();
4389 else
4390 load_font_list_from_cache(hkey_font_cache);
4392 reorder_font_list();
4394 DumpFontList();
4395 LoadSubstList();
4396 DumpSubstList();
4397 LoadReplaceList();
4399 if(disposition == REG_CREATED_NEW_KEY)
4400 update_reg_entries();
4402 init_system_links();
4404 ReleaseMutex(font_mutex);
4405 return TRUE;
4408 /* Some fonts have large usWinDescent values, as a result of storing signed short
4409 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
4410 some font generation tools. */
4411 static inline USHORT get_fixed_windescent(USHORT windescent)
4413 return abs((SHORT)windescent);
4416 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
4418 TT_OS2 *pOS2;
4419 TT_HoriHeader *pHori;
4421 LONG ppem;
4422 const LONG MAX_PPEM = (1 << 16) - 1;
4424 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4425 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4427 if(height == 0) height = 16;
4429 /* Calc. height of EM square:
4431 * For +ve lfHeight we have
4432 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
4433 * Re-arranging gives:
4434 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4436 * For -ve lfHeight we have
4437 * |lfHeight| = ppem
4438 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4439 * with il = winAscent + winDescent - units_per_em]
4443 if(height > 0) {
4444 USHORT windescent = get_fixed_windescent(pOS2->usWinDescent);
4445 if(pOS2->usWinAscent + windescent == 0)
4446 ppem = MulDiv(ft_face->units_per_EM, height,
4447 pHori->Ascender - pHori->Descender);
4448 else
4449 ppem = MulDiv(ft_face->units_per_EM, height,
4450 pOS2->usWinAscent + windescent);
4451 if(ppem > MAX_PPEM) {
4452 WARN("Ignoring too large height %d, ppem %d\n", height, ppem);
4453 ppem = 1;
4456 else if(height >= -MAX_PPEM)
4457 ppem = -height;
4458 else {
4459 WARN("Ignoring too large height %d\n", height);
4460 ppem = 1;
4463 return ppem;
4466 static struct font_mapping *map_font_file( const char *name )
4468 struct font_mapping *mapping;
4469 struct stat st;
4470 int fd;
4472 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
4473 if (fstat( fd, &st ) == -1) goto error;
4475 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
4477 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
4479 mapping->refcount++;
4480 close( fd );
4481 return mapping;
4484 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
4485 goto error;
4487 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
4488 close( fd );
4490 if (mapping->data == MAP_FAILED)
4492 HeapFree( GetProcessHeap(), 0, mapping );
4493 return NULL;
4495 mapping->refcount = 1;
4496 mapping->dev = st.st_dev;
4497 mapping->ino = st.st_ino;
4498 mapping->size = st.st_size;
4499 list_add_tail( &mappings_list, &mapping->entry );
4500 return mapping;
4502 error:
4503 close( fd );
4504 return NULL;
4507 static void unmap_font_file( struct font_mapping *mapping )
4509 if (!--mapping->refcount)
4511 list_remove( &mapping->entry );
4512 munmap( mapping->data, mapping->size );
4513 HeapFree( GetProcessHeap(), 0, mapping );
4517 static LONG load_VDMX(GdiFont*, LONG);
4519 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
4521 FT_Error err;
4522 FT_Face ft_face;
4523 void *data_ptr;
4524 DWORD data_size;
4526 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
4528 if (face->file)
4530 char *filename = strWtoA( CP_UNIXCP, face->file );
4531 font->mapping = map_font_file( filename );
4532 HeapFree( GetProcessHeap(), 0, filename );
4533 if (!font->mapping)
4535 WARN("failed to map %s\n", debugstr_w(face->file));
4536 return 0;
4538 data_ptr = font->mapping->data;
4539 data_size = font->mapping->size;
4541 else
4543 data_ptr = face->font_data_ptr;
4544 data_size = face->font_data_size;
4547 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
4548 if(err) {
4549 ERR("FT_New_Face rets %d\n", err);
4550 return 0;
4553 /* set it here, as load_VDMX needs it */
4554 font->ft_face = ft_face;
4556 if(FT_IS_SCALABLE(ft_face)) {
4557 FT_ULong len;
4558 DWORD header;
4560 /* load the VDMX table if we have one */
4561 font->ppem = load_VDMX(font, height);
4562 if(font->ppem == 0)
4563 font->ppem = calc_ppem_for_height(ft_face, height);
4564 TRACE("height %d => ppem %d\n", height, font->ppem);
4566 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
4567 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
4569 /* see if it's a TTC */
4570 len = sizeof(header);
4571 if (!pFT_Load_Sfnt_Table(ft_face, 0, 0, (void*)&header, &len)) {
4572 if (header == MS_TTCF_TAG)
4574 len = sizeof(font->ttc_item_offset);
4575 if (pFT_Load_Sfnt_Table(ft_face, 0, (3 + face->face_index) * sizeof(DWORD),
4576 (void*)&font->ttc_item_offset, &len))
4577 font->ttc_item_offset = 0;
4578 else
4579 font->ttc_item_offset = GET_BE_DWORD(font->ttc_item_offset);
4582 } else {
4583 font->ppem = height;
4584 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
4585 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
4587 return ft_face;
4591 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
4593 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4594 a single face with the requested charset. The idea is to check if
4595 the selected font supports the current ANSI codepage, if it does
4596 return the corresponding charset, else return the first charset */
4598 CHARSETINFO csi;
4599 int acp = GetACP(), i;
4600 DWORD fs0;
4602 *cp = acp;
4603 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
4605 const SYSTEM_LINKS *font_link;
4607 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4608 return csi.ciCharset;
4610 font_link = find_font_link(family_name);
4611 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4612 return csi.ciCharset;
4615 for(i = 0; i < 32; i++) {
4616 fs0 = 1L << i;
4617 if(face->fs.fsCsb[0] & fs0) {
4618 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4619 *cp = csi.ciACP;
4620 return csi.ciCharset;
4622 else
4623 FIXME("TCI failing on %x\n", fs0);
4627 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4628 face->fs.fsCsb[0], debugstr_w(face->file));
4629 *cp = acp;
4630 return DEFAULT_CHARSET;
4633 static GdiFont *alloc_font(void)
4635 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4636 ret->refcount = 1;
4637 ret->gmsize = 1;
4638 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4639 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4640 ret->potm = NULL;
4641 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4642 ret->total_kern_pairs = (DWORD)-1;
4643 ret->kern_pairs = NULL;
4644 ret->instance_id = alloc_font_handle(ret);
4645 list_init(&ret->child_fonts);
4646 return ret;
4649 static void free_font(GdiFont *font)
4651 CHILD_FONT *child, *child_next;
4652 DWORD i;
4654 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
4656 list_remove(&child->entry);
4657 if(child->font)
4658 free_font(child->font);
4659 release_face( child->face );
4660 HeapFree(GetProcessHeap(), 0, child);
4663 HeapFree(GetProcessHeap(), 0, font->fileinfo);
4664 free_font_handle(font->instance_id);
4665 if (font->ft_face) pFT_Done_Face(font->ft_face);
4666 if (font->mapping) unmap_font_file( font->mapping );
4667 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4668 HeapFree(GetProcessHeap(), 0, font->potm);
4669 HeapFree(GetProcessHeap(), 0, font->name);
4670 for (i = 0; i < font->gmsize; i++)
4671 HeapFree(GetProcessHeap(),0,font->gm[i]);
4672 HeapFree(GetProcessHeap(), 0, font->gm);
4673 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4674 HeapFree(GetProcessHeap(), 0, font);
4678 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4680 FT_Face ft_face = font->ft_face;
4681 FT_ULong len;
4682 FT_Error err;
4684 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4686 if(!buf)
4687 len = 0;
4688 else
4689 len = cbData;
4691 /* if font is a member of TTC, 'ttcf' tag allows reading from beginning of TTC file,
4692 0 tag means to read from start of collection member data. */
4693 if (font->ttc_item_offset)
4695 if (table == MS_TTCF_TAG)
4696 table = 0;
4697 else if (table == 0)
4698 offset += font->ttc_item_offset;
4701 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4703 /* make sure value of len is the value freetype says it needs */
4704 if (buf && len)
4706 FT_ULong needed = 0;
4707 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4708 if( !err && needed < len) len = needed;
4710 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4711 if (err)
4713 table = RtlUlongByteSwap( table );
4714 TRACE("Can't find table %s\n", debugstr_an((char*)&table, 4));
4715 return GDI_ERROR;
4717 return len;
4720 /*************************************************************
4721 * load_VDMX
4723 * load the vdmx entry for the specified height
4728 typedef struct {
4729 WORD version;
4730 WORD numRecs;
4731 WORD numRatios;
4732 } VDMX_Header;
4734 typedef struct {
4735 BYTE bCharSet;
4736 BYTE xRatio;
4737 BYTE yStartRatio;
4738 BYTE yEndRatio;
4739 } Ratios;
4741 typedef struct {
4742 WORD recs;
4743 BYTE startsz;
4744 BYTE endsz;
4745 } VDMX_group;
4747 typedef struct {
4748 WORD yPelHeight;
4749 WORD yMax;
4750 WORD yMin;
4751 } VDMX_vTable;
4753 static LONG load_VDMX(GdiFont *font, LONG height)
4755 VDMX_Header hdr;
4756 VDMX_group group;
4757 BYTE devXRatio, devYRatio;
4758 USHORT numRecs, numRatios;
4759 DWORD result, offset = -1;
4760 LONG ppem = 0;
4761 int i;
4763 result = get_font_data(font, MS_VDMX_TAG, 0, &hdr, sizeof(hdr));
4765 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4766 return ppem;
4768 /* FIXME: need the real device aspect ratio */
4769 devXRatio = 1;
4770 devYRatio = 1;
4772 numRecs = GET_BE_WORD(hdr.numRecs);
4773 numRatios = GET_BE_WORD(hdr.numRatios);
4775 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr.version), numRecs, numRatios);
4776 for(i = 0; i < numRatios; i++) {
4777 Ratios ratio;
4779 offset = sizeof(hdr) + (i * sizeof(Ratios));
4780 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4781 offset = -1;
4783 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4785 if (!ratio.bCharSet) continue;
4787 if((ratio.xRatio == 0 &&
4788 ratio.yStartRatio == 0 &&
4789 ratio.yEndRatio == 0) ||
4790 (devXRatio == ratio.xRatio &&
4791 devYRatio >= ratio.yStartRatio &&
4792 devYRatio <= ratio.yEndRatio))
4794 WORD group_offset;
4796 offset = sizeof(hdr) + numRatios * sizeof(ratio) + i * sizeof(group_offset);
4797 get_font_data(font, MS_VDMX_TAG, offset, &group_offset, sizeof(group_offset));
4798 offset = GET_BE_WORD(group_offset);
4799 break;
4803 if(offset == -1) return 0;
4805 if(get_font_data(font, MS_VDMX_TAG, offset, &group, sizeof(group)) != GDI_ERROR) {
4806 USHORT recs;
4807 BYTE startsz, endsz;
4808 WORD *vTable;
4810 recs = GET_BE_WORD(group.recs);
4811 startsz = group.startsz;
4812 endsz = group.endsz;
4814 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4816 vTable = HeapAlloc(GetProcessHeap(), 0, recs * sizeof(VDMX_vTable));
4817 result = get_font_data(font, MS_VDMX_TAG, offset + sizeof(group), vTable, recs * sizeof(VDMX_vTable));
4818 if(result == GDI_ERROR) {
4819 FIXME("Failed to retrieve vTable\n");
4820 goto end;
4823 if(height > 0) {
4824 for(i = 0; i < recs; i++) {
4825 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4826 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4827 ppem = GET_BE_WORD(vTable[i * 3]);
4829 if(yMax + -yMin == height) {
4830 font->yMax = yMax;
4831 font->yMin = yMin;
4832 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4833 break;
4835 if(yMax + -yMin > height) {
4836 if(--i < 0) {
4837 ppem = 0;
4838 goto end; /* failed */
4840 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4841 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4842 ppem = GET_BE_WORD(vTable[i * 3]);
4843 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4844 break;
4847 if(!font->yMax) {
4848 ppem = 0;
4849 TRACE("ppem not found for height %d\n", height);
4851 } else {
4852 ppem = -height;
4853 if(ppem < startsz || ppem > endsz)
4855 ppem = 0;
4856 goto end;
4859 for(i = 0; i < recs; i++) {
4860 USHORT yPelHeight;
4861 yPelHeight = GET_BE_WORD(vTable[i * 3]);
4863 if(yPelHeight > ppem)
4865 ppem = 0;
4866 break; /* failed */
4869 if(yPelHeight == ppem) {
4870 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4871 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4872 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
4873 break;
4877 end:
4878 HeapFree(GetProcessHeap(), 0, vTable);
4881 return ppem;
4884 static void dump_gdi_font_list(void)
4886 GdiFont *font;
4888 TRACE("---------- Font Cache ----------\n");
4889 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct tagGdiFont, entry )
4890 TRACE("font=%p ref=%u %s %d\n", font, font->refcount,
4891 debugstr_w(font->font_desc.lf.lfFaceName), font->font_desc.lf.lfHeight);
4894 static void grab_font( GdiFont *font )
4896 if (!font->refcount++)
4898 list_remove( &font->unused_entry );
4899 unused_font_count--;
4903 static void release_font( GdiFont *font )
4905 if (!font) return;
4906 if (!--font->refcount)
4908 TRACE( "font %p\n", font );
4910 /* add it to the unused list */
4911 list_add_head( &unused_gdi_font_list, &font->unused_entry );
4912 if (unused_font_count > UNUSED_CACHE_SIZE)
4914 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct tagGdiFont, unused_entry );
4915 TRACE( "freeing %p\n", font );
4916 list_remove( &font->entry );
4917 list_remove( &font->unused_entry );
4918 free_font( font );
4920 else unused_font_count++;
4922 if (TRACE_ON(font)) dump_gdi_font_list();
4926 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4928 if(font->font_desc.hash != fd->hash) return TRUE;
4929 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4930 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4931 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4932 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4935 static void calc_hash(FONT_DESC *pfd)
4937 DWORD hash = 0, *ptr, two_chars;
4938 WORD *pwc;
4939 unsigned int i;
4941 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4942 hash ^= *ptr;
4943 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4944 hash ^= *ptr;
4945 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4946 two_chars = *ptr;
4947 pwc = (WCHAR *)&two_chars;
4948 if(!*pwc) break;
4949 *pwc = toupperW(*pwc);
4950 pwc++;
4951 *pwc = toupperW(*pwc);
4952 hash ^= two_chars;
4953 if(!*pwc) break;
4955 hash ^= !pfd->can_use_bitmap;
4956 pfd->hash = hash;
4959 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4961 GdiFont *ret;
4962 FONT_DESC fd;
4964 fd.lf = *plf;
4965 fd.matrix = *pmat;
4966 fd.can_use_bitmap = can_use_bitmap;
4967 calc_hash(&fd);
4969 /* try the in-use list */
4970 LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
4972 if(fontcmp(ret, &fd)) continue;
4973 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4974 list_remove( &ret->entry );
4975 list_add_head( &gdi_font_list, &ret->entry );
4976 grab_font( ret );
4977 return ret;
4979 return NULL;
4982 static void add_to_cache(GdiFont *font)
4984 static DWORD cache_num = 1;
4986 font->cache_num = cache_num++;
4987 list_add_head(&gdi_font_list, &font->entry);
4988 TRACE( "font %p\n", font );
4991 /*************************************************************
4992 * create_child_font_list
4994 static BOOL create_child_font_list(GdiFont *font)
4996 BOOL ret = FALSE;
4997 SYSTEM_LINKS *font_link;
4998 CHILD_FONT *font_link_entry, *new_child;
4999 FontSubst *psub;
5000 WCHAR* font_name;
5002 psub = get_font_subst(&font_subst_list, font->name, -1);
5003 font_name = psub ? psub->to.name : font->name;
5004 font_link = find_font_link(font_name);
5005 if (font_link != NULL)
5007 TRACE("found entry in system list\n");
5008 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5010 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
5011 new_child->face = font_link_entry->face;
5012 new_child->font = NULL;
5013 new_child->face->refcount++;
5014 list_add_tail(&font->child_fonts, &new_child->entry);
5015 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
5017 ret = TRUE;
5020 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
5021 * Sans Serif. This is how asian windows get default fallbacks for fonts
5023 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
5024 font->charset != OEM_CHARSET &&
5025 strcmpiW(font_name,szDefaultFallbackLink) != 0)
5027 font_link = find_font_link(szDefaultFallbackLink);
5028 if (font_link != NULL)
5030 TRACE("found entry in default fallback list\n");
5031 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5033 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
5034 new_child->face = font_link_entry->face;
5035 new_child->font = NULL;
5036 new_child->face->refcount++;
5037 list_add_tail(&font->child_fonts, &new_child->entry);
5038 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
5040 ret = TRUE;
5044 return ret;
5047 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
5049 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
5051 if (pFT_Set_Charmap)
5053 FT_Int i;
5054 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
5056 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
5058 for (i = 0; i < ft_face->num_charmaps; i++)
5060 if (ft_face->charmaps[i]->encoding == encoding)
5062 TRACE("found cmap with platform_id %u, encoding_id %u\n",
5063 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
5065 switch (ft_face->charmaps[i]->platform_id)
5067 default:
5068 cmap_def = ft_face->charmaps[i];
5069 break;
5070 case 0: /* Apple Unicode */
5071 cmap0 = ft_face->charmaps[i];
5072 break;
5073 case 1: /* Macintosh */
5074 cmap1 = ft_face->charmaps[i];
5075 break;
5076 case 2: /* ISO */
5077 cmap2 = ft_face->charmaps[i];
5078 break;
5079 case 3: /* Microsoft */
5080 cmap3 = ft_face->charmaps[i];
5081 break;
5085 if (cmap3) /* prefer Microsoft cmap table */
5086 ft_err = pFT_Set_Charmap(ft_face, cmap3);
5087 else if (cmap1)
5088 ft_err = pFT_Set_Charmap(ft_face, cmap1);
5089 else if (cmap2)
5090 ft_err = pFT_Set_Charmap(ft_face, cmap2);
5091 else if (cmap0)
5092 ft_err = pFT_Set_Charmap(ft_face, cmap0);
5093 else if (cmap_def)
5094 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
5096 return ft_err == FT_Err_Ok;
5099 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
5103 /*************************************************************
5104 * freetype_CreateDC
5106 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
5107 LPCWSTR output, const DEVMODEW *devmode )
5109 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
5111 if (!physdev) return FALSE;
5112 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
5113 return TRUE;
5117 /*************************************************************
5118 * freetype_DeleteDC
5120 static BOOL freetype_DeleteDC( PHYSDEV dev )
5122 struct freetype_physdev *physdev = get_freetype_dev( dev );
5123 release_font( physdev->font );
5124 HeapFree( GetProcessHeap(), 0, physdev );
5125 return TRUE;
5128 static FT_Encoding pick_charmap( FT_Face face, int charset )
5130 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
5131 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
5132 const FT_Encoding *encs = regular_order;
5134 if (charset == SYMBOL_CHARSET) encs = symbol_order;
5136 while (*encs != 0)
5138 if (select_charmap( face, *encs )) break;
5139 encs++;
5141 return *encs;
5144 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
5146 DWORD size;
5147 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
5148 WORD *alloced = NULL, *ptr = buf;
5149 WORD num_recs, version;
5150 BOOL ret = FALSE;
5152 *flags = 0;
5153 size = get_font_data( font, MS_GASP_TAG, 0, NULL, 0 );
5154 if (size == GDI_ERROR) return FALSE;
5155 if (size < 4 * sizeof(WORD)) return FALSE;
5156 if (size > sizeof(buf))
5158 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
5159 if (!ptr) return FALSE;
5162 get_font_data( font, MS_GASP_TAG, 0, ptr, size );
5164 version = GET_BE_WORD( *ptr++ );
5165 num_recs = GET_BE_WORD( *ptr++ );
5167 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
5169 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
5170 goto done;
5173 while (num_recs--)
5175 *flags = GET_BE_WORD( *(ptr + 1) );
5176 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
5177 ptr += 2;
5179 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
5180 ret = TRUE;
5182 done:
5183 HeapFree( GetProcessHeap(), 0, alloced );
5184 return ret;
5187 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5189 const GSUB_ScriptList *script;
5190 const GSUB_Script *deflt = NULL;
5191 int i;
5192 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5194 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5195 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5197 const GSUB_Script *scr;
5198 int offset;
5200 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5201 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5203 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5204 return scr;
5205 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5206 deflt = scr;
5208 return deflt;
5211 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5213 int i;
5214 int offset;
5215 const GSUB_LangSys *Lang;
5217 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5219 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5221 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5222 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5224 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5225 return Lang;
5227 offset = GET_BE_WORD(script->DefaultLangSys);
5228 if (offset)
5230 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5231 return Lang;
5233 return NULL;
5236 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5238 int i;
5239 const GSUB_FeatureList *feature;
5240 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5242 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5243 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5245 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5246 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5248 const GSUB_Feature *feat;
5249 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5250 return feat;
5253 return NULL;
5256 static const char* get_opentype_script(const GdiFont *font)
5259 * I am not sure if this is the correct way to generate our script tag
5262 switch (font->charset)
5264 case ANSI_CHARSET: return "latn";
5265 case BALTIC_CHARSET: return "latn"; /* ?? */
5266 case CHINESEBIG5_CHARSET: return "hani";
5267 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5268 case GB2312_CHARSET: return "hani";
5269 case GREEK_CHARSET: return "grek";
5270 case HANGUL_CHARSET: return "hang";
5271 case RUSSIAN_CHARSET: return "cyrl";
5272 case SHIFTJIS_CHARSET: return "kana";
5273 case TURKISH_CHARSET: return "latn"; /* ?? */
5274 case VIETNAMESE_CHARSET: return "latn";
5275 case JOHAB_CHARSET: return "latn"; /* ?? */
5276 case ARABIC_CHARSET: return "arab";
5277 case HEBREW_CHARSET: return "hebr";
5278 case THAI_CHARSET: return "thai";
5279 default: return "latn";
5283 static const VOID * get_GSUB_vert_feature(const GdiFont *font)
5285 const GSUB_Header *header;
5286 const GSUB_Script *script;
5287 const GSUB_LangSys *language;
5288 const GSUB_Feature *feature;
5290 if (!font->GSUB_Table)
5291 return NULL;
5293 header = font->GSUB_Table;
5295 script = GSUB_get_script_table(header, get_opentype_script(font));
5296 if (!script)
5298 TRACE("Script not found\n");
5299 return NULL;
5301 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5302 if (!language)
5304 TRACE("Language not found\n");
5305 return NULL;
5307 feature = GSUB_get_feature(header, language, "vrt2");
5308 if (!feature)
5309 feature = GSUB_get_feature(header, language, "vert");
5310 if (!feature)
5312 TRACE("vrt2/vert feature not found\n");
5313 return NULL;
5315 return feature;
5318 static void fill_fileinfo_from_face( GdiFont *font, Face *face )
5320 WIN32_FILE_ATTRIBUTE_DATA info;
5321 int len;
5323 if (!face->file)
5325 font->fileinfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*font->fileinfo));
5326 return;
5329 len = strlenW(face->file);
5330 font->fileinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*font->fileinfo) + len * sizeof(WCHAR));
5331 if (GetFileAttributesExW(face->file, GetFileExInfoStandard, &info))
5333 font->fileinfo->writetime = info.ftLastWriteTime;
5334 font->fileinfo->size.QuadPart = (LONGLONG)info.nFileSizeHigh << 32 | info.nFileSizeLow;
5335 strcpyW(font->fileinfo->path, face->file);
5337 else
5338 memset(font->fileinfo, 0, sizeof(*font->fileinfo) + len * sizeof(WCHAR));
5341 /*************************************************************
5342 * freetype_SelectFont
5344 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
5346 struct freetype_physdev *physdev = get_freetype_dev( dev );
5347 GdiFont *ret;
5348 Face *face, *best, *best_bitmap;
5349 Family *family, *last_resort_family;
5350 const struct list *face_list;
5351 INT height, width = 0;
5352 unsigned int score = 0, new_score;
5353 signed int diff = 0, newdiff;
5354 BOOL bd, it, can_use_bitmap, want_vertical;
5355 LOGFONTW lf;
5356 CHARSETINFO csi;
5357 FMAT2 dcmat;
5358 FontSubst *psub = NULL;
5359 DC *dc = get_physdev_dc( dev );
5360 const SYSTEM_LINKS *font_link;
5362 if (!hfont) /* notification that the font has been changed by another driver */
5364 release_font( physdev->font );
5365 physdev->font = NULL;
5366 return 0;
5369 GetObjectW( hfont, sizeof(lf), &lf );
5370 lf.lfWidth = abs(lf.lfWidth);
5372 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
5374 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
5375 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
5376 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
5377 lf.lfEscapement);
5379 if(dc->GraphicsMode == GM_ADVANCED)
5381 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
5382 /* Try to avoid not necessary glyph transformations */
5383 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
5385 lf.lfHeight *= fabs(dcmat.eM11);
5386 lf.lfWidth *= fabs(dcmat.eM11);
5387 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
5390 else
5392 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
5393 font scaling abilities. */
5394 dcmat.eM11 = dcmat.eM22 = 1.0;
5395 dcmat.eM21 = dcmat.eM12 = 0;
5396 lf.lfOrientation = lf.lfEscapement;
5397 if (dc->vport2WorldValid)
5399 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
5400 lf.lfOrientation = -lf.lfOrientation;
5401 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
5402 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
5406 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
5407 dcmat.eM21, dcmat.eM22);
5409 GDI_CheckNotLock();
5410 EnterCriticalSection( &freetype_cs );
5412 /* check the cache first */
5413 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5414 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
5415 goto done;
5418 TRACE("not in cache\n");
5419 ret = alloc_font();
5421 ret->font_desc.matrix = dcmat;
5422 ret->font_desc.lf = lf;
5423 ret->font_desc.can_use_bitmap = can_use_bitmap;
5424 calc_hash(&ret->font_desc);
5426 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
5427 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
5428 original value lfCharSet. Note this is a special case for
5429 Symbol and doesn't happen at least for "Wingdings*" */
5431 if(!strcmpiW(lf.lfFaceName, SymbolW))
5432 lf.lfCharSet = SYMBOL_CHARSET;
5434 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
5435 switch(lf.lfCharSet) {
5436 case DEFAULT_CHARSET:
5437 csi.fs.fsCsb[0] = 0;
5438 break;
5439 default:
5440 FIXME("Untranslated charset %d\n", lf.lfCharSet);
5441 csi.fs.fsCsb[0] = 0;
5442 break;
5446 family = NULL;
5447 if(lf.lfFaceName[0] != '\0') {
5448 CHILD_FONT *font_link_entry;
5449 LPWSTR FaceName = lf.lfFaceName;
5451 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
5453 if(psub) {
5454 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
5455 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
5456 if (psub->to.charset != -1)
5457 lf.lfCharSet = psub->to.charset;
5460 /* We want a match on name and charset or just name if
5461 charset was DEFAULT_CHARSET. If the latter then
5462 we fixup the returned charset later in get_nearest_charset
5463 where we'll either use the charset of the current ansi codepage
5464 or if that's unavailable the first charset that the font supports.
5466 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5467 if (!strcmpiW(family->FamilyName, FaceName) ||
5468 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
5470 font_link = find_font_link(family->FamilyName);
5471 face_list = get_face_list_from_family(family);
5472 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5473 if (!(face->scalable || can_use_bitmap))
5474 continue;
5475 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5476 goto found;
5477 if (font_link != NULL &&
5478 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5479 goto found;
5480 if (!csi.fs.fsCsb[0])
5481 goto found;
5486 /* Search by full face name. */
5487 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5488 face_list = get_face_list_from_family(family);
5489 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5490 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
5491 (face->scalable || can_use_bitmap))
5493 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5494 goto found_face;
5495 font_link = find_font_link(family->FamilyName);
5496 if (font_link != NULL &&
5497 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5498 goto found_face;
5504 * Try check the SystemLink list first for a replacement font.
5505 * We may find good replacements there.
5507 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
5509 if(!strcmpiW(font_link->font_name, FaceName) ||
5510 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
5512 TRACE("found entry in system list\n");
5513 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5515 const SYSTEM_LINKS *links;
5517 face = font_link_entry->face;
5518 if (!(face->scalable || can_use_bitmap))
5519 continue;
5520 family = face->family;
5521 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5522 goto found;
5523 links = find_font_link(family->FamilyName);
5524 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
5525 goto found;
5531 psub = NULL; /* substitution is no more relevant */
5533 /* If requested charset was DEFAULT_CHARSET then try using charset
5534 corresponding to the current ansi codepage */
5535 if (!csi.fs.fsCsb[0])
5537 INT acp = GetACP();
5538 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
5539 FIXME("TCI failed on codepage %d\n", acp);
5540 csi.fs.fsCsb[0] = 0;
5541 } else
5542 lf.lfCharSet = csi.ciCharset;
5545 want_vertical = (lf.lfFaceName[0] == '@');
5547 /* Face families are in the top 4 bits of lfPitchAndFamily,
5548 so mask with 0xF0 before testing */
5550 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
5551 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
5552 strcpyW(lf.lfFaceName, defFixed);
5553 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
5554 strcpyW(lf.lfFaceName, defSerif);
5555 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
5556 strcpyW(lf.lfFaceName, defSans);
5557 else
5558 strcpyW(lf.lfFaceName, defSans);
5559 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5560 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
5561 font_link = find_font_link(family->FamilyName);
5562 face_list = get_face_list_from_family(family);
5563 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5564 if (!(face->scalable || can_use_bitmap))
5565 continue;
5566 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5567 goto found;
5568 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5569 goto found;
5574 last_resort_family = NULL;
5575 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5576 font_link = find_font_link(family->FamilyName);
5577 face_list = get_face_list_from_family(family);
5578 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5579 if(!(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical &&
5580 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5581 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
5582 if(face->scalable)
5583 goto found;
5584 if(can_use_bitmap && !last_resort_family)
5585 last_resort_family = family;
5590 if(last_resort_family) {
5591 family = last_resort_family;
5592 csi.fs.fsCsb[0] = 0;
5593 goto found;
5596 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5597 face_list = get_face_list_from_family(family);
5598 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5599 if(face->scalable && !(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical) {
5600 csi.fs.fsCsb[0] = 0;
5601 WARN("just using first face for now\n");
5602 goto found;
5604 if(can_use_bitmap && !last_resort_family)
5605 last_resort_family = family;
5608 if(!last_resort_family) {
5609 FIXME("can't find a single appropriate font - bailing\n");
5610 free_font(ret);
5611 ret = NULL;
5612 goto done;
5615 WARN("could only find a bitmap font - this will probably look awful!\n");
5616 family = last_resort_family;
5617 csi.fs.fsCsb[0] = 0;
5619 found:
5620 it = lf.lfItalic ? 1 : 0;
5621 bd = lf.lfWeight > 550 ? 1 : 0;
5623 height = lf.lfHeight;
5625 face = best = best_bitmap = NULL;
5626 font_link = find_font_link(family->FamilyName);
5627 face_list = get_face_list_from_family(family);
5628 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5630 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5631 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
5632 !csi.fs.fsCsb[0])
5634 BOOL italic, bold;
5636 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
5637 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
5638 new_score = (italic ^ it) + (bold ^ bd);
5639 if(!best || new_score <= score)
5641 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5642 italic, bold, it, bd);
5643 score = new_score;
5644 best = face;
5645 if(best->scalable && score == 0) break;
5646 if(!best->scalable)
5648 if(height > 0)
5649 newdiff = height - (signed int)(best->size.height);
5650 else
5651 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
5652 if(!best_bitmap || new_score < score ||
5653 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
5655 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
5656 diff = newdiff;
5657 best_bitmap = best;
5658 if(score == 0 && diff == 0) break;
5664 if(best)
5665 face = best->scalable ? best : best_bitmap;
5666 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
5667 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
5669 found_face:
5670 height = lf.lfHeight;
5672 ret->fs = face->fs;
5674 if(csi.fs.fsCsb[0]) {
5675 ret->charset = lf.lfCharSet;
5676 ret->codepage = csi.ciACP;
5678 else
5679 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
5681 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
5682 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
5684 ret->aveWidth = height ? lf.lfWidth : 0;
5686 if(!face->scalable) {
5687 /* Windows uses integer scaling factors for bitmap fonts */
5688 INT scale, scaled_height;
5689 GdiFont *cachedfont;
5691 /* FIXME: rotation of bitmap fonts is ignored */
5692 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
5693 if (ret->aveWidth)
5694 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
5695 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
5696 dcmat.eM11 = dcmat.eM22 = 1.0;
5697 /* As we changed the matrix, we need to search the cache for the font again,
5698 * otherwise we might explode the cache. */
5699 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5700 TRACE("Found cached font after non-scalable matrix rescale!\n");
5701 free_font( ret );
5702 ret = cachedfont;
5703 goto done;
5705 calc_hash(&ret->font_desc);
5707 if (height != 0) height = diff;
5708 height += face->size.height;
5710 scale = (height + face->size.height - 1) / face->size.height;
5711 scaled_height = scale * face->size.height;
5712 /* Only jump to the next height if the difference <= 25% original height */
5713 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
5714 /* The jump between unscaled and doubled is delayed by 1 */
5715 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
5716 ret->scale_y = scale;
5718 width = face->size.x_ppem >> 6;
5719 height = face->size.y_ppem >> 6;
5721 else
5722 ret->scale_y = 1.0;
5723 TRACE("font scale y: %f\n", ret->scale_y);
5725 ret->ft_face = OpenFontFace(ret, face, width, height);
5727 if (!ret->ft_face)
5729 free_font( ret );
5730 ret = NULL;
5731 goto done;
5734 fill_fileinfo_from_face( ret, face );
5735 ret->ntmFlags = face->ntmFlags;
5737 pick_charmap( ret->ft_face, ret->charset );
5739 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
5740 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
5741 ret->underline = lf.lfUnderline ? 0xff : 0;
5742 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
5743 create_child_font_list(ret);
5745 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
5747 int length = get_font_data(ret, MS_GSUB_TAG , 0, NULL, 0);
5748 if (length != GDI_ERROR)
5750 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
5751 get_font_data(ret, MS_GSUB_TAG , 0, ret->GSUB_Table, length);
5752 TRACE("Loaded GSUB table of %i bytes\n",length);
5753 ret->vert_feature = get_GSUB_vert_feature(ret);
5754 if (!ret->vert_feature)
5756 TRACE("Vertical feature not found\n");
5757 HeapFree(GetProcessHeap(), 0, ret->GSUB_Table);
5758 ret->GSUB_Table = NULL;
5762 ret->aa_flags = HIWORD( face->flags );
5764 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
5766 add_to_cache(ret);
5767 done:
5768 if (ret)
5770 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
5772 switch (lf.lfQuality)
5774 case NONANTIALIASED_QUALITY:
5775 case ANTIALIASED_QUALITY:
5776 next->funcs->pSelectFont( dev, hfont, aa_flags );
5777 break;
5778 case CLEARTYPE_QUALITY:
5779 case CLEARTYPE_NATURAL_QUALITY:
5780 default:
5781 if (!*aa_flags) *aa_flags = ret->aa_flags;
5782 next->funcs->pSelectFont( dev, hfont, aa_flags );
5784 /* fixup the antialiasing flags for that font */
5785 switch (*aa_flags)
5787 case WINE_GGO_HRGB_BITMAP:
5788 case WINE_GGO_HBGR_BITMAP:
5789 case WINE_GGO_VRGB_BITMAP:
5790 case WINE_GGO_VBGR_BITMAP:
5791 if (is_subpixel_rendering_enabled()) break;
5792 *aa_flags = GGO_GRAY4_BITMAP;
5793 /* fall through */
5794 case GGO_GRAY2_BITMAP:
5795 case GGO_GRAY4_BITMAP:
5796 case GGO_GRAY8_BITMAP:
5797 case WINE_GGO_GRAY16_BITMAP:
5798 if ((!antialias_fakes || (!ret->fake_bold && !ret->fake_italic)) && is_hinting_enabled())
5800 WORD gasp_flags;
5801 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
5803 TRACE( "font %s %d aa disabled by GASP\n",
5804 debugstr_w(lf.lfFaceName), lf.lfHeight );
5805 *aa_flags = GGO_BITMAP;
5810 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5811 release_font( physdev->font );
5812 physdev->font = ret;
5814 LeaveCriticalSection( &freetype_cs );
5815 return ret ? hfont : 0;
5818 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5820 HRSRC rsrc;
5821 HGLOBAL hMem;
5822 WCHAR *p;
5823 int i;
5825 id += IDS_FIRST_SCRIPT;
5826 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5827 if (!rsrc) return 0;
5828 hMem = LoadResource( gdi32_module, rsrc );
5829 if (!hMem) return 0;
5831 p = LockResource( hMem );
5832 id &= 0x000f;
5833 while (id--) p += *p + 1;
5835 i = min(LF_FACESIZE - 1, *p);
5836 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5837 buffer[i] = 0;
5838 return i;
5841 static inline BOOL is_complex_script_ansi_cp(UINT ansi_cp)
5843 return (ansi_cp == 874 /* Thai */
5844 || ansi_cp == 1255 /* Hebrew */
5845 || ansi_cp == 1256 /* Arabic */
5849 /***************************************************
5850 * create_enum_charset_list
5852 * This function creates charset enumeration list because in DEFAULT_CHARSET
5853 * case, the ANSI codepage's charset takes precedence over other charsets.
5854 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
5855 * This function works as a filter other than DEFAULT_CHARSET case.
5857 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5859 CHARSETINFO csi;
5860 DWORD n = 0;
5862 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5863 csi.fs.fsCsb[0] != 0) {
5864 list->element[n].mask = csi.fs.fsCsb[0];
5865 list->element[n].charset = csi.ciCharset;
5866 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5867 n++;
5869 else { /* charset is DEFAULT_CHARSET or invalid. */
5870 INT acp, i;
5871 DWORD mask = 0;
5873 /* Set the current codepage's charset as the first element. */
5874 acp = GetACP();
5875 if (!is_complex_script_ansi_cp(acp) &&
5876 TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5877 csi.fs.fsCsb[0] != 0) {
5878 list->element[n].mask = csi.fs.fsCsb[0];
5879 list->element[n].charset = csi.ciCharset;
5880 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5881 mask |= csi.fs.fsCsb[0];
5882 n++;
5885 /* Fill out left elements. */
5886 for (i = 0; i < 32; i++) {
5887 FONTSIGNATURE fs;
5888 fs.fsCsb[0] = 1L << i;
5889 fs.fsCsb[1] = 0;
5890 if (fs.fsCsb[0] & mask)
5891 continue; /* skip, already added. */
5892 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5893 continue; /* skip, this is an invalid fsCsb bit. */
5895 list->element[n].mask = fs.fsCsb[0];
5896 list->element[n].charset = csi.ciCharset;
5897 load_script_name( i, list->element[n].name );
5898 mask |= fs.fsCsb[0];
5899 n++;
5902 /* add catch all mask for remaining bits */
5903 if (~mask)
5905 list->element[n].mask = ~mask;
5906 list->element[n].charset = DEFAULT_CHARSET;
5907 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5908 n++;
5911 list->total = n;
5913 return n;
5916 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
5917 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5919 GdiFont *font;
5920 LONG width, height;
5922 if (face->cached_enum_data)
5924 TRACE("Cached\n");
5925 *pelf = face->cached_enum_data->elf;
5926 *pntm = face->cached_enum_data->ntm;
5927 *ptype = face->cached_enum_data->type;
5928 return;
5931 font = alloc_font();
5933 if(face->scalable) {
5934 height = 100;
5935 width = 0;
5936 } else {
5937 height = face->size.y_ppem >> 6;
5938 width = face->size.x_ppem >> 6;
5940 font->scale_y = 1.0;
5942 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5944 free_font(font);
5945 return;
5948 font->name = strdupW( family_name );
5949 font->ntmFlags = face->ntmFlags;
5951 if (get_outline_text_metrics(font))
5953 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5955 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5956 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5957 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5959 lstrcpynW(pelf->elfLogFont.lfFaceName,
5960 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5961 LF_FACESIZE);
5962 lstrcpynW(pelf->elfFullName,
5963 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5964 LF_FULLFACESIZE);
5965 lstrcpynW(pelf->elfStyle,
5966 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5967 LF_FACESIZE);
5969 else
5971 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5973 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5974 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5975 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5977 lstrcpynW(pelf->elfLogFont.lfFaceName, family_name, LF_FACESIZE);
5978 if (face->FullName)
5979 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5980 else
5981 lstrcpynW(pelf->elfFullName, family_name, LF_FULLFACESIZE);
5982 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5985 pntm->ntmTm.ntmFlags = face->ntmFlags;
5986 pntm->ntmFontSig = face->fs;
5988 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5990 pelf->elfLogFont.lfEscapement = 0;
5991 pelf->elfLogFont.lfOrientation = 0;
5992 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5993 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5994 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5995 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5996 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5997 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5998 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5999 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
6000 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
6001 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
6002 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
6004 *ptype = 0;
6005 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
6006 *ptype |= TRUETYPE_FONTTYPE;
6007 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
6008 *ptype |= DEVICE_FONTTYPE;
6009 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
6010 *ptype |= RASTER_FONTTYPE;
6012 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
6013 if (face->cached_enum_data)
6015 face->cached_enum_data->elf = *pelf;
6016 face->cached_enum_data->ntm = *pntm;
6017 face->cached_enum_data->type = *ptype;
6020 free_font(font);
6023 static BOOL family_matches(Family *family, const WCHAR *face_name)
6025 Face *face;
6026 const struct list *face_list;
6028 if (!strcmpiW(face_name, family->FamilyName)) return TRUE;
6030 face_list = get_face_list_from_family(family);
6031 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
6032 if (face->FullName && !strcmpiW(face_name, face->FullName)) return TRUE;
6034 return FALSE;
6037 static BOOL face_matches(const WCHAR *family_name, Face *face, const WCHAR *face_name)
6039 if (!strcmpiW(face_name, family_name)) return TRUE;
6041 return (face->FullName && !strcmpiW(face_name, face->FullName));
6044 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
6045 FONTENUMPROCW proc, LPARAM lparam, const WCHAR *subst)
6047 ENUMLOGFONTEXW elf;
6048 NEWTEXTMETRICEXW ntm;
6049 DWORD type = 0;
6050 DWORD i;
6052 GetEnumStructs(face, face->family->FamilyName, &elf, &ntm, &type);
6053 for(i = 0; i < list->total; i++) {
6054 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
6055 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
6056 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
6057 i = list->total; /* break out of loop after enumeration */
6059 else
6061 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
6062 /* use the DEFAULT_CHARSET case only if no other charset is present */
6063 if (list->element[i].charset == DEFAULT_CHARSET &&
6064 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
6065 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
6066 strcpyW(elf.elfScript, list->element[i].name);
6067 if (!elf.elfScript[0])
6068 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
6070 /* Font Replacement */
6071 if (family != face->family)
6073 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
6074 if (face->FullName)
6075 strcpyW(elf.elfFullName, face->FullName);
6076 else
6077 strcpyW(elf.elfFullName, family->FamilyName);
6079 if (subst)
6080 strcpyW(elf.elfLogFont.lfFaceName, subst);
6081 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
6082 debugstr_w(elf.elfLogFont.lfFaceName),
6083 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
6084 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
6085 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
6086 ntm.ntmTm.ntmFlags);
6087 /* release section before callback (FIXME) */
6088 LeaveCriticalSection( &freetype_cs );
6089 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
6090 EnterCriticalSection( &freetype_cs );
6092 return TRUE;
6095 /*************************************************************
6096 * freetype_EnumFonts
6098 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
6100 Family *family;
6101 Face *face;
6102 const struct list *face_list;
6103 LOGFONTW lf;
6104 struct enum_charset_list enum_charsets;
6106 if (!plf)
6108 lf.lfCharSet = DEFAULT_CHARSET;
6109 lf.lfPitchAndFamily = 0;
6110 lf.lfFaceName[0] = 0;
6111 plf = &lf;
6114 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
6116 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
6118 GDI_CheckNotLock();
6119 EnterCriticalSection( &freetype_cs );
6120 if(plf->lfFaceName[0]) {
6121 WCHAR *face_name = plf->lfFaceName;
6122 FontSubst *psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
6124 if(psub) {
6125 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
6126 debugstr_w(psub->to.name));
6127 face_name = psub->to.name;
6130 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
6131 if (!family_matches(family, face_name)) continue;
6132 face_list = get_face_list_from_family(family);
6133 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
6134 if (!face_matches(family->FamilyName, face, face_name)) continue;
6135 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam, psub ? psub->from.name : NULL)) return FALSE;
6138 } else {
6139 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
6140 face_list = get_face_list_from_family(family);
6141 face = LIST_ENTRY(list_head(face_list), Face, entry);
6142 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam, NULL)) return FALSE;
6145 LeaveCriticalSection( &freetype_cs );
6146 return TRUE;
6149 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
6151 pt->x.value = vec->x >> 6;
6152 pt->x.fract = (vec->x & 0x3f) << 10;
6153 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
6154 pt->y.value = vec->y >> 6;
6155 pt->y.fract = (vec->y & 0x3f) << 10;
6156 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
6159 /***************************************************
6160 * According to the MSDN documentation on WideCharToMultiByte,
6161 * certain codepages cannot set the default_used parameter.
6162 * This returns TRUE if the codepage can set that parameter, false else
6163 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
6165 static BOOL codepage_sets_default_used(UINT codepage)
6167 switch (codepage)
6169 case CP_UTF7:
6170 case CP_UTF8:
6171 case CP_SYMBOL:
6172 return FALSE;
6173 default:
6174 return TRUE;
6179 * GSUB Table handling functions
6182 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
6184 const GSUB_CoverageFormat1* cf1;
6186 cf1 = table;
6188 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
6190 int count = GET_BE_WORD(cf1->GlyphCount);
6191 int i;
6192 TRACE("Coverage Format 1, %i glyphs\n",count);
6193 for (i = 0; i < count; i++)
6194 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
6195 return i;
6196 return -1;
6198 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
6200 const GSUB_CoverageFormat2* cf2;
6201 int i;
6202 int count;
6203 cf2 = (const GSUB_CoverageFormat2*)cf1;
6205 count = GET_BE_WORD(cf2->RangeCount);
6206 TRACE("Coverage Format 2, %i ranges\n",count);
6207 for (i = 0; i < count; i++)
6209 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
6210 return -1;
6211 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
6212 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
6214 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
6215 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
6218 return -1;
6220 else
6221 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
6223 return -1;
6226 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
6228 int i;
6229 int offset;
6230 const GSUB_LookupList *lookup;
6231 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
6233 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
6234 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
6236 const GSUB_LookupTable *look;
6237 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
6238 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
6239 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
6240 if (GET_BE_WORD(look->LookupType) != 1)
6241 FIXME("We only handle SubType 1\n");
6242 else
6244 int j;
6246 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
6248 const GSUB_SingleSubstFormat1 *ssf1;
6249 offset = GET_BE_WORD(look->SubTable[j]);
6250 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
6251 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
6253 int offset = GET_BE_WORD(ssf1->Coverage);
6254 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
6255 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
6257 TRACE(" Glyph 0x%x ->",glyph);
6258 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
6259 TRACE(" 0x%x\n",glyph);
6262 else
6264 const GSUB_SingleSubstFormat2 *ssf2;
6265 INT index;
6266 INT offset;
6268 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
6269 offset = GET_BE_WORD(ssf1->Coverage);
6270 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
6271 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
6272 TRACE(" Coverage index %i\n",index);
6273 if (index != -1)
6275 TRACE(" Glyph is 0x%x ->",glyph);
6276 glyph = GET_BE_WORD(ssf2->Substitute[index]);
6277 TRACE("0x%x\n",glyph);
6283 return glyph;
6287 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
6289 const GSUB_Header *header;
6290 const GSUB_Feature *feature;
6292 if (!font->GSUB_Table)
6293 return glyph;
6295 header = font->GSUB_Table;
6296 feature = font->vert_feature;
6298 return GSUB_apply_feature(header, feature, glyph);
6301 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
6303 FT_UInt glyphId;
6305 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
6306 WCHAR wc = (WCHAR)glyph;
6307 BOOL default_used;
6308 BOOL *default_used_pointer;
6309 FT_UInt ret;
6310 char buf;
6311 default_used_pointer = NULL;
6312 default_used = FALSE;
6313 if (codepage_sets_default_used(font->codepage))
6314 default_used_pointer = &default_used;
6315 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
6317 if (font->codepage == CP_SYMBOL && wc < 0x100)
6318 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
6319 else
6320 ret = 0;
6322 else
6323 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
6324 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6325 return ret;
6328 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
6330 if (glyph < 0x100) glyph += 0xf000;
6331 /* there is a number of old pre-Unicode "broken" TTFs, which
6332 do have symbols at U+00XX instead of U+f0XX */
6333 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
6334 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
6336 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
6338 return glyphId;
6341 /* helper for freetype_GetGlyphIndices */
6342 static FT_UInt get_gdi_glyph_index(const GdiFont *font, UINT glyph)
6344 WCHAR wc = (WCHAR)glyph;
6345 BOOL default_used = FALSE;
6346 BOOL *default_used_pointer = NULL;
6347 FT_UInt ret;
6348 char buf;
6350 if(font->ft_face->charmap->encoding != FT_ENCODING_NONE)
6351 return get_glyph_index(font, glyph);
6353 if (codepage_sets_default_used(font->codepage))
6354 default_used_pointer = &default_used;
6355 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer)
6356 || default_used)
6358 if (font->codepage == CP_SYMBOL && wc < 0x100)
6359 ret = (unsigned char)wc;
6360 else
6361 ret = 0;
6363 else
6364 ret = (unsigned char)buf;
6365 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6366 return ret;
6369 static FT_UInt get_default_char_index(GdiFont *font)
6371 FT_UInt default_char;
6373 if (FT_IS_SFNT(font->ft_face))
6375 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
6376 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
6378 else
6380 TEXTMETRICW textm;
6381 get_text_metrics(font, &textm);
6382 default_char = textm.tmDefaultChar;
6385 return default_char;
6388 /*************************************************************
6389 * freetype_GetGlyphIndices
6391 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
6393 struct freetype_physdev *physdev = get_freetype_dev( dev );
6394 int i;
6395 WORD default_char;
6396 BOOL got_default = FALSE;
6398 if (!physdev->font)
6400 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
6401 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
6404 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
6406 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
6407 got_default = TRUE;
6410 GDI_CheckNotLock();
6411 EnterCriticalSection( &freetype_cs );
6413 for(i = 0; i < count; i++)
6415 pgi[i] = get_gdi_glyph_index(physdev->font, lpstr[i]);
6416 if (pgi[i] == 0)
6418 if (!got_default)
6420 default_char = get_default_char_index(physdev->font);
6421 got_default = TRUE;
6423 pgi[i] = default_char;
6425 else
6426 pgi[i] = get_GSUB_vert_glyph(physdev->font, pgi[i]);
6428 LeaveCriticalSection( &freetype_cs );
6429 return count;
6432 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
6434 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
6435 return !memcmp(matrix, &identity, sizeof(FMAT2));
6438 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
6440 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
6441 return !memcmp(matrix, &identity, sizeof(MAT2));
6444 static inline FT_Vector normalize_vector(FT_Vector *vec)
6446 FT_Vector out;
6447 FT_Fixed len;
6448 len = pFT_Vector_Length(vec);
6449 if (len) {
6450 out.x = (vec->x << 6) / len;
6451 out.y = (vec->y << 6) / len;
6453 else
6454 out.x = out.y = 0;
6455 return out;
6458 static BOOL get_bold_glyph_outline(FT_GlyphSlot glyph, LONG ppem, FT_Glyph_Metrics *metrics)
6460 FT_Error err;
6461 FT_Pos strength;
6462 FT_BBox bbox;
6464 if(glyph->format != FT_GLYPH_FORMAT_OUTLINE)
6465 return FALSE;
6466 if(!pFT_Outline_Embolden)
6467 return FALSE;
6469 strength = MulDiv(ppem, 1 << 6, 24);
6470 err = pFT_Outline_Embolden(&glyph->outline, strength);
6471 if(err) {
6472 TRACE("FT_Ouline_Embolden returns %d\n", err);
6473 return FALSE;
6476 pFT_Outline_Get_CBox(&glyph->outline, &bbox);
6477 metrics->width = bbox.xMax - bbox.xMin;
6478 metrics->height = bbox.yMax - bbox.yMin;
6479 metrics->horiBearingX = bbox.xMin;
6480 metrics->horiBearingY = bbox.yMax;
6481 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
6482 metrics->vertBearingY = (metrics->vertAdvance - metrics->height) / 2;
6483 return TRUE;
6486 static inline BYTE get_max_level( UINT format )
6488 switch( format )
6490 case GGO_GRAY2_BITMAP: return 4;
6491 case GGO_GRAY4_BITMAP: return 16;
6492 case GGO_GRAY8_BITMAP: return 64;
6494 return 255;
6497 extern const unsigned short vertical_orientation_table[] DECLSPEC_HIDDEN;
6499 static BOOL check_unicode_tategaki(WCHAR uchar)
6501 unsigned short orientation = vertical_orientation_table[vertical_orientation_table[vertical_orientation_table[uchar >> 8]+((uchar >> 4) & 0x0f)]+ (uchar & 0xf)];
6503 /* We only reach this code if typographical substitution did not occur */
6504 /* Type: U or Type: Tu */
6505 return (orientation == 1 || orientation == 3);
6508 static FT_Vector get_advance_metric(GdiFont *incoming_font, GdiFont *font,
6509 const FT_Glyph_Metrics *metrics,
6510 const FT_Matrix *transMat, BOOL vertical_metrics)
6512 FT_Vector adv;
6513 FT_Fixed base_advance, em_scale = 0;
6514 BOOL fixed_pitch_full = FALSE;
6516 if (vertical_metrics)
6517 base_advance = metrics->vertAdvance;
6518 else
6519 base_advance = metrics->horiAdvance;
6521 adv.x = base_advance;
6522 adv.y = 0;
6524 /* In fixed-pitch font, we adjust the fullwidth character advance so that
6525 they have double halfwidth character width. E.g. if the font is 19 ppem,
6526 we return 20 (not 19) for fullwidth characters as we return 10 for
6527 halfwidth characters. */
6528 if(FT_IS_SCALABLE(incoming_font->ft_face) &&
6529 (incoming_font->potm || get_outline_text_metrics(incoming_font)) &&
6530 !(incoming_font->potm->otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
6531 UINT avg_advance;
6532 em_scale = MulDiv(incoming_font->ppem, 1 << 16,
6533 incoming_font->ft_face->units_per_EM);
6534 avg_advance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
6535 fixed_pitch_full = (avg_advance > 0 &&
6536 (base_advance + 63) >> 6 ==
6537 pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale));
6538 if (fixed_pitch_full && !transMat)
6539 adv.x = (avg_advance * 2) << 6;
6542 if (transMat) {
6543 pFT_Vector_Transform(&adv, transMat);
6544 if (fixed_pitch_full && adv.y == 0) {
6545 FT_Vector vec;
6546 vec.x = incoming_font->ntmAvgWidth;
6547 vec.y = 0;
6548 pFT_Vector_Transform(&vec, transMat);
6549 adv.x = (pFT_MulFix(vec.x, em_scale) * 2) << 6;
6553 if (font->fake_bold) {
6554 if (!transMat)
6555 adv.x += 1 << 6;
6556 else {
6557 FT_Vector fake_bold_adv, vec = { 1 << 6, 0 };
6558 pFT_Vector_Transform(&vec, transMat);
6559 fake_bold_adv = normalize_vector(&vec);
6560 adv.x += fake_bold_adv.x;
6561 adv.y += fake_bold_adv.y;
6565 adv.x = (adv.x + 63) & -64;
6566 adv.y = -((adv.y + 63) & -64);
6567 return adv;
6570 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
6572 TTPOLYGONHEADER *pph;
6573 TTPOLYCURVE *ppc;
6574 unsigned int needed = 0, point = 0, contour, first_pt;
6575 unsigned int pph_start, cpfx;
6576 DWORD type;
6578 for (contour = 0; contour < outline->n_contours; contour++)
6580 /* Ignore contours containing one point */
6581 if (point == outline->contours[contour])
6583 point++;
6584 continue;
6587 pph_start = needed;
6588 pph = (TTPOLYGONHEADER *)(buf + needed);
6589 first_pt = point;
6590 if (buf)
6592 pph->dwType = TT_POLYGON_TYPE;
6593 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6595 needed += sizeof(*pph);
6596 point++;
6597 while (point <= outline->contours[contour])
6599 ppc = (TTPOLYCURVE *)(buf + needed);
6600 type = outline->tags[point] & FT_Curve_Tag_On ?
6601 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6602 cpfx = 0;
6605 if (buf)
6606 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6607 cpfx++;
6608 point++;
6609 } while (point <= outline->contours[contour] &&
6610 (outline->tags[point] & FT_Curve_Tag_On) ==
6611 (outline->tags[point-1] & FT_Curve_Tag_On));
6612 /* At the end of a contour Windows adds the start point, but
6613 only for Beziers */
6614 if (point > outline->contours[contour] &&
6615 !(outline->tags[point-1] & FT_Curve_Tag_On))
6617 if (buf)
6618 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6619 cpfx++;
6621 else if (point <= outline->contours[contour] &&
6622 outline->tags[point] & FT_Curve_Tag_On)
6624 /* add closing pt for bezier */
6625 if (buf)
6626 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6627 cpfx++;
6628 point++;
6630 if (buf)
6632 ppc->wType = type;
6633 ppc->cpfx = cpfx;
6635 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6637 if (buf)
6638 pph->cb = needed - pph_start;
6640 return needed;
6643 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
6645 /* Convert the quadratic Beziers to cubic Beziers.
6646 The parametric eqn for a cubic Bezier is, from PLRM:
6647 r(t) = at^3 + bt^2 + ct + r0
6648 with the control points:
6649 r1 = r0 + c/3
6650 r2 = r1 + (c + b)/3
6651 r3 = r0 + c + b + a
6653 A quadratic Bezier has the form:
6654 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6656 So equating powers of t leads to:
6657 r1 = 2/3 p1 + 1/3 p0
6658 r2 = 2/3 p1 + 1/3 p2
6659 and of course r0 = p0, r3 = p2
6661 int contour, point = 0, first_pt;
6662 TTPOLYGONHEADER *pph;
6663 TTPOLYCURVE *ppc;
6664 DWORD pph_start, cpfx, type;
6665 FT_Vector cubic_control[4];
6666 unsigned int needed = 0;
6668 for (contour = 0; contour < outline->n_contours; contour++)
6670 pph_start = needed;
6671 pph = (TTPOLYGONHEADER *)(buf + needed);
6672 first_pt = point;
6673 if (buf)
6675 pph->dwType = TT_POLYGON_TYPE;
6676 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6678 needed += sizeof(*pph);
6679 point++;
6680 while (point <= outline->contours[contour])
6682 ppc = (TTPOLYCURVE *)(buf + needed);
6683 type = outline->tags[point] & FT_Curve_Tag_On ?
6684 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6685 cpfx = 0;
6688 if (type == TT_PRIM_LINE)
6690 if (buf)
6691 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6692 cpfx++;
6693 point++;
6695 else
6697 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6698 so cpfx = 3n */
6700 /* FIXME: Possible optimization in endpoint calculation
6701 if there are two consecutive curves */
6702 cubic_control[0] = outline->points[point-1];
6703 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
6705 cubic_control[0].x += outline->points[point].x + 1;
6706 cubic_control[0].y += outline->points[point].y + 1;
6707 cubic_control[0].x >>= 1;
6708 cubic_control[0].y >>= 1;
6710 if (point+1 > outline->contours[contour])
6711 cubic_control[3] = outline->points[first_pt];
6712 else
6714 cubic_control[3] = outline->points[point+1];
6715 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
6717 cubic_control[3].x += outline->points[point].x + 1;
6718 cubic_control[3].y += outline->points[point].y + 1;
6719 cubic_control[3].x >>= 1;
6720 cubic_control[3].y >>= 1;
6723 /* r1 = 1/3 p0 + 2/3 p1
6724 r2 = 1/3 p2 + 2/3 p1 */
6725 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6726 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6727 cubic_control[2] = cubic_control[1];
6728 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6729 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6730 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6731 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6732 if (buf)
6734 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6735 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6736 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6738 cpfx += 3;
6739 point++;
6741 } while (point <= outline->contours[contour] &&
6742 (outline->tags[point] & FT_Curve_Tag_On) ==
6743 (outline->tags[point-1] & FT_Curve_Tag_On));
6744 /* At the end of a contour Windows adds the start point,
6745 but only for Beziers and we've already done that.
6747 if (point <= outline->contours[contour] &&
6748 outline->tags[point] & FT_Curve_Tag_On)
6750 /* This is the closing pt of a bezier, but we've already
6751 added it, so just inc point and carry on */
6752 point++;
6754 if (buf)
6756 ppc->wType = type;
6757 ppc->cpfx = cpfx;
6759 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6761 if (buf)
6762 pph->cb = needed - pph_start;
6764 return needed;
6767 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6769 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
6770 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
6771 const MAT2* lpmat)
6773 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
6774 GLYPHMETRICS gm;
6775 FT_Face ft_face = incoming_font->ft_face;
6776 GdiFont *font = incoming_font;
6777 FT_Glyph_Metrics metrics;
6778 FT_UInt glyph_index;
6779 DWORD width, height, pitch, needed = 0;
6780 FT_Bitmap ft_bitmap;
6781 FT_Error err;
6782 INT left, right, top = 0, bottom = 0;
6783 FT_Vector adv;
6784 INT origin_x = 0, origin_y = 0;
6785 FT_Angle angle = 0;
6786 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
6787 double widthRatio = 1.0;
6788 FT_Matrix transMat = identityMat;
6789 FT_Matrix transMatUnrotated;
6790 FT_Matrix transMatTategaki;
6791 BOOL needsTransform = FALSE;
6792 BOOL tategaki = (font->name[0] == '@');
6793 BOOL vertical_metrics;
6794 UINT original_index;
6796 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
6797 buflen, buf, lpmat);
6799 TRACE("font transform %f %f %f %f\n",
6800 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
6801 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
6803 if(format & GGO_GLYPH_INDEX) {
6804 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
6805 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
6806 as glyph index. "Treasure Adventure Game" depends on this. */
6807 glyph_index = pFT_Get_Char_Index(font->ft_face, glyph);
6808 TRACE("translate glyph index %04x -> %04x\n", glyph, glyph_index);
6809 } else
6810 glyph_index = glyph;
6811 original_index = glyph_index;
6812 format &= ~GGO_GLYPH_INDEX;
6813 /* TODO: Window also turns off tategaki for glyphs passed in by index
6814 if their unicode code points fall outside of the range that is
6815 rotated. */
6816 } else {
6817 BOOL vert;
6818 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index, &vert);
6819 ft_face = font->ft_face;
6820 original_index = glyph_index;
6821 if (!vert && tategaki)
6822 tategaki = check_unicode_tategaki(glyph);
6825 if(format & GGO_UNHINTED) {
6826 load_flags |= FT_LOAD_NO_HINTING;
6827 format &= ~GGO_UNHINTED;
6830 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
6831 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
6832 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
6833 font->gmsize * sizeof(GM*));
6834 } else {
6835 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
6836 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
6838 *lpgm = FONT_GM(font,original_index)->gm;
6839 *abc = FONT_GM(font,original_index)->abc;
6840 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6841 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6842 lpgm->gmCellIncX, lpgm->gmCellIncY);
6843 return 1; /* FIXME */
6847 if (!font->gm[original_index / GM_BLOCK_SIZE])
6848 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
6850 /* Scaling factor */
6851 if (font->aveWidth)
6853 TEXTMETRICW tm;
6855 get_text_metrics(font, &tm);
6857 widthRatio = (double)font->aveWidth;
6858 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6860 else
6861 widthRatio = font->scale_y;
6863 /* Scaling transform */
6864 if (widthRatio != 1.0 || font->scale_y != 1.0)
6866 FT_Matrix scaleMat;
6867 scaleMat.xx = FT_FixedFromFloat(widthRatio);
6868 scaleMat.xy = 0;
6869 scaleMat.yx = 0;
6870 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
6872 pFT_Matrix_Multiply(&scaleMat, &transMat);
6873 needsTransform = TRUE;
6876 /* Slant transform */
6877 if (font->fake_italic) {
6878 FT_Matrix slantMat;
6880 slantMat.xx = (1 << 16);
6881 slantMat.xy = ((1 << 16) >> 2);
6882 slantMat.yx = 0;
6883 slantMat.yy = (1 << 16);
6884 pFT_Matrix_Multiply(&slantMat, &transMat);
6885 needsTransform = TRUE;
6888 /* Rotation transform */
6889 transMatUnrotated = transMat;
6890 transMatTategaki = transMat;
6891 if(font->orientation || tategaki) {
6892 FT_Matrix rotationMat;
6893 FT_Matrix taterotationMat;
6894 FT_Vector vecAngle;
6896 double orient = font->orientation / 10.0;
6897 double tate_orient = 0.f;
6899 if (tategaki)
6900 tate_orient = ((font->orientation+900)%3600)/10.0;
6901 else
6902 tate_orient = font->orientation/10.0;
6904 if (orient)
6906 angle = FT_FixedFromFloat(orient);
6907 pFT_Vector_Unit(&vecAngle, angle);
6908 rotationMat.xx = vecAngle.x;
6909 rotationMat.xy = -vecAngle.y;
6910 rotationMat.yx = -rotationMat.xy;
6911 rotationMat.yy = rotationMat.xx;
6913 pFT_Matrix_Multiply(&rotationMat, &transMat);
6916 if (tate_orient)
6918 angle = FT_FixedFromFloat(tate_orient);
6919 pFT_Vector_Unit(&vecAngle, angle);
6920 taterotationMat.xx = vecAngle.x;
6921 taterotationMat.xy = -vecAngle.y;
6922 taterotationMat.yx = -taterotationMat.xy;
6923 taterotationMat.yy = taterotationMat.xx;
6924 pFT_Matrix_Multiply(&taterotationMat, &transMatTategaki);
6927 needsTransform = TRUE;
6930 /* World transform */
6931 if (!is_identity_FMAT2(&font->font_desc.matrix))
6933 FT_Matrix worldMat;
6934 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
6935 worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21);
6936 worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12);
6937 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
6938 pFT_Matrix_Multiply(&worldMat, &transMat);
6939 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
6940 pFT_Matrix_Multiply(&worldMat, &transMatTategaki);
6941 needsTransform = TRUE;
6944 /* Extra transformation specified by caller */
6945 if (!is_identity_MAT2(lpmat))
6947 FT_Matrix extraMat;
6948 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
6949 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
6950 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
6951 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
6952 pFT_Matrix_Multiply(&extraMat, &transMat);
6953 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
6954 pFT_Matrix_Multiply(&extraMat, &transMatTategaki);
6955 needsTransform = TRUE;
6958 vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face));
6959 /* there is a freetype bug where vertical metrics are only
6960 properly scaled and correct in 2.4.0 or greater */
6961 if ((vertical_metrics) && (FT_Version.major < 2 || (FT_Version.major == 2 && FT_Version.minor < 4)))
6962 vertical_metrics = FALSE;
6964 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
6965 if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
6967 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
6969 if(err) {
6970 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
6971 return GDI_ERROR;
6974 metrics = ft_face->glyph->metrics;
6975 if(font->fake_bold) {
6976 if (!get_bold_glyph_outline(ft_face->glyph, font->ppem, &metrics) && metrics.width)
6977 metrics.width += 1 << 6;
6980 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6981 * by the text metrics. The proper behavior is to clip the glyph metrics to
6982 * fit within the maximums specified in the text metrics. */
6983 if(incoming_font->potm || get_outline_text_metrics(incoming_font) ||
6984 get_bitmap_text_metrics(incoming_font)) {
6985 TEXTMETRICW *ptm = &incoming_font->potm->otmTextMetrics;
6986 top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
6987 bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
6988 metrics.horiBearingY = top;
6989 metrics.height = top - bottom;
6991 /* TODO: Are we supposed to clip the width as well...? */
6992 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6995 if(!needsTransform) {
6996 left = (INT)(metrics.horiBearingX) & -64;
6997 right = (INT)((metrics.horiBearingX + metrics.width) + 63) & -64;
6998 top = (metrics.horiBearingY + 63) & -64;
6999 bottom = (metrics.horiBearingY - metrics.height) & -64;
7000 adv = get_advance_metric(incoming_font, font, &metrics, NULL, vertical_metrics);
7001 gm.gmCellIncX = adv.x >> 6;
7002 gm.gmCellIncY = 0;
7003 origin_x = left;
7004 origin_y = top;
7005 abc->abcA = origin_x >> 6;
7006 abc->abcB = metrics.width >> 6;
7007 } else {
7008 INT xc, yc;
7009 FT_Vector vec;
7010 FT_Pos lsb;
7012 left = right = 0;
7014 for(xc = 0; xc < 2; xc++) {
7015 for(yc = 0; yc < 2; yc++) {
7016 vec.x = metrics.horiBearingX + xc * metrics.width;
7017 vec.y = metrics.horiBearingY - yc * metrics.height;
7018 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
7019 pFT_Vector_Transform(&vec, &transMatTategaki);
7020 if(xc == 0 && yc == 0) {
7021 left = right = vec.x;
7022 top = bottom = vec.y;
7023 } else {
7024 if(vec.x < left) left = vec.x;
7025 else if(vec.x > right) right = vec.x;
7026 if(vec.y < bottom) bottom = vec.y;
7027 else if(vec.y > top) top = vec.y;
7031 left = left & -64;
7032 right = (right + 63) & -64;
7033 bottom = bottom & -64;
7034 top = (top + 63) & -64;
7036 if (tategaki && (font->potm || get_outline_text_metrics(font)))
7038 if (vertical_metrics)
7039 lsb = metrics.horiBearingY + metrics.vertBearingY;
7040 else
7041 lsb = metrics.vertAdvance + (font->potm->otmDescent << 6);
7042 vec.x = lsb;
7043 vec.y = font->potm->otmDescent << 6;
7044 TRACE ("Vec %ld,%ld\n", vec.x>>6, vec.y>>6);
7045 pFT_Vector_Transform(&vec, &transMat);
7046 origin_x = (vec.x + left) & -64;
7047 origin_y = (vec.y + top + 63) & -64;
7049 else
7051 origin_x = left;
7052 origin_y = top;
7053 lsb = metrics.horiBearingX;
7056 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
7057 adv = get_advance_metric(incoming_font, font, &metrics, &transMat, vertical_metrics);
7058 gm.gmCellIncX = adv.x >> 6;
7059 gm.gmCellIncY = adv.y >> 6;
7061 adv = get_advance_metric(incoming_font, font, &metrics, &transMatUnrotated, vertical_metrics);
7063 vec.x = lsb;
7064 vec.y = 0;
7065 pFT_Vector_Transform(&vec, &transMatUnrotated);
7066 abc->abcA = vec.x >> 6;
7068 vec.x = metrics.width;
7069 vec.y = 0;
7070 pFT_Vector_Transform(&vec, &transMatUnrotated);
7071 if (vec.x >= 0)
7072 abc->abcB = vec.x >> 6;
7073 else
7074 abc->abcB = -vec.x >> 6;
7077 width = (right - left) >> 6;
7078 height = (top - bottom) >> 6;
7079 gm.gmBlackBoxX = width ? width : 1;
7080 gm.gmBlackBoxY = height ? height : 1;
7081 gm.gmptGlyphOrigin.x = origin_x >> 6;
7082 gm.gmptGlyphOrigin.y = origin_y >> 6;
7083 if (!abc->abcB) abc->abcB = 1;
7084 abc->abcC = (adv.x >> 6) - abc->abcA - abc->abcB;
7086 TRACE("%u,%u,%s,%d,%d\n", gm.gmBlackBoxX, gm.gmBlackBoxY,
7087 wine_dbgstr_point(&gm.gmptGlyphOrigin),
7088 gm.gmCellIncX, gm.gmCellIncY);
7090 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
7091 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
7093 FONT_GM(font,original_index)->gm = gm;
7094 FONT_GM(font,original_index)->abc = *abc;
7095 FONT_GM(font,original_index)->init = TRUE;
7098 if(format == GGO_METRICS)
7100 *lpgm = gm;
7101 return 1; /* FIXME */
7104 if(ft_face->glyph->format != ft_glyph_format_outline &&
7105 (format == GGO_NATIVE || format == GGO_BEZIER))
7107 TRACE("loaded a bitmap\n");
7108 return GDI_ERROR;
7111 switch(format) {
7112 case GGO_BITMAP:
7113 pitch = ((width + 31) >> 5) << 2;
7114 needed = pitch * height;
7116 if(!buf || !buflen) break;
7117 if (!needed) return GDI_ERROR; /* empty glyph */
7118 if (needed > buflen)
7119 return GDI_ERROR;
7121 switch(ft_face->glyph->format) {
7122 case ft_glyph_format_bitmap:
7124 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
7125 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
7126 INT h = min( height, ft_face->glyph->bitmap.rows );
7127 while(h--) {
7128 if (!font->fake_bold)
7129 memcpy(dst, src, w);
7130 else {
7131 INT x;
7132 dst[0] = 0;
7133 for (x = 0; x < w; x++) {
7134 dst[x ] = (dst[x] & 0x80) | (src[x] >> 1) | src[x];
7135 if (x+1 < pitch)
7136 dst[x+1] = (src[x] & 0x01) << 7;
7139 src += ft_face->glyph->bitmap.pitch;
7140 dst += pitch;
7142 break;
7145 case ft_glyph_format_outline:
7146 ft_bitmap.width = width;
7147 ft_bitmap.rows = height;
7148 ft_bitmap.pitch = pitch;
7149 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
7150 ft_bitmap.buffer = buf;
7152 if(needsTransform)
7153 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
7155 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
7157 /* Note: FreeType will only set 'black' bits for us. */
7158 memset(buf, 0, needed);
7159 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
7160 break;
7162 default:
7163 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
7164 return GDI_ERROR;
7166 break;
7168 case GGO_GRAY2_BITMAP:
7169 case GGO_GRAY4_BITMAP:
7170 case GGO_GRAY8_BITMAP:
7171 case WINE_GGO_GRAY16_BITMAP:
7173 unsigned int max_level, row, col;
7174 BYTE *start, *ptr;
7176 pitch = (width + 3) / 4 * 4;
7177 needed = pitch * height;
7179 if(!buf || !buflen) break;
7180 if (!needed) return GDI_ERROR; /* empty glyph */
7181 if (needed > buflen)
7182 return GDI_ERROR;
7184 max_level = get_max_level( format );
7186 switch(ft_face->glyph->format) {
7187 case ft_glyph_format_bitmap:
7189 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
7190 INT h = min( height, ft_face->glyph->bitmap.rows );
7191 INT x;
7192 memset( buf, 0, needed );
7193 while(h--) {
7194 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++) {
7195 if (src[x / 8] & masks[x % 8]) {
7196 dst[x] = max_level;
7197 if (font->fake_bold && x+1 < pitch) dst[x+1] = max_level;
7200 src += ft_face->glyph->bitmap.pitch;
7201 dst += pitch;
7203 break;
7205 case ft_glyph_format_outline:
7207 ft_bitmap.width = width;
7208 ft_bitmap.rows = height;
7209 ft_bitmap.pitch = pitch;
7210 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
7211 ft_bitmap.buffer = buf;
7213 if(needsTransform)
7214 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
7216 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
7218 memset(ft_bitmap.buffer, 0, buflen);
7220 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
7222 if (max_level != 255)
7224 for (row = 0, start = buf; row < height; row++)
7226 for (col = 0, ptr = start; col < width; col++, ptr++)
7227 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
7228 start += pitch;
7231 break;
7234 default:
7235 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
7236 return GDI_ERROR;
7238 break;
7241 case WINE_GGO_HRGB_BITMAP:
7242 case WINE_GGO_HBGR_BITMAP:
7243 case WINE_GGO_VRGB_BITMAP:
7244 case WINE_GGO_VBGR_BITMAP:
7245 #ifdef FT_LCD_FILTER_H
7247 switch (ft_face->glyph->format)
7249 case FT_GLYPH_FORMAT_BITMAP:
7251 BYTE *src, *dst;
7252 INT src_pitch, x;
7254 pitch = width * 4;
7255 needed = pitch * height;
7257 if (!buf || !buflen) break;
7258 if (!needed) return GDI_ERROR; /* empty glyph */
7259 if (needed > buflen)
7260 return GDI_ERROR;
7262 memset(buf, 0, buflen);
7263 dst = buf;
7264 src = ft_face->glyph->bitmap.buffer;
7265 src_pitch = ft_face->glyph->bitmap.pitch;
7267 height = min( height, ft_face->glyph->bitmap.rows );
7268 while ( height-- )
7270 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
7272 if ( src[x / 8] & masks[x % 8] )
7274 ((unsigned int *)dst)[x] = ~0u;
7275 if (font->fake_bold && x+1 < width) ((unsigned int *)dst)[x+1] = ~0u;
7278 src += src_pitch;
7279 dst += pitch;
7282 break;
7285 case FT_GLYPH_FORMAT_OUTLINE:
7287 unsigned int *dst;
7288 BYTE *src;
7289 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
7290 INT x_shift, y_shift;
7291 BOOL rgb;
7292 FT_Render_Mode render_mode =
7293 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
7294 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
7296 if (!width || !height)
7298 if (!buf || !buflen) break;
7299 return GDI_ERROR;
7302 if ( render_mode == FT_RENDER_MODE_LCD)
7304 gm.gmBlackBoxX += 2;
7305 gm.gmptGlyphOrigin.x -= 1;
7306 left -= (1 << 6);
7308 else
7310 gm.gmBlackBoxY += 2;
7311 gm.gmptGlyphOrigin.y += 1;
7312 top += (1 << 6);
7315 width = gm.gmBlackBoxX;
7316 height = gm.gmBlackBoxY;
7317 pitch = width * 4;
7318 needed = pitch * height;
7320 if (!buf || !buflen) break;
7321 if (needed > buflen)
7322 return GDI_ERROR;
7324 memset(buf, 0, buflen);
7325 dst = buf;
7326 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
7328 if ( needsTransform )
7329 pFT_Outline_Transform (&ft_face->glyph->outline, &transMatTategaki);
7331 if ( pFT_Library_SetLcdFilter )
7332 pFT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT );
7333 pFT_Render_Glyph (ft_face->glyph, render_mode);
7335 src = ft_face->glyph->bitmap.buffer;
7336 src_pitch = ft_face->glyph->bitmap.pitch;
7337 src_width = ft_face->glyph->bitmap.width;
7338 src_height = ft_face->glyph->bitmap.rows;
7340 if ( render_mode == FT_RENDER_MODE_LCD)
7342 rgb_interval = 1;
7343 hmul = 3;
7344 vmul = 1;
7346 else
7348 rgb_interval = src_pitch;
7349 hmul = 1;
7350 vmul = 3;
7353 x_shift = ft_face->glyph->bitmap_left - (left >> 6);
7354 if ( x_shift < 0 )
7356 src += hmul * -x_shift;
7357 src_width -= hmul * -x_shift;
7359 else if ( x_shift > 0 )
7361 dst += x_shift;
7362 width -= x_shift;
7365 y_shift = (top >> 6) - ft_face->glyph->bitmap_top;
7366 if ( y_shift < 0 )
7368 src += src_pitch * vmul * -y_shift;
7369 src_height -= vmul * -y_shift;
7371 else if ( y_shift > 0 )
7373 dst += y_shift * ( pitch / sizeof(*dst) );
7374 height -= y_shift;
7377 width = min( width, src_width / hmul );
7378 height = min( height, src_height / vmul );
7380 while ( height-- )
7382 for ( x = 0; x < width; x++ )
7384 if ( rgb )
7386 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
7387 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
7388 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
7389 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
7391 else
7393 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
7394 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
7395 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
7396 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
7399 src += src_pitch * vmul;
7400 dst += pitch / sizeof(*dst);
7403 break;
7406 default:
7407 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
7408 return GDI_ERROR;
7411 break;
7413 #else
7414 return GDI_ERROR;
7415 #endif
7417 case GGO_NATIVE:
7419 FT_Outline *outline = &ft_face->glyph->outline;
7421 if(buflen == 0) buf = NULL;
7423 if (needsTransform && buf)
7424 pFT_Outline_Transform(outline, &transMatTategaki);
7426 needed = get_native_glyph_outline(outline, buflen, NULL);
7428 if (!buf || !buflen)
7429 break;
7430 if (needed > buflen)
7431 return GDI_ERROR;
7433 get_native_glyph_outline(outline, buflen, buf);
7434 break;
7436 case GGO_BEZIER:
7438 FT_Outline *outline = &ft_face->glyph->outline;
7439 if(buflen == 0) buf = NULL;
7441 if (needsTransform && buf)
7442 pFT_Outline_Transform(outline, &transMat);
7444 needed = get_bezier_glyph_outline(outline, buflen, NULL);
7446 if (!buf || !buflen)
7447 break;
7448 if (needed > buflen)
7449 return GDI_ERROR;
7451 get_bezier_glyph_outline(outline, buflen, buf);
7452 break;
7455 default:
7456 FIXME("Unsupported format %d\n", format);
7457 return GDI_ERROR;
7459 *lpgm = gm;
7460 return needed;
7463 static BOOL get_bitmap_text_metrics(GdiFont *font)
7465 FT_Face ft_face = font->ft_face;
7466 FT_WinFNT_HeaderRec winfnt_header;
7467 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
7468 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
7469 font->potm->otmSize = size;
7471 #define TM font->potm->otmTextMetrics
7472 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
7474 TM.tmHeight = winfnt_header.pixel_height;
7475 TM.tmAscent = winfnt_header.ascent;
7476 TM.tmDescent = TM.tmHeight - TM.tmAscent;
7477 TM.tmInternalLeading = winfnt_header.internal_leading;
7478 TM.tmExternalLeading = winfnt_header.external_leading;
7479 TM.tmAveCharWidth = winfnt_header.avg_width;
7480 TM.tmMaxCharWidth = winfnt_header.max_width;
7481 TM.tmWeight = winfnt_header.weight;
7482 TM.tmOverhang = 0;
7483 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
7484 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
7485 TM.tmFirstChar = winfnt_header.first_char;
7486 TM.tmLastChar = winfnt_header.last_char;
7487 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
7488 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
7489 TM.tmItalic = winfnt_header.italic;
7490 TM.tmUnderlined = font->underline;
7491 TM.tmStruckOut = font->strikeout;
7492 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
7493 TM.tmCharSet = winfnt_header.charset;
7495 else
7497 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
7498 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
7499 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7500 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
7501 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
7502 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
7503 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
7504 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
7505 TM.tmOverhang = 0;
7506 TM.tmDigitizedAspectX = 96; /* FIXME */
7507 TM.tmDigitizedAspectY = 96; /* FIXME */
7508 TM.tmFirstChar = 1;
7509 TM.tmLastChar = 255;
7510 TM.tmDefaultChar = 32;
7511 TM.tmBreakChar = 32;
7512 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
7513 TM.tmUnderlined = font->underline;
7514 TM.tmStruckOut = font->strikeout;
7515 /* NB inverted meaning of TMPF_FIXED_PITCH */
7516 TM.tmPitchAndFamily = FT_IS_FIXED_WIDTH(ft_face) ? 0 : TMPF_FIXED_PITCH;
7517 TM.tmCharSet = font->charset;
7519 #undef TM
7521 return TRUE;
7525 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
7527 double scale_x, scale_y;
7529 if (font->aveWidth)
7531 scale_x = (double)font->aveWidth;
7532 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7534 else
7535 scale_x = font->scale_y;
7537 scale_x *= fabs(font->font_desc.matrix.eM11);
7538 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7540 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7541 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7543 SCALE_Y(ptm->tmHeight);
7544 SCALE_Y(ptm->tmAscent);
7545 SCALE_Y(ptm->tmDescent);
7546 SCALE_Y(ptm->tmInternalLeading);
7547 SCALE_Y(ptm->tmExternalLeading);
7548 SCALE_Y(ptm->tmOverhang);
7550 SCALE_X(ptm->tmAveCharWidth);
7551 SCALE_X(ptm->tmMaxCharWidth);
7553 #undef SCALE_X
7554 #undef SCALE_Y
7557 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
7559 double scale_x, scale_y;
7561 if (font->aveWidth)
7563 scale_x = (double)font->aveWidth;
7564 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7566 else
7567 scale_x = font->scale_y;
7569 scale_x *= fabs(font->font_desc.matrix.eM11);
7570 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7572 scale_font_metrics(font, &potm->otmTextMetrics);
7574 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7575 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7577 SCALE_Y(potm->otmAscent);
7578 SCALE_Y(potm->otmDescent);
7579 SCALE_Y(potm->otmLineGap);
7580 SCALE_Y(potm->otmsCapEmHeight);
7581 SCALE_Y(potm->otmsXHeight);
7582 SCALE_Y(potm->otmrcFontBox.top);
7583 SCALE_Y(potm->otmrcFontBox.bottom);
7584 SCALE_X(potm->otmrcFontBox.left);
7585 SCALE_X(potm->otmrcFontBox.right);
7586 SCALE_Y(potm->otmMacAscent);
7587 SCALE_Y(potm->otmMacDescent);
7588 SCALE_Y(potm->otmMacLineGap);
7589 SCALE_X(potm->otmptSubscriptSize.x);
7590 SCALE_Y(potm->otmptSubscriptSize.y);
7591 SCALE_X(potm->otmptSubscriptOffset.x);
7592 SCALE_Y(potm->otmptSubscriptOffset.y);
7593 SCALE_X(potm->otmptSuperscriptSize.x);
7594 SCALE_Y(potm->otmptSuperscriptSize.y);
7595 SCALE_X(potm->otmptSuperscriptOffset.x);
7596 SCALE_Y(potm->otmptSuperscriptOffset.y);
7597 SCALE_Y(potm->otmsStrikeoutSize);
7598 SCALE_Y(potm->otmsStrikeoutPosition);
7599 SCALE_Y(potm->otmsUnderscoreSize);
7600 SCALE_Y(potm->otmsUnderscorePosition);
7602 #undef SCALE_X
7603 #undef SCALE_Y
7606 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
7608 if(!font->potm)
7610 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
7612 /* Make sure that the font has sane width/height ratio */
7613 if (font->aveWidth)
7615 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
7617 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
7618 font->aveWidth = 0;
7622 *ptm = font->potm->otmTextMetrics;
7623 scale_font_metrics(font, ptm);
7624 return TRUE;
7627 static BOOL face_has_symbol_charmap(FT_Face ft_face)
7629 int i;
7631 for(i = 0; i < ft_face->num_charmaps; i++)
7633 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
7634 return TRUE;
7636 return FALSE;
7639 static BOOL get_outline_text_metrics(GdiFont *font)
7641 BOOL ret = FALSE;
7642 FT_Face ft_face = font->ft_face;
7643 UINT needed, lenfam, lensty, lenface, lenfull;
7644 TT_OS2 *pOS2;
7645 TT_HoriHeader *pHori;
7646 TT_Postscript *pPost;
7647 FT_Fixed em_scale;
7648 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
7649 char *cp;
7650 INT ascent, descent;
7651 USHORT windescent;
7653 TRACE("font=%p\n", font);
7655 if(!FT_IS_SCALABLE(ft_face))
7656 return FALSE;
7658 needed = sizeof(*font->potm);
7660 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
7661 family_nameW = strdupW(font->name);
7663 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
7664 if (!style_nameW)
7666 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
7667 style_nameW = towstr( CP_ACP, ft_face->style_name );
7669 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
7671 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
7672 if (!face_nameW)
7674 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
7675 face_nameW = strdupW(font->name);
7677 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
7678 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
7680 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
7681 if (!full_nameW)
7683 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
7684 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
7685 full_nameW = strdupW(fake_nameW);
7687 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
7689 /* These names should be read from the TT name table */
7691 /* length of otmpFamilyName */
7692 needed += lenfam;
7694 /* length of otmpFaceName */
7695 needed += lenface;
7697 /* length of otmpStyleName */
7698 needed += lensty;
7700 /* length of otmpFullName */
7701 needed += lenfull;
7704 em_scale = (FT_Fixed)MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
7706 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
7707 if(!pOS2) {
7708 FIXME("Can't find OS/2 table - not TT font?\n");
7709 goto end;
7712 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
7713 if(!pHori) {
7714 FIXME("Can't find HHEA table - not TT font?\n");
7715 goto end;
7718 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
7720 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",
7721 pOS2->usWinAscent, pOS2->usWinDescent,
7722 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
7723 pOS2->xAvgCharWidth,
7724 ft_face->ascender, ft_face->descender, ft_face->height,
7725 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
7726 ft_face->bbox.yMax, ft_face->bbox.yMin);
7728 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
7729 font->potm->otmSize = needed;
7731 #define TM font->potm->otmTextMetrics
7733 windescent = get_fixed_windescent(pOS2->usWinDescent);
7734 if(pOS2->usWinAscent + windescent == 0) {
7735 ascent = pHori->Ascender;
7736 descent = -pHori->Descender;
7737 } else {
7738 ascent = pOS2->usWinAscent;
7739 descent = windescent;
7742 font->ntmCellHeight = ascent + descent;
7743 font->ntmAvgWidth = pOS2->xAvgCharWidth;
7745 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7746 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7748 if(font->yMax) {
7749 TM.tmAscent = font->yMax;
7750 TM.tmDescent = -font->yMin;
7751 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
7752 } else {
7753 TM.tmAscent = SCALE_Y(ascent);
7754 TM.tmDescent = SCALE_Y(descent);
7755 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
7758 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7760 /* MSDN says:
7761 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7763 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
7764 ((ascent + descent) -
7765 (pHori->Ascender - pHori->Descender))));
7767 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
7768 if (TM.tmAveCharWidth == 0) {
7769 TM.tmAveCharWidth = 1;
7771 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
7772 TM.tmWeight = FW_REGULAR;
7773 if (font->fake_bold) {
7774 TM.tmAveCharWidth++;
7775 TM.tmMaxCharWidth++;
7776 TM.tmWeight = FW_BOLD;
7778 else
7780 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
7782 if (pOS2->usWeightClass > FW_MEDIUM)
7783 TM.tmWeight = pOS2->usWeightClass;
7785 else if (pOS2->usWeightClass <= FW_MEDIUM)
7786 TM.tmWeight = pOS2->usWeightClass;
7788 TM.tmOverhang = 0;
7789 TM.tmDigitizedAspectX = 96; /* FIXME */
7790 TM.tmDigitizedAspectY = 96; /* FIXME */
7791 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7792 * symbol range to 0 - f0ff
7795 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
7797 TM.tmFirstChar = 0;
7798 switch(GetACP())
7800 case 1255: /* Hebrew */
7801 TM.tmLastChar = 0xf896;
7802 break;
7803 case 1257: /* Baltic */
7804 TM.tmLastChar = 0xf8fd;
7805 break;
7806 default:
7807 TM.tmLastChar = 0xf0ff;
7809 TM.tmBreakChar = 0x20;
7810 TM.tmDefaultChar = 0x1f;
7812 else
7814 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
7815 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
7817 if(pOS2->usFirstCharIndex <= 1)
7818 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
7819 else if (pOS2->usFirstCharIndex > 0xff)
7820 TM.tmBreakChar = 0x20;
7821 else
7822 TM.tmBreakChar = pOS2->usFirstCharIndex;
7823 TM.tmDefaultChar = TM.tmBreakChar - 1;
7825 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
7826 TM.tmUnderlined = font->underline;
7827 TM.tmStruckOut = font->strikeout;
7829 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7830 if(!FT_IS_FIXED_WIDTH(ft_face) &&
7831 (pOS2->version == 0xFFFFU ||
7832 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
7833 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
7834 else
7835 TM.tmPitchAndFamily = 0;
7837 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
7839 case PAN_FAMILY_SCRIPT:
7840 TM.tmPitchAndFamily |= FF_SCRIPT;
7841 break;
7843 case PAN_FAMILY_DECORATIVE:
7844 TM.tmPitchAndFamily |= FF_DECORATIVE;
7845 break;
7847 case PAN_ANY:
7848 case PAN_NO_FIT:
7849 case PAN_FAMILY_TEXT_DISPLAY:
7850 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
7851 /* which is clearly not what the panose spec says. */
7852 default:
7853 if(TM.tmPitchAndFamily == 0 || /* fixed */
7854 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
7855 TM.tmPitchAndFamily = FF_MODERN;
7856 else
7858 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
7860 case PAN_ANY:
7861 case PAN_NO_FIT:
7862 default:
7863 TM.tmPitchAndFamily |= FF_DONTCARE;
7864 break;
7866 case PAN_SERIF_COVE:
7867 case PAN_SERIF_OBTUSE_COVE:
7868 case PAN_SERIF_SQUARE_COVE:
7869 case PAN_SERIF_OBTUSE_SQUARE_COVE:
7870 case PAN_SERIF_SQUARE:
7871 case PAN_SERIF_THIN:
7872 case PAN_SERIF_BONE:
7873 case PAN_SERIF_EXAGGERATED:
7874 case PAN_SERIF_TRIANGLE:
7875 TM.tmPitchAndFamily |= FF_ROMAN;
7876 break;
7878 case PAN_SERIF_NORMAL_SANS:
7879 case PAN_SERIF_OBTUSE_SANS:
7880 case PAN_SERIF_PERP_SANS:
7881 case PAN_SERIF_FLARED:
7882 case PAN_SERIF_ROUNDED:
7883 TM.tmPitchAndFamily |= FF_SWISS;
7884 break;
7887 break;
7890 if(FT_IS_SCALABLE(ft_face))
7891 TM.tmPitchAndFamily |= TMPF_VECTOR;
7893 if(FT_IS_SFNT(ft_face))
7895 if (font->ntmFlags & NTM_PS_OPENTYPE)
7896 TM.tmPitchAndFamily |= TMPF_DEVICE;
7897 else
7898 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
7901 TM.tmCharSet = font->charset;
7903 font->potm->otmFiller = 0;
7904 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
7905 font->potm->otmfsSelection = pOS2->fsSelection;
7906 if (font->fake_italic)
7907 font->potm->otmfsSelection |= 1;
7908 if (font->fake_bold)
7909 font->potm->otmfsSelection |= 1 << 5;
7910 font->potm->otmfsType = pOS2->fsType;
7911 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
7912 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
7913 font->potm->otmItalicAngle = 0; /* POST table */
7914 font->potm->otmEMSquare = ft_face->units_per_EM;
7915 font->potm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
7916 font->potm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
7917 font->potm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
7918 font->potm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
7919 font->potm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
7920 font->potm->otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
7921 font->potm->otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
7922 font->potm->otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
7923 font->potm->otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
7924 font->potm->otmMacAscent = TM.tmAscent;
7925 font->potm->otmMacDescent = -TM.tmDescent;
7926 font->potm->otmMacLineGap = font->potm->otmLineGap;
7927 font->potm->otmusMinimumPPEM = 0; /* TT Header */
7928 font->potm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
7929 font->potm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
7930 font->potm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
7931 font->potm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
7932 font->potm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
7933 font->potm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
7934 font->potm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
7935 font->potm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
7936 font->potm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
7937 font->potm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
7938 if(!pPost) {
7939 font->potm->otmsUnderscoreSize = 0;
7940 font->potm->otmsUnderscorePosition = 0;
7941 } else {
7942 font->potm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
7943 font->potm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
7945 #undef SCALE_X
7946 #undef SCALE_Y
7947 #undef TM
7949 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7950 cp = (char*)font->potm + sizeof(*font->potm);
7951 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
7952 strcpyW((WCHAR*)cp, family_nameW);
7953 cp += lenfam;
7954 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
7955 strcpyW((WCHAR*)cp, style_nameW);
7956 cp += lensty;
7957 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7958 strcpyW((WCHAR*)cp, face_nameW);
7959 cp += lenface;
7960 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
7961 strcpyW((WCHAR*)cp, full_nameW);
7962 ret = TRUE;
7964 end:
7965 HeapFree(GetProcessHeap(), 0, style_nameW);
7966 HeapFree(GetProcessHeap(), 0, family_nameW);
7967 HeapFree(GetProcessHeap(), 0, face_nameW);
7968 HeapFree(GetProcessHeap(), 0, full_nameW);
7969 return ret;
7972 /*************************************************************
7973 * freetype_GetGlyphOutline
7975 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
7976 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7978 struct freetype_physdev *physdev = get_freetype_dev( dev );
7979 DWORD ret;
7980 ABC abc;
7982 if (!physdev->font)
7984 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
7985 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
7988 GDI_CheckNotLock();
7989 EnterCriticalSection( &freetype_cs );
7990 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
7991 LeaveCriticalSection( &freetype_cs );
7992 return ret;
7995 /*************************************************************
7996 * freetype_GetTextMetrics
7998 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
8000 struct freetype_physdev *physdev = get_freetype_dev( dev );
8001 BOOL ret;
8003 if (!physdev->font)
8005 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
8006 return dev->funcs->pGetTextMetrics( dev, metrics );
8009 GDI_CheckNotLock();
8010 EnterCriticalSection( &freetype_cs );
8011 ret = get_text_metrics( physdev->font, metrics );
8012 LeaveCriticalSection( &freetype_cs );
8013 return ret;
8016 /*************************************************************
8017 * freetype_GetOutlineTextMetrics
8019 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
8021 struct freetype_physdev *physdev = get_freetype_dev( dev );
8022 UINT ret = 0;
8024 if (!physdev->font)
8026 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
8027 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
8030 TRACE("font=%p\n", physdev->font);
8032 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
8034 GDI_CheckNotLock();
8035 EnterCriticalSection( &freetype_cs );
8037 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
8039 if(potm && cbSize >= physdev->font->potm->otmSize)
8041 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
8042 scale_outline_font_metrics(physdev->font, potm);
8044 ret = physdev->font->potm->otmSize;
8046 LeaveCriticalSection( &freetype_cs );
8047 return ret;
8050 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
8052 child->font = alloc_font();
8053 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
8054 if(!child->font->ft_face)
8056 free_font(child->font);
8057 child->font = NULL;
8058 return FALSE;
8061 child->font->font_desc = font->font_desc;
8062 child->font->ntmFlags = child->face->ntmFlags;
8063 child->font->orientation = font->orientation;
8064 child->font->scale_y = font->scale_y;
8065 child->font->name = strdupW(child->face->family->FamilyName);
8066 child->font->base_font = font;
8067 TRACE("created child font %p for base %p\n", child->font, font);
8068 return TRUE;
8071 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL* vert)
8073 FT_UInt g,o;
8074 CHILD_FONT *child_font;
8076 if(font->base_font)
8077 font = font->base_font;
8079 *linked_font = font;
8081 if((*glyph = get_glyph_index(font, c)))
8083 o = *glyph;
8084 *glyph = get_GSUB_vert_glyph(font, *glyph);
8085 *vert = (o != *glyph);
8086 return TRUE;
8089 if (c < 32) goto done; /* don't check linked fonts for control characters */
8091 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
8093 if(!child_font->font)
8094 if(!load_child_font(font, child_font))
8095 continue;
8097 if(!child_font->font->ft_face)
8098 continue;
8099 g = get_glyph_index(child_font->font, c);
8100 o = g;
8101 g = get_GSUB_vert_glyph(child_font->font, g);
8102 if(g)
8104 *glyph = g;
8105 *linked_font = child_font->font;
8106 *vert = (o != g);
8107 return TRUE;
8111 done:
8112 *vert = FALSE;
8113 return FALSE;
8116 /*************************************************************
8117 * freetype_GetCharWidth
8119 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
8121 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8122 UINT c;
8123 GLYPHMETRICS gm;
8124 ABC abc;
8125 struct freetype_physdev *physdev = get_freetype_dev( dev );
8127 if (!physdev->font)
8129 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
8130 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
8133 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
8135 GDI_CheckNotLock();
8136 EnterCriticalSection( &freetype_cs );
8137 for(c = firstChar; c <= lastChar; c++) {
8138 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
8139 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
8141 LeaveCriticalSection( &freetype_cs );
8142 return TRUE;
8145 /*************************************************************
8146 * freetype_GetCharABCWidths
8148 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
8150 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8151 UINT c;
8152 GLYPHMETRICS gm;
8153 struct freetype_physdev *physdev = get_freetype_dev( dev );
8155 if (!physdev->font)
8157 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
8158 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
8161 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
8163 GDI_CheckNotLock();
8164 EnterCriticalSection( &freetype_cs );
8166 for(c = firstChar; c <= lastChar; c++, buffer++)
8167 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
8169 LeaveCriticalSection( &freetype_cs );
8170 return TRUE;
8173 /*************************************************************
8174 * freetype_GetCharABCWidthsI
8176 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
8178 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8179 UINT c;
8180 GLYPHMETRICS gm;
8181 struct freetype_physdev *physdev = get_freetype_dev( dev );
8183 if (!physdev->font)
8185 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
8186 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
8189 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
8190 return FALSE;
8192 GDI_CheckNotLock();
8193 EnterCriticalSection( &freetype_cs );
8195 for(c = 0; c < count; c++, buffer++)
8196 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
8197 &gm, buffer, 0, NULL, &identity );
8199 LeaveCriticalSection( &freetype_cs );
8200 return TRUE;
8203 /*************************************************************
8204 * freetype_GetTextExtentExPoint
8206 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
8208 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8209 INT idx, pos;
8210 ABC abc;
8211 GLYPHMETRICS gm;
8212 struct freetype_physdev *physdev = get_freetype_dev( dev );
8214 if (!physdev->font)
8216 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
8217 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
8220 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
8222 GDI_CheckNotLock();
8223 EnterCriticalSection( &freetype_cs );
8225 for (idx = pos = 0; idx < count; idx++)
8227 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
8228 pos += abc.abcA + abc.abcB + abc.abcC;
8229 dxs[idx] = pos;
8232 LeaveCriticalSection( &freetype_cs );
8233 return TRUE;
8236 /*************************************************************
8237 * freetype_GetTextExtentExPointI
8239 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
8241 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8242 INT idx, pos;
8243 ABC abc;
8244 GLYPHMETRICS gm;
8245 struct freetype_physdev *physdev = get_freetype_dev( dev );
8247 if (!physdev->font)
8249 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
8250 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
8253 TRACE("%p, %p, %d\n", physdev->font, indices, count);
8255 GDI_CheckNotLock();
8256 EnterCriticalSection( &freetype_cs );
8258 for (idx = pos = 0; idx < count; idx++)
8260 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
8261 &gm, &abc, 0, NULL, &identity );
8262 pos += abc.abcA + abc.abcB + abc.abcC;
8263 dxs[idx] = pos;
8266 LeaveCriticalSection( &freetype_cs );
8267 return TRUE;
8270 /*************************************************************
8271 * freetype_GetFontData
8273 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
8275 struct freetype_physdev *physdev = get_freetype_dev( dev );
8277 if (!physdev->font)
8279 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
8280 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
8283 TRACE("font=%p, table=%s, offset=0x%x, buf=%p, cbData=0x%x\n",
8284 physdev->font, debugstr_an((char*)&table, 4), offset, buf, cbData);
8286 return get_font_data( physdev->font, table, offset, buf, cbData );
8289 /*************************************************************
8290 * freetype_GetTextFace
8292 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
8294 INT n;
8295 struct freetype_physdev *physdev = get_freetype_dev( dev );
8297 if (!physdev->font)
8299 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
8300 return dev->funcs->pGetTextFace( dev, count, str );
8303 n = strlenW(physdev->font->name) + 1;
8304 if (str)
8306 lstrcpynW(str, physdev->font->name, count);
8307 n = min(count, n);
8309 return n;
8312 /*************************************************************
8313 * freetype_GetTextCharsetInfo
8315 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
8317 struct freetype_physdev *physdev = get_freetype_dev( dev );
8319 if (!physdev->font)
8321 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
8322 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
8324 if (fs) *fs = physdev->font->fs;
8325 return physdev->font->charset;
8328 /* Retrieve a list of supported Unicode ranges for a given font.
8329 * Can be called with NULL gs to calculate the buffer size. Returns
8330 * the number of ranges found.
8332 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
8334 DWORD num_ranges = 0;
8336 if (face->charmap->encoding == FT_ENCODING_UNICODE)
8338 FT_UInt glyph_code;
8339 FT_ULong char_code, char_code_prev;
8341 glyph_code = 0;
8342 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
8344 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
8345 face->num_glyphs, glyph_code, char_code);
8347 if (!glyph_code) return 0;
8349 if (gs)
8351 gs->ranges[0].wcLow = (USHORT)char_code;
8352 gs->ranges[0].cGlyphs = 0;
8353 gs->cGlyphsSupported = 0;
8356 num_ranges = 1;
8357 while (glyph_code)
8359 if (char_code < char_code_prev)
8361 ERR("expected increasing char code from FT_Get_Next_Char\n");
8362 return 0;
8364 if (char_code - char_code_prev > 1)
8366 num_ranges++;
8367 if (gs)
8369 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
8370 gs->ranges[num_ranges - 1].cGlyphs = 1;
8371 gs->cGlyphsSupported++;
8374 else if (gs)
8376 gs->ranges[num_ranges - 1].cGlyphs++;
8377 gs->cGlyphsSupported++;
8379 char_code_prev = char_code;
8380 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
8383 else
8384 FIXME("encoding %u not supported\n", face->charmap->encoding);
8386 return num_ranges;
8389 /*************************************************************
8390 * freetype_GetFontUnicodeRanges
8392 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
8394 struct freetype_physdev *physdev = get_freetype_dev( dev );
8395 DWORD size, num_ranges;
8397 if (!physdev->font)
8399 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
8400 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
8403 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
8404 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
8405 if (glyphset)
8407 glyphset->cbThis = size;
8408 glyphset->cRanges = num_ranges;
8409 glyphset->flAccel = 0;
8411 return size;
8414 /*************************************************************
8415 * freetype_FontIsLinked
8417 static BOOL freetype_FontIsLinked( PHYSDEV dev )
8419 struct freetype_physdev *physdev = get_freetype_dev( dev );
8420 BOOL ret;
8422 if (!physdev->font)
8424 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
8425 return dev->funcs->pFontIsLinked( dev );
8428 GDI_CheckNotLock();
8429 EnterCriticalSection( &freetype_cs );
8430 ret = !list_empty(&physdev->font->child_fonts);
8431 LeaveCriticalSection( &freetype_cs );
8432 return ret;
8435 /*************************************************************************
8436 * GetRasterizerCaps (GDI32.@)
8438 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8440 lprs->nSize = sizeof(RASTERIZER_STATUS);
8441 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
8442 lprs->nLanguageID = 0;
8443 return TRUE;
8446 /*************************************************************
8447 * freetype_GetFontRealizationInfo
8449 static BOOL freetype_GetFontRealizationInfo( PHYSDEV dev, void *ptr )
8451 struct freetype_physdev *physdev = get_freetype_dev( dev );
8452 struct font_realization_info *info = ptr;
8454 if (!physdev->font)
8456 dev = GET_NEXT_PHYSDEV( dev, pGetFontRealizationInfo );
8457 return dev->funcs->pGetFontRealizationInfo( dev, ptr );
8460 TRACE("(%p, %p)\n", physdev->font, info);
8462 info->flags = 1;
8463 if(FT_IS_SCALABLE(physdev->font->ft_face))
8464 info->flags |= 2;
8466 info->cache_num = physdev->font->cache_num;
8467 info->instance_id = physdev->font->instance_id;
8468 if (info->size == sizeof(*info))
8470 info->unk = 0;
8471 info->face_index = physdev->font->ft_face->face_index;
8472 info->simulations = 0;
8473 if (physdev->font->fake_bold)
8474 info->simulations |= 0x1;
8475 if (physdev->font->fake_italic)
8476 info->simulations |= 0x2;
8479 return TRUE;
8482 /*************************************************************************
8483 * GetFontFileInfo (GDI32.@)
8485 BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_fileinfo *info, DWORD size, DWORD *needed )
8487 struct font_handle_entry *entry = handle_entry( instance_id );
8488 const GdiFont *font;
8490 if (!entry)
8492 SetLastError(ERROR_INVALID_PARAMETER);
8493 return FALSE;
8496 font = entry->obj;
8497 *needed = sizeof(*info) + strlenW(font->fileinfo->path) * sizeof(WCHAR);
8498 if (*needed > size)
8500 SetLastError(ERROR_INSUFFICIENT_BUFFER);
8501 return FALSE;
8504 /* path is included too */
8505 memcpy(info, font->fileinfo, *needed);
8506 return TRUE;
8509 /*************************************************************************
8510 * Kerning support for TrueType fonts
8513 struct TT_kern_table
8515 USHORT version;
8516 USHORT nTables;
8519 struct TT_kern_subtable
8521 USHORT version;
8522 USHORT length;
8523 union
8525 USHORT word;
8526 struct
8528 USHORT horizontal : 1;
8529 USHORT minimum : 1;
8530 USHORT cross_stream: 1;
8531 USHORT override : 1;
8532 USHORT reserved1 : 4;
8533 USHORT format : 8;
8534 } bits;
8535 } coverage;
8538 struct TT_format0_kern_subtable
8540 USHORT nPairs;
8541 USHORT searchRange;
8542 USHORT entrySelector;
8543 USHORT rangeShift;
8546 struct TT_kern_pair
8548 USHORT left;
8549 USHORT right;
8550 short value;
8553 static DWORD parse_format0_kern_subtable(GdiFont *font,
8554 const struct TT_format0_kern_subtable *tt_f0_ks,
8555 const USHORT *glyph_to_char,
8556 KERNINGPAIR *kern_pair, DWORD cPairs)
8558 USHORT i, nPairs;
8559 const struct TT_kern_pair *tt_kern_pair;
8561 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
8563 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
8565 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8566 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
8567 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
8569 if (!kern_pair || !cPairs)
8570 return nPairs;
8572 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
8574 nPairs = min(nPairs, cPairs);
8576 for (i = 0; i < nPairs; i++)
8578 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
8579 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
8580 /* this algorithm appears to better match what Windows does */
8581 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
8582 if (kern_pair->iKernAmount < 0)
8584 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
8585 kern_pair->iKernAmount -= font->ppem;
8587 else if (kern_pair->iKernAmount > 0)
8589 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
8590 kern_pair->iKernAmount += font->ppem;
8592 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
8594 TRACE("left %u right %u value %d\n",
8595 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
8597 kern_pair++;
8599 TRACE("copied %u entries\n", nPairs);
8600 return nPairs;
8603 /*************************************************************
8604 * freetype_GetKerningPairs
8606 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
8608 DWORD length;
8609 void *buf;
8610 const struct TT_kern_table *tt_kern_table;
8611 const struct TT_kern_subtable *tt_kern_subtable;
8612 USHORT i, nTables;
8613 USHORT *glyph_to_char;
8614 GdiFont *font;
8615 struct freetype_physdev *physdev = get_freetype_dev( dev );
8617 if (!(font = physdev->font))
8619 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
8620 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
8623 GDI_CheckNotLock();
8624 EnterCriticalSection( &freetype_cs );
8625 if (font->total_kern_pairs != (DWORD)-1)
8627 if (cPairs && kern_pair)
8629 cPairs = min(cPairs, font->total_kern_pairs);
8630 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8632 else cPairs = font->total_kern_pairs;
8634 LeaveCriticalSection( &freetype_cs );
8635 return cPairs;
8638 font->total_kern_pairs = 0;
8640 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
8642 if (length == GDI_ERROR)
8644 TRACE("no kerning data in the font\n");
8645 LeaveCriticalSection( &freetype_cs );
8646 return 0;
8649 buf = HeapAlloc(GetProcessHeap(), 0, length);
8650 if (!buf)
8652 WARN("Out of memory\n");
8653 LeaveCriticalSection( &freetype_cs );
8654 return 0;
8657 get_font_data(font, MS_KERN_TAG, 0, buf, length);
8659 /* build a glyph index to char code map */
8660 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
8661 if (!glyph_to_char)
8663 WARN("Out of memory allocating a glyph index to char code map\n");
8664 HeapFree(GetProcessHeap(), 0, buf);
8665 LeaveCriticalSection( &freetype_cs );
8666 return 0;
8669 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
8671 FT_UInt glyph_code;
8672 FT_ULong char_code;
8674 glyph_code = 0;
8675 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
8677 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
8678 font->ft_face->num_glyphs, glyph_code, char_code);
8680 while (glyph_code)
8682 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
8684 /* FIXME: This doesn't match what Windows does: it does some fancy
8685 * things with duplicate glyph index to char code mappings, while
8686 * we just avoid overriding existing entries.
8688 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
8689 glyph_to_char[glyph_code] = (USHORT)char_code;
8691 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
8694 else
8696 ULONG n;
8698 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
8699 for (n = 0; n <= 65535; n++)
8700 glyph_to_char[n] = (USHORT)n;
8703 tt_kern_table = buf;
8704 nTables = GET_BE_WORD(tt_kern_table->nTables);
8705 TRACE("version %u, nTables %u\n",
8706 GET_BE_WORD(tt_kern_table->version), nTables);
8708 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
8710 for (i = 0; i < nTables; i++)
8712 struct TT_kern_subtable tt_kern_subtable_copy;
8714 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
8715 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
8716 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
8718 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8719 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
8720 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
8722 /* According to the TrueType specification this is the only format
8723 * that will be properly interpreted by Windows and OS/2
8725 if (tt_kern_subtable_copy.coverage.bits.format == 0)
8727 DWORD new_chunk, old_total = font->total_kern_pairs;
8729 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8730 glyph_to_char, NULL, 0);
8731 font->total_kern_pairs += new_chunk;
8733 if (!font->kern_pairs)
8734 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
8735 font->total_kern_pairs * sizeof(*font->kern_pairs));
8736 else
8737 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
8738 font->total_kern_pairs * sizeof(*font->kern_pairs));
8740 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8741 glyph_to_char, font->kern_pairs + old_total, new_chunk);
8743 else
8744 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
8746 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
8749 HeapFree(GetProcessHeap(), 0, glyph_to_char);
8750 HeapFree(GetProcessHeap(), 0, buf);
8752 if (cPairs && kern_pair)
8754 cPairs = min(cPairs, font->total_kern_pairs);
8755 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8757 else cPairs = font->total_kern_pairs;
8759 LeaveCriticalSection( &freetype_cs );
8760 return cPairs;
8763 static const struct gdi_dc_funcs freetype_funcs =
8765 NULL, /* pAbortDoc */
8766 NULL, /* pAbortPath */
8767 NULL, /* pAlphaBlend */
8768 NULL, /* pAngleArc */
8769 NULL, /* pArc */
8770 NULL, /* pArcTo */
8771 NULL, /* pBeginPath */
8772 NULL, /* pBlendImage */
8773 NULL, /* pChord */
8774 NULL, /* pCloseFigure */
8775 NULL, /* pCreateCompatibleDC */
8776 freetype_CreateDC, /* pCreateDC */
8777 freetype_DeleteDC, /* pDeleteDC */
8778 NULL, /* pDeleteObject */
8779 NULL, /* pDeviceCapabilities */
8780 NULL, /* pEllipse */
8781 NULL, /* pEndDoc */
8782 NULL, /* pEndPage */
8783 NULL, /* pEndPath */
8784 freetype_EnumFonts, /* pEnumFonts */
8785 NULL, /* pEnumICMProfiles */
8786 NULL, /* pExcludeClipRect */
8787 NULL, /* pExtDeviceMode */
8788 NULL, /* pExtEscape */
8789 NULL, /* pExtFloodFill */
8790 NULL, /* pExtSelectClipRgn */
8791 NULL, /* pExtTextOut */
8792 NULL, /* pFillPath */
8793 NULL, /* pFillRgn */
8794 NULL, /* pFlattenPath */
8795 freetype_FontIsLinked, /* pFontIsLinked */
8796 NULL, /* pFrameRgn */
8797 NULL, /* pGdiComment */
8798 NULL, /* pGetBoundsRect */
8799 freetype_GetCharABCWidths, /* pGetCharABCWidths */
8800 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
8801 freetype_GetCharWidth, /* pGetCharWidth */
8802 NULL, /* pGetDeviceCaps */
8803 NULL, /* pGetDeviceGammaRamp */
8804 freetype_GetFontData, /* pGetFontData */
8805 freetype_GetFontRealizationInfo, /* pGetFontRealizationInfo */
8806 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
8807 freetype_GetGlyphIndices, /* pGetGlyphIndices */
8808 freetype_GetGlyphOutline, /* pGetGlyphOutline */
8809 NULL, /* pGetICMProfile */
8810 NULL, /* pGetImage */
8811 freetype_GetKerningPairs, /* pGetKerningPairs */
8812 NULL, /* pGetNearestColor */
8813 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
8814 NULL, /* pGetPixel */
8815 NULL, /* pGetSystemPaletteEntries */
8816 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
8817 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
8818 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
8819 freetype_GetTextFace, /* pGetTextFace */
8820 freetype_GetTextMetrics, /* pGetTextMetrics */
8821 NULL, /* pGradientFill */
8822 NULL, /* pIntersectClipRect */
8823 NULL, /* pInvertRgn */
8824 NULL, /* pLineTo */
8825 NULL, /* pModifyWorldTransform */
8826 NULL, /* pMoveTo */
8827 NULL, /* pOffsetClipRgn */
8828 NULL, /* pOffsetViewportOrg */
8829 NULL, /* pOffsetWindowOrg */
8830 NULL, /* pPaintRgn */
8831 NULL, /* pPatBlt */
8832 NULL, /* pPie */
8833 NULL, /* pPolyBezier */
8834 NULL, /* pPolyBezierTo */
8835 NULL, /* pPolyDraw */
8836 NULL, /* pPolyPolygon */
8837 NULL, /* pPolyPolyline */
8838 NULL, /* pPolygon */
8839 NULL, /* pPolyline */
8840 NULL, /* pPolylineTo */
8841 NULL, /* pPutImage */
8842 NULL, /* pRealizeDefaultPalette */
8843 NULL, /* pRealizePalette */
8844 NULL, /* pRectangle */
8845 NULL, /* pResetDC */
8846 NULL, /* pRestoreDC */
8847 NULL, /* pRoundRect */
8848 NULL, /* pSaveDC */
8849 NULL, /* pScaleViewportExt */
8850 NULL, /* pScaleWindowExt */
8851 NULL, /* pSelectBitmap */
8852 NULL, /* pSelectBrush */
8853 NULL, /* pSelectClipPath */
8854 freetype_SelectFont, /* pSelectFont */
8855 NULL, /* pSelectPalette */
8856 NULL, /* pSelectPen */
8857 NULL, /* pSetArcDirection */
8858 NULL, /* pSetBkColor */
8859 NULL, /* pSetBkMode */
8860 NULL, /* pSetDCBrushColor */
8861 NULL, /* pSetDCPenColor */
8862 NULL, /* pSetDIBColorTable */
8863 NULL, /* pSetDIBitsToDevice */
8864 NULL, /* pSetDeviceClipping */
8865 NULL, /* pSetDeviceGammaRamp */
8866 NULL, /* pSetLayout */
8867 NULL, /* pSetMapMode */
8868 NULL, /* pSetMapperFlags */
8869 NULL, /* pSetPixel */
8870 NULL, /* pSetPolyFillMode */
8871 NULL, /* pSetROP2 */
8872 NULL, /* pSetRelAbs */
8873 NULL, /* pSetStretchBltMode */
8874 NULL, /* pSetTextAlign */
8875 NULL, /* pSetTextCharacterExtra */
8876 NULL, /* pSetTextColor */
8877 NULL, /* pSetTextJustification */
8878 NULL, /* pSetViewportExt */
8879 NULL, /* pSetViewportOrg */
8880 NULL, /* pSetWindowExt */
8881 NULL, /* pSetWindowOrg */
8882 NULL, /* pSetWorldTransform */
8883 NULL, /* pStartDoc */
8884 NULL, /* pStartPage */
8885 NULL, /* pStretchBlt */
8886 NULL, /* pStretchDIBits */
8887 NULL, /* pStrokeAndFillPath */
8888 NULL, /* pStrokePath */
8889 NULL, /* pUnrealizePalette */
8890 NULL, /* pWidenPath */
8891 NULL, /* wine_get_wgl_driver */
8892 GDI_PRIORITY_FONT_DRV /* priority */
8895 #else /* HAVE_FREETYPE */
8897 struct font_fileinfo;
8899 /*************************************************************************/
8901 BOOL WineEngInit(void)
8903 return FALSE;
8906 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8908 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8909 return 1;
8912 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8914 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8915 return TRUE;
8918 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
8920 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
8921 return NULL;
8924 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
8925 LPCWSTR font_file, LPCWSTR font_path )
8927 FIXME("stub\n");
8928 return FALSE;
8931 /*************************************************************************
8932 * GetRasterizerCaps (GDI32.@)
8934 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8936 lprs->nSize = sizeof(RASTERIZER_STATUS);
8937 lprs->wFlags = 0;
8938 lprs->nLanguageID = 0;
8939 return TRUE;
8942 /*************************************************************************
8943 * GetFontFileInfo (GDI32.@)
8945 BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_fileinfo *info, DWORD size, DWORD *needed)
8947 *needed = 0;
8948 return FALSE;
8951 #endif /* HAVE_FREETYPE */