winedevice: Get rid of global driver_hkey variable and fix some leaks.
[wine.git] / dlls / gdi32 / freetype.c
blob01cb9131a5f887a827707252feb2738949d7d84d
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 #else
214 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
215 #endif
217 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
218 typedef struct {
219 FT_Short height;
220 FT_Short width;
221 FT_Pos size;
222 FT_Pos x_ppem;
223 FT_Pos y_ppem;
224 FT_Short internal_leading;
225 } Bitmap_Size;
227 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
228 So to let this compile on older versions of FreeType we'll define the
229 new structure here. */
230 typedef struct {
231 FT_Short height, width;
232 FT_Pos size, x_ppem, y_ppem;
233 } My_FT_Bitmap_Size;
235 struct enum_data
237 ENUMLOGFONTEXW elf;
238 NEWTEXTMETRICEXW ntm;
239 DWORD type;
242 typedef struct tagFace {
243 struct list entry;
244 unsigned int refcount;
245 WCHAR *StyleName;
246 WCHAR *FullName;
247 WCHAR *file;
248 dev_t dev;
249 ino_t ino;
250 void *font_data_ptr;
251 DWORD font_data_size;
252 FT_Long face_index;
253 FONTSIGNATURE fs;
254 DWORD ntmFlags;
255 FT_Fixed font_version;
256 BOOL scalable;
257 Bitmap_Size size; /* set if face is a bitmap */
258 DWORD flags; /* ADDFONT flags */
259 struct tagFamily *family;
260 /* Cached data for Enum */
261 struct enum_data *cached_enum_data;
262 } Face;
264 #define ADDFONT_EXTERNAL_FONT 0x01
265 #define ADDFONT_ALLOW_BITMAP 0x02
266 #define ADDFONT_ADD_TO_CACHE 0x04
267 #define ADDFONT_ADD_RESOURCE 0x08 /* added through AddFontResource */
268 #define ADDFONT_VERTICAL_FONT 0x10
269 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
271 typedef struct tagFamily {
272 struct list entry;
273 unsigned int refcount;
274 WCHAR *FamilyName;
275 WCHAR *EnglishName;
276 struct list faces;
277 struct list *replacement;
278 } Family;
280 typedef struct {
281 GLYPHMETRICS gm;
282 ABC abc; /* metrics of the unrotated char */
283 BOOL init;
284 } GM;
286 typedef struct {
287 FLOAT eM11, eM12;
288 FLOAT eM21, eM22;
289 } FMAT2;
291 typedef struct {
292 DWORD hash;
293 LOGFONTW lf;
294 FMAT2 matrix;
295 BOOL can_use_bitmap;
296 } FONT_DESC;
298 typedef struct tagGdiFont GdiFont;
300 #define FIRST_FONT_HANDLE 1
301 #define MAX_FONT_HANDLES 256
303 struct font_handle_entry
305 void *obj;
306 WORD generation; /* generation count for reusing handle values */
309 static struct font_handle_entry font_handles[MAX_FONT_HANDLES];
310 static struct font_handle_entry *next_free;
311 static struct font_handle_entry *next_unused = font_handles;
313 static inline DWORD entry_to_handle( struct font_handle_entry *entry )
315 unsigned int idx = entry - font_handles + FIRST_FONT_HANDLE;
316 return idx | (entry->generation << 16);
319 static inline struct font_handle_entry *handle_entry( DWORD handle )
321 unsigned int idx = LOWORD(handle) - FIRST_FONT_HANDLE;
323 if (idx < MAX_FONT_HANDLES)
325 if (!HIWORD( handle ) || HIWORD( handle ) == font_handles[idx].generation)
326 return &font_handles[idx];
328 if (handle) WARN( "invalid handle 0x%08x\n", handle );
329 return NULL;
332 static DWORD alloc_font_handle( void *obj )
334 struct font_handle_entry *entry;
336 entry = next_free;
337 if (entry)
338 next_free = entry->obj;
339 else if (next_unused < font_handles + MAX_FONT_HANDLES)
340 entry = next_unused++;
341 else
343 ERR( "out of realized font handles\n" );
344 return 0;
346 entry->obj = obj;
347 if (++entry->generation == 0xffff) entry->generation = 1;
348 return entry_to_handle( entry );
351 static void free_font_handle( DWORD handle )
353 struct font_handle_entry *entry;
355 if ((entry = handle_entry( handle )))
357 entry->obj = next_free;
358 next_free = entry;
362 typedef struct {
363 struct list entry;
364 Face *face;
365 GdiFont *font;
366 } CHILD_FONT;
368 struct font_fileinfo {
369 FILETIME writetime;
370 LARGE_INTEGER size;
371 WCHAR path[1];
374 struct tagGdiFont {
375 struct list entry;
376 struct list unused_entry;
377 unsigned int refcount;
378 GM **gm;
379 DWORD gmsize;
380 OUTLINETEXTMETRICW *potm;
381 DWORD total_kern_pairs;
382 KERNINGPAIR *kern_pairs;
383 struct list child_fonts;
385 /* the following members can be accessed without locking, they are never modified after creation */
386 FT_Face ft_face;
387 struct font_mapping *mapping;
388 LPWSTR name;
389 int charset;
390 int codepage;
391 BOOL fake_italic;
392 BOOL fake_bold;
393 BYTE underline;
394 BYTE strikeout;
395 INT orientation;
396 FONT_DESC font_desc;
397 LONG aveWidth, ppem;
398 double scale_y;
399 SHORT yMax;
400 SHORT yMin;
401 DWORD ntmFlags;
402 DWORD aa_flags;
403 UINT ntmCellHeight, ntmAvgWidth;
404 FONTSIGNATURE fs;
405 GdiFont *base_font;
406 VOID *GSUB_Table;
407 const VOID *vert_feature;
408 DWORD cache_num;
409 DWORD instance_id;
410 struct font_fileinfo *fileinfo;
413 typedef struct {
414 struct list entry;
415 const WCHAR *font_name;
416 FONTSIGNATURE fs;
417 struct list links;
418 } SYSTEM_LINKS;
420 struct enum_charset_element {
421 DWORD mask;
422 DWORD charset;
423 WCHAR name[LF_FACESIZE];
426 struct enum_charset_list {
427 DWORD total;
428 struct enum_charset_element element[32];
431 #define GM_BLOCK_SIZE 128
432 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
434 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
435 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
436 static unsigned int unused_font_count;
437 #define UNUSED_CACHE_SIZE 10
438 static struct list system_links = LIST_INIT(system_links);
440 static struct list font_subst_list = LIST_INIT(font_subst_list);
442 static struct list font_list = LIST_INIT(font_list);
444 struct freetype_physdev
446 struct gdi_physdev dev;
447 GdiFont *font;
450 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
452 return (struct freetype_physdev *)dev;
455 static const struct gdi_dc_funcs freetype_funcs;
457 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
458 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
459 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
461 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
462 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
463 'W','i','n','d','o','w','s','\\',
464 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
465 'F','o','n','t','s','\0'};
467 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
468 'W','i','n','d','o','w','s',' ','N','T','\\',
469 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
470 'F','o','n','t','s','\0'};
472 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
473 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
474 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
475 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
477 static const WCHAR * const SystemFontValues[] = {
478 System_Value,
479 OEMFont_Value,
480 FixedSys_Value,
481 NULL
484 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
485 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
487 /* Interesting and well-known (frequently-assumed!) font names */
488 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
489 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 };
490 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
491 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
492 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
493 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
494 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
495 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
497 static const WCHAR arial[] = {'A','r','i','a','l',0};
498 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
499 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};
500 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};
501 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
502 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
503 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
504 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
505 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
506 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
508 static const WCHAR *default_serif_list[] =
510 times_new_roman,
511 liberation_serif,
512 bitstream_vera_serif,
513 NULL
516 static const WCHAR *default_fixed_list[] =
518 courier_new,
519 liberation_mono,
520 bitstream_vera_sans_mono,
521 NULL
524 static const WCHAR *default_sans_list[] =
526 arial,
527 liberation_sans,
528 bitstream_vera_sans,
529 NULL
532 typedef struct {
533 WCHAR *name;
534 INT charset;
535 } NameCs;
537 typedef struct tagFontSubst {
538 struct list entry;
539 NameCs from;
540 NameCs to;
541 } FontSubst;
543 /* Registry font cache key and value names */
544 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
545 'F','o','n','t','s',0};
546 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
547 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
548 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
549 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
550 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
551 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
552 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
553 static const WCHAR face_size_value[] = {'S','i','z','e',0};
554 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
555 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
556 static const WCHAR face_flags_value[] = {'F','l','a','g','s',0};
557 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
558 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
559 static const WCHAR face_file_name_value[] = {'F','i','l','e',' ','N','a','m','e','\0'};
560 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
563 struct font_mapping
565 struct list entry;
566 int refcount;
567 dev_t dev;
568 ino_t ino;
569 void *data;
570 size_t size;
573 static struct list mappings_list = LIST_INIT( mappings_list );
575 static UINT default_aa_flags;
576 static HKEY hkey_font_cache;
577 static BOOL antialias_fakes = TRUE;
579 static CRITICAL_SECTION freetype_cs;
580 static CRITICAL_SECTION_DEBUG critsect_debug =
582 0, 0, &freetype_cs,
583 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
584 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
586 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
588 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
590 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
591 static BOOL use_default_fallback = FALSE;
593 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL *vert);
594 static BOOL get_outline_text_metrics(GdiFont *font);
595 static BOOL get_bitmap_text_metrics(GdiFont *font);
596 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
597 static void remove_face_from_cache( Face *face );
599 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
600 'W','i','n','d','o','w','s',' ','N','T','\\',
601 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
602 'S','y','s','t','e','m','L','i','n','k',0};
604 /****************************************
605 * Notes on .fon files
607 * The fonts System, FixedSys and Terminal are special. There are typically multiple
608 * versions installed for different resolutions and codepages. Windows stores which one to use
609 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
610 * Key Meaning
611 * FIXEDFON.FON FixedSys
612 * FONTS.FON System
613 * OEMFONT.FON Terminal
614 * LogPixels Current dpi set by the display control panel applet
615 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
616 * also has a LogPixels value that appears to mirror this)
618 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
619 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
620 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
621 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
622 * so that makes sense.
624 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
625 * to be mapped into the registry on Windows 2000 at least).
626 * I have
627 * woafont=app850.fon
628 * ega80woa.fon=ega80850.fon
629 * ega40woa.fon=ega40850.fon
630 * cga80woa.fon=cga80850.fon
631 * cga40woa.fon=cga40850.fon
634 /* These are all structures needed for the GSUB table */
636 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
638 typedef struct {
639 DWORD version;
640 WORD ScriptList;
641 WORD FeatureList;
642 WORD LookupList;
643 } GSUB_Header;
645 typedef struct {
646 CHAR ScriptTag[4];
647 WORD Script;
648 } GSUB_ScriptRecord;
650 typedef struct {
651 WORD ScriptCount;
652 GSUB_ScriptRecord ScriptRecord[1];
653 } GSUB_ScriptList;
655 typedef struct {
656 CHAR LangSysTag[4];
657 WORD LangSys;
658 } GSUB_LangSysRecord;
660 typedef struct {
661 WORD DefaultLangSys;
662 WORD LangSysCount;
663 GSUB_LangSysRecord LangSysRecord[1];
664 } GSUB_Script;
666 typedef struct {
667 WORD LookupOrder; /* Reserved */
668 WORD ReqFeatureIndex;
669 WORD FeatureCount;
670 WORD FeatureIndex[1];
671 } GSUB_LangSys;
673 typedef struct {
674 CHAR FeatureTag[4];
675 WORD Feature;
676 } GSUB_FeatureRecord;
678 typedef struct {
679 WORD FeatureCount;
680 GSUB_FeatureRecord FeatureRecord[1];
681 } GSUB_FeatureList;
683 typedef struct {
684 WORD FeatureParams; /* Reserved */
685 WORD LookupCount;
686 WORD LookupListIndex[1];
687 } GSUB_Feature;
689 typedef struct {
690 WORD LookupCount;
691 WORD Lookup[1];
692 } GSUB_LookupList;
694 typedef struct {
695 WORD LookupType;
696 WORD LookupFlag;
697 WORD SubTableCount;
698 WORD SubTable[1];
699 } GSUB_LookupTable;
701 typedef struct {
702 WORD CoverageFormat;
703 WORD GlyphCount;
704 WORD GlyphArray[1];
705 } GSUB_CoverageFormat1;
707 typedef struct {
708 WORD Start;
709 WORD End;
710 WORD StartCoverageIndex;
711 } GSUB_RangeRecord;
713 typedef struct {
714 WORD CoverageFormat;
715 WORD RangeCount;
716 GSUB_RangeRecord RangeRecord[1];
717 } GSUB_CoverageFormat2;
719 typedef struct {
720 WORD SubstFormat; /* = 1 */
721 WORD Coverage;
722 WORD DeltaGlyphID;
723 } GSUB_SingleSubstFormat1;
725 typedef struct {
726 WORD SubstFormat; /* = 2 */
727 WORD Coverage;
728 WORD GlyphCount;
729 WORD Substitute[1];
730 }GSUB_SingleSubstFormat2;
732 #ifdef HAVE_CARBON_CARBON_H
733 static char *find_cache_dir(void)
735 FSRef ref;
736 OSErr err;
737 static char cached_path[MAX_PATH];
738 static const char *wine = "/Wine", *fonts = "/Fonts";
740 if(*cached_path) return cached_path;
742 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
743 if(err != noErr)
745 WARN("can't create cached data folder\n");
746 return NULL;
748 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
749 if(err != noErr)
751 WARN("can't create cached data path\n");
752 *cached_path = '\0';
753 return NULL;
755 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
757 ERR("Could not create full path\n");
758 *cached_path = '\0';
759 return NULL;
761 strcat(cached_path, wine);
763 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
765 WARN("Couldn't mkdir %s\n", cached_path);
766 *cached_path = '\0';
767 return NULL;
769 strcat(cached_path, fonts);
770 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
772 WARN("Couldn't mkdir %s\n", cached_path);
773 *cached_path = '\0';
774 return NULL;
776 return cached_path;
779 /******************************************************************
780 * expand_mac_font
782 * Extracts individual TrueType font files from a Mac suitcase font
783 * and saves them into the user's caches directory (see
784 * find_cache_dir()).
785 * Returns a NULL terminated array of filenames.
787 * We do this because they are apps that try to read ttf files
788 * themselves and they don't like Mac suitcase files.
790 static char **expand_mac_font(const char *path)
792 FSRef ref;
793 SInt16 res_ref;
794 OSStatus s;
795 unsigned int idx;
796 const char *out_dir;
797 const char *filename;
798 int output_len;
799 struct {
800 char **array;
801 unsigned int size, max_size;
802 } ret;
804 TRACE("path %s\n", path);
806 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
807 if(s != noErr)
809 WARN("failed to get ref\n");
810 return NULL;
813 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
814 if(s != noErr)
816 TRACE("no data fork, so trying resource fork\n");
817 res_ref = FSOpenResFile(&ref, fsRdPerm);
818 if(res_ref == -1)
820 TRACE("unable to open resource fork\n");
821 return NULL;
825 ret.size = 0;
826 ret.max_size = 10;
827 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
828 if(!ret.array)
830 CloseResFile(res_ref);
831 return NULL;
834 out_dir = find_cache_dir();
836 filename = strrchr(path, '/');
837 if(!filename) filename = path;
838 else filename++;
840 /* output filename has the form out_dir/filename_%04x.ttf */
841 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
843 UseResFile(res_ref);
844 idx = 1;
845 while(1)
847 FamRec *fam_rec;
848 unsigned short *num_faces_ptr, num_faces, face;
849 AsscEntry *assoc;
850 Handle fond;
851 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
853 fond = Get1IndResource(fond_res, idx);
854 if(!fond) break;
855 TRACE("got fond resource %d\n", idx);
856 HLock(fond);
858 fam_rec = *(FamRec**)fond;
859 num_faces_ptr = (unsigned short *)(fam_rec + 1);
860 num_faces = GET_BE_WORD(*num_faces_ptr);
861 num_faces++;
862 assoc = (AsscEntry*)(num_faces_ptr + 1);
863 TRACE("num faces %04x\n", num_faces);
864 for(face = 0; face < num_faces; face++, assoc++)
866 Handle sfnt;
867 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
868 unsigned short size, font_id;
869 char *output;
871 size = GET_BE_WORD(assoc->fontSize);
872 font_id = GET_BE_WORD(assoc->fontID);
873 if(size != 0)
875 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
876 continue;
879 TRACE("trying to load sfnt id %04x\n", font_id);
880 sfnt = GetResource(sfnt_res, font_id);
881 if(!sfnt)
883 TRACE("can't get sfnt resource %04x\n", font_id);
884 continue;
887 output = HeapAlloc(GetProcessHeap(), 0, output_len);
888 if(output)
890 int fd;
892 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
894 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
895 if(fd != -1 || errno == EEXIST)
897 if(fd != -1)
899 unsigned char *sfnt_data;
901 HLock(sfnt);
902 sfnt_data = *(unsigned char**)sfnt;
903 write(fd, sfnt_data, GetHandleSize(sfnt));
904 HUnlock(sfnt);
905 close(fd);
907 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
909 ret.max_size *= 2;
910 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
912 ret.array[ret.size++] = output;
914 else
916 WARN("unable to create %s\n", output);
917 HeapFree(GetProcessHeap(), 0, output);
920 ReleaseResource(sfnt);
922 HUnlock(fond);
923 ReleaseResource(fond);
924 idx++;
926 CloseResFile(res_ref);
928 return ret.array;
931 #endif /* HAVE_CARBON_CARBON_H */
933 static inline BOOL is_win9x(void)
935 return GetVersion() & 0x80000000;
938 This function builds an FT_Fixed from a double. It fails if the absolute
939 value of the float number is greater than 32768.
941 static inline FT_Fixed FT_FixedFromFloat(double f)
943 return f * 0x10000;
947 This function builds an FT_Fixed from a FIXED. It simply put f.value
948 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
950 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
952 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
955 static BOOL is_hinting_enabled(void)
957 static int enabled = -1;
959 if (enabled == -1)
961 /* Use the >= 2.2.0 function if available */
962 if (pFT_Get_TrueType_Engine_Type)
964 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
965 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
967 else enabled = FALSE;
968 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
970 return enabled;
973 static BOOL is_subpixel_rendering_enabled( void )
975 #ifdef FT_LCD_FILTER_H
976 static int enabled = -1;
977 if (enabled == -1)
979 enabled = (pFT_Library_SetLcdFilter &&
980 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature);
981 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
983 return enabled;
984 #else
985 return FALSE;
986 #endif
990 static const struct list *get_face_list_from_family(const Family *family)
992 if (!list_empty(&family->faces))
993 return &family->faces;
994 else
995 return family->replacement;
998 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
1000 Family *family;
1001 Face *face;
1002 const WCHAR *file;
1004 TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
1006 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1008 const struct list *face_list;
1009 if(face_name && strcmpiW(face_name, family->FamilyName))
1010 continue;
1011 face_list = get_face_list_from_family(family);
1012 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
1014 if (!face->file)
1015 continue;
1016 file = strrchrW(face->file, '/');
1017 if(!file)
1018 file = face->file;
1019 else
1020 file++;
1021 if(strcmpiW(file, file_name)) continue;
1022 face->refcount++;
1023 return face;
1026 return NULL;
1029 static Family *find_family_from_name(const WCHAR *name)
1031 Family *family;
1033 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1035 if(!strcmpiW(family->FamilyName, name))
1036 return family;
1039 return NULL;
1042 static Family *find_family_from_any_name(const WCHAR *name)
1044 Family *family;
1046 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1048 if(!strcmpiW(family->FamilyName, name))
1049 return family;
1050 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
1051 return family;
1054 return NULL;
1057 static void DumpSubstList(void)
1059 FontSubst *psub;
1061 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
1063 if(psub->from.charset != -1 || psub->to.charset != -1)
1064 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
1065 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
1066 else
1067 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
1068 debugstr_w(psub->to.name));
1072 static LPWSTR strdupW(LPCWSTR p)
1074 LPWSTR ret;
1075 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
1076 ret = HeapAlloc(GetProcessHeap(), 0, len);
1077 memcpy(ret, p, len);
1078 return ret;
1081 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1082 INT from_charset)
1084 FontSubst *element;
1086 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1088 if(!strcmpiW(element->from.name, from_name) &&
1089 (element->from.charset == from_charset ||
1090 element->from.charset == -1))
1091 return element;
1094 return NULL;
1097 #define ADD_FONT_SUBST_FORCE 1
1099 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1101 FontSubst *from_exist, *to_exist;
1103 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1105 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1107 list_remove(&from_exist->entry);
1108 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
1109 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
1110 HeapFree(GetProcessHeap(), 0, from_exist);
1111 from_exist = NULL;
1114 if(!from_exist)
1116 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1118 if(to_exist)
1120 HeapFree(GetProcessHeap(), 0, subst->to.name);
1121 subst->to.name = strdupW(to_exist->to.name);
1124 list_add_tail(subst_list, &subst->entry);
1126 return TRUE;
1129 HeapFree(GetProcessHeap(), 0, subst->from.name);
1130 HeapFree(GetProcessHeap(), 0, subst->to.name);
1131 HeapFree(GetProcessHeap(), 0, subst);
1132 return FALSE;
1135 static WCHAR *towstr(UINT cp, const char *str)
1137 int len;
1138 WCHAR *wstr;
1140 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1141 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1142 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1143 return wstr;
1146 static char *strWtoA(UINT cp, const WCHAR *str)
1148 int len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL );
1149 char *ret = HeapAlloc( GetProcessHeap(), 0, len );
1150 WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL );
1151 return ret;
1154 static void split_subst_info(NameCs *nc, LPSTR str)
1156 CHAR *p = strrchr(str, ',');
1158 nc->charset = -1;
1159 if(p && *(p+1)) {
1160 nc->charset = strtol(p+1, NULL, 10);
1161 *p = '\0';
1163 nc->name = towstr(CP_ACP, str);
1166 static void LoadSubstList(void)
1168 FontSubst *psub;
1169 HKEY hkey;
1170 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1171 LPSTR value;
1172 LPVOID data;
1174 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1175 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1176 &hkey) == ERROR_SUCCESS) {
1178 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1179 &valuelen, &datalen, NULL, NULL);
1181 valuelen++; /* returned value doesn't include room for '\0' */
1182 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1183 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1185 dlen = datalen;
1186 vlen = valuelen;
1187 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1188 &dlen) == ERROR_SUCCESS) {
1189 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1191 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1192 split_subst_info(&psub->from, value);
1193 split_subst_info(&psub->to, data);
1195 /* Win 2000 doesn't allow mapping between different charsets
1196 or mapping of DEFAULT_CHARSET */
1197 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1198 psub->to.charset == DEFAULT_CHARSET) {
1199 HeapFree(GetProcessHeap(), 0, psub->to.name);
1200 HeapFree(GetProcessHeap(), 0, psub->from.name);
1201 HeapFree(GetProcessHeap(), 0, psub);
1202 } else {
1203 add_font_subst(&font_subst_list, psub, 0);
1205 /* reset dlen and vlen */
1206 dlen = datalen;
1207 vlen = valuelen;
1209 HeapFree(GetProcessHeap(), 0, data);
1210 HeapFree(GetProcessHeap(), 0, value);
1211 RegCloseKey(hkey);
1216 static const LANGID mac_langid_table[] =
1218 MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */
1219 MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */
1220 MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */
1221 MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */
1222 MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */
1223 MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */
1224 MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */
1225 MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */
1226 MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */
1227 MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */
1228 MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */
1229 MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */
1230 MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */
1231 MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */
1232 MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */
1233 MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */
1234 MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */
1235 MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */
1236 MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */
1237 MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
1238 MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */
1239 MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */
1240 MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */
1241 MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */
1242 MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */
1243 MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */
1244 MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */
1245 MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */
1246 MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */
1247 MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */
1248 MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */
1249 MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */
1250 MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */
1251 MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
1252 MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */
1253 MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */
1254 MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */
1255 MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */
1256 MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */
1257 MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */
1258 MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */
1259 0, /* TT_MAC_LANGID_YIDDISH */
1260 MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */
1261 MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */
1262 MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */
1263 MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */
1264 MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */
1265 MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */
1266 MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */
1267 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */
1268 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
1269 MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */
1270 MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */
1271 0, /* TT_MAC_LANGID_MOLDAVIAN */
1272 MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */
1273 MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */
1274 MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */
1275 MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */
1276 MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
1277 MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */
1278 0, /* TT_MAC_LANGID_KURDISH */
1279 MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */
1280 MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */
1281 MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */
1282 MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */
1283 MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */
1284 MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */
1285 MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */
1286 MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */
1287 MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */
1288 MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */
1289 MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */
1290 MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */
1291 MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */
1292 MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */
1293 MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */
1294 MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */
1295 0, /* TT_MAC_LANGID_BURMESE */
1296 MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */
1297 MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */
1298 MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */
1299 MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */
1300 0, /* TT_MAC_LANGID_TAGALOG */
1301 MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
1302 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
1303 MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */
1304 MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */
1305 0, /* TT_MAC_LANGID_GALLA */
1306 0, /* TT_MAC_LANGID_SOMALI */
1307 MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */
1308 0, /* TT_MAC_LANGID_RUANDA */
1309 0, /* TT_MAC_LANGID_RUNDI */
1310 0, /* TT_MAC_LANGID_CHEWA */
1311 MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */
1312 MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */
1313 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
1314 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
1315 MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */
1316 MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */
1317 MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */
1318 0, /* TT_MAC_LANGID_LATIN */
1319 MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */
1320 0, /* TT_MAC_LANGID_GUARANI */
1321 0, /* TT_MAC_LANGID_AYMARA */
1322 MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */
1323 MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */
1324 0, /* TT_MAC_LANGID_DZONGKHA */
1325 0, /* TT_MAC_LANGID_JAVANESE */
1326 0, /* TT_MAC_LANGID_SUNDANESE */
1327 MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */
1328 MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */
1329 MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */
1330 MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */
1331 MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
1332 MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */
1333 MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */
1334 0, /* TT_MAC_LANGID_TONGAN */
1335 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
1336 MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */
1337 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
1340 static inline WORD get_mac_code_page( const FT_SfntName *name )
1342 if (name->encoding_id == TT_MAC_ID_SIMPLIFIED_CHINESE) return 10008; /* special case */
1343 return 10000 + name->encoding_id;
1346 static int match_name_table_language( const FT_SfntName *name, LANGID lang )
1348 LANGID name_lang;
1349 int res = 0;
1351 switch (name->platform_id)
1353 case TT_PLATFORM_MICROSOFT:
1354 res += 5; /* prefer the Microsoft name */
1355 switch (name->encoding_id)
1357 case TT_MS_ID_UNICODE_CS:
1358 case TT_MS_ID_SYMBOL_CS:
1359 name_lang = name->language_id;
1360 break;
1361 default:
1362 return 0;
1364 break;
1365 case TT_PLATFORM_MACINTOSH:
1366 if (!IsValidCodePage( get_mac_code_page( name ))) return 0;
1367 if (name->language_id >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
1368 name_lang = mac_langid_table[name->language_id];
1369 break;
1370 case TT_PLATFORM_APPLE_UNICODE:
1371 res += 2; /* prefer Unicode encodings */
1372 switch (name->encoding_id)
1374 case TT_APPLE_ID_DEFAULT:
1375 case TT_APPLE_ID_ISO_10646:
1376 case TT_APPLE_ID_UNICODE_2_0:
1377 if (name->language_id >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
1378 name_lang = mac_langid_table[name->language_id];
1379 break;
1380 default:
1381 return 0;
1383 break;
1384 default:
1385 return 0;
1387 if (name_lang == lang) res += 30;
1388 else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20;
1389 else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10;
1390 return res;
1393 static WCHAR *copy_name_table_string( const FT_SfntName *name )
1395 WCHAR *ret;
1396 WORD codepage;
1397 int i;
1399 switch (name->platform_id)
1401 case TT_PLATFORM_APPLE_UNICODE:
1402 case TT_PLATFORM_MICROSOFT:
1403 ret = HeapAlloc( GetProcessHeap(), 0, name->string_len + sizeof(WCHAR) );
1404 for (i = 0; i < name->string_len / 2; i++)
1405 ret[i] = (name->string[i * 2] << 8) | name->string[i * 2 + 1];
1406 ret[i] = 0;
1407 return ret;
1408 case TT_PLATFORM_MACINTOSH:
1409 codepage = get_mac_code_page( name );
1410 i = MultiByteToWideChar( codepage, 0, (char *)name->string, name->string_len, NULL, 0 );
1411 ret = HeapAlloc( GetProcessHeap(), 0, (i + 1) * sizeof(WCHAR) );
1412 MultiByteToWideChar( codepage, 0, (char *)name->string, name->string_len, ret, i );
1413 ret[i] = 0;
1414 return ret;
1416 return NULL;
1419 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, LANGID language_id)
1421 FT_SfntName name;
1422 FT_UInt num_names, name_index;
1423 int res, best_lang = 0, best_index = -1;
1425 if (!FT_IS_SFNT(ft_face)) return NULL;
1427 num_names = pFT_Get_Sfnt_Name_Count( ft_face );
1429 for (name_index = 0; name_index < num_names; name_index++)
1431 if (pFT_Get_Sfnt_Name( ft_face, name_index, &name )) continue;
1432 if (name.name_id != name_id) continue;
1433 res = match_name_table_language( &name, language_id );
1434 if (res > best_lang)
1436 best_lang = res;
1437 best_index = name_index;
1441 if (best_index != -1 && !pFT_Get_Sfnt_Name( ft_face, best_index, &name ))
1443 WCHAR *ret = copy_name_table_string( &name );
1444 TRACE( "name %u found platform %u lang %04x %s\n",
1445 name_id, name.platform_id, name.language_id, debugstr_w( ret ));
1446 return ret;
1448 return NULL;
1451 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1453 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1454 if (f1->scalable) return TRUE;
1455 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1456 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1459 static void release_family( Family *family )
1461 if (--family->refcount) return;
1462 assert( list_empty( &family->faces ));
1463 list_remove( &family->entry );
1464 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1465 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1466 HeapFree( GetProcessHeap(), 0, family );
1469 static void release_face( Face *face )
1471 if (--face->refcount) return;
1472 if (face->family)
1474 if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
1475 list_remove( &face->entry );
1476 release_family( face->family );
1478 HeapFree( GetProcessHeap(), 0, face->file );
1479 HeapFree( GetProcessHeap(), 0, face->StyleName );
1480 HeapFree( GetProcessHeap(), 0, face->FullName );
1481 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1482 HeapFree( GetProcessHeap(), 0, face );
1485 static inline int style_order(const Face *face)
1487 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1489 case NTM_REGULAR:
1490 return 0;
1491 case NTM_BOLD:
1492 return 1;
1493 case NTM_ITALIC:
1494 return 2;
1495 case NTM_BOLD | NTM_ITALIC:
1496 return 3;
1497 default:
1498 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1499 debugstr_w(face->family->FamilyName),
1500 debugstr_w(face->StyleName),
1501 face->ntmFlags);
1502 return 9999;
1506 static BOOL insert_face_in_family_list( Face *face, Family *family )
1508 Face *cursor;
1510 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1512 if (faces_equal( face, cursor ))
1514 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1515 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1516 cursor->font_version, face->font_version);
1518 if (face->file && face->dev == cursor->dev && face->ino == cursor->ino)
1520 cursor->refcount++;
1521 TRACE("Font %s already in list, refcount now %d\n",
1522 debugstr_w(face->file), cursor->refcount);
1523 return FALSE;
1525 if (face->font_version <= cursor->font_version)
1527 TRACE("Original font %s is newer so skipping %s\n",
1528 debugstr_w(cursor->file), debugstr_w(face->file));
1529 return FALSE;
1531 else
1533 TRACE("Replacing original %s with %s\n",
1534 debugstr_w(cursor->file), debugstr_w(face->file));
1535 list_add_before( &cursor->entry, &face->entry );
1536 face->family = family;
1537 family->refcount++;
1538 face->refcount++;
1539 release_face( cursor );
1540 return TRUE;
1543 else
1544 TRACE("Adding new %s\n", debugstr_w(face->file));
1546 if (style_order( face ) < style_order( cursor )) break;
1549 list_add_before( &cursor->entry, &face->entry );
1550 face->family = family;
1551 family->refcount++;
1552 face->refcount++;
1553 return TRUE;
1556 /****************************************************************
1557 * NB This function stores the ptrs to the strings to save copying.
1558 * Don't free them after calling.
1560 static Family *create_family( WCHAR *name, WCHAR *english_name )
1562 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1563 family->refcount = 1;
1564 family->FamilyName = name;
1565 family->EnglishName = english_name;
1566 list_init( &family->faces );
1567 family->replacement = &family->faces;
1568 list_add_tail( &font_list, &family->entry );
1570 return family;
1573 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1575 DWORD type, size = sizeof(DWORD);
1577 if (RegQueryValueExW(hkey, value, NULL, &type, (BYTE *)data, &size) ||
1578 type != REG_DWORD || size != sizeof(DWORD))
1580 *data = 0;
1581 return ERROR_BAD_CONFIGURATION;
1583 return ERROR_SUCCESS;
1586 static inline LONG reg_load_ftlong(HKEY hkey, const WCHAR *value, FT_Long *data)
1588 DWORD dw;
1589 LONG ret = reg_load_dword(hkey, value, &dw);
1590 *data = dw;
1591 return ret;
1594 static inline LONG reg_load_ftshort(HKEY hkey, const WCHAR *value, FT_Short *data)
1596 DWORD dw;
1597 LONG ret = reg_load_dword(hkey, value, &dw);
1598 *data = dw;
1599 return ret;
1602 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1604 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1607 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1609 DWORD needed, strike_index = 0;
1610 HKEY hkey_strike;
1612 /* If we have a File Name key then this is a real font, not just the parent
1613 key of a bunch of non-scalable strikes */
1614 needed = buffer_size;
1615 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1617 Face *face;
1618 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1619 face->cached_enum_data = NULL;
1620 face->family = NULL;
1622 face->refcount = 1;
1623 face->file = strdupW( buffer );
1624 face->StyleName = strdupW(face_name);
1626 needed = buffer_size;
1627 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1628 face->FullName = strdupW( buffer );
1629 else
1630 face->FullName = NULL;
1632 reg_load_ftlong(hkey_face, face_index_value, &face->face_index);
1633 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1634 reg_load_ftlong(hkey_face, face_version_value, &face->font_version);
1635 reg_load_dword(hkey_face, face_flags_value, &face->flags);
1637 needed = sizeof(face->fs);
1638 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1640 if(reg_load_ftshort(hkey_face, face_height_value, &face->size.height) != ERROR_SUCCESS)
1642 face->scalable = TRUE;
1643 memset(&face->size, 0, sizeof(face->size));
1645 else
1647 face->scalable = FALSE;
1648 reg_load_ftshort(hkey_face, face_width_value, &face->size.width);
1649 reg_load_ftlong(hkey_face, face_size_value, &face->size.size);
1650 reg_load_ftlong(hkey_face, face_x_ppem_value, &face->size.x_ppem);
1651 reg_load_ftlong(hkey_face, face_y_ppem_value, &face->size.y_ppem);
1652 reg_load_ftshort(hkey_face, face_internal_leading_value, &face->size.internal_leading);
1654 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1655 face->size.height, face->size.width, face->size.size >> 6,
1656 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1659 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1660 face->fs.fsCsb[0], face->fs.fsCsb[1],
1661 face->fs.fsUsb[0], face->fs.fsUsb[1],
1662 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1664 if (insert_face_in_family_list(face, family))
1665 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1667 release_face( face );
1670 /* load bitmap strikes */
1672 needed = buffer_size;
1673 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1675 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1677 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1678 RegCloseKey(hkey_strike);
1680 needed = buffer_size;
1684 /* move vertical fonts after their horizontal counterpart */
1685 /* assumes that font_list is already sorted by family name */
1686 static void reorder_vertical_fonts(void)
1688 Family *family, *next, *vert_family;
1689 struct list *ptr, *vptr;
1690 struct list vertical_families = LIST_INIT( vertical_families );
1692 LIST_FOR_EACH_ENTRY_SAFE( family, next, &font_list, Family, entry )
1694 if (family->FamilyName[0] != '@') continue;
1695 list_remove( &family->entry );
1696 list_add_tail( &vertical_families, &family->entry );
1699 ptr = list_head( &font_list );
1700 vptr = list_head( &vertical_families );
1701 while (ptr && vptr)
1703 family = LIST_ENTRY( ptr, Family, entry );
1704 vert_family = LIST_ENTRY( vptr, Family, entry );
1705 if (strcmpiW( family->FamilyName, vert_family->FamilyName + 1 ) > 0)
1707 list_remove( vptr );
1708 list_add_before( ptr, vptr );
1709 vptr = list_head( &vertical_families );
1711 else ptr = list_next( &font_list, ptr );
1713 list_move_tail( &font_list, &vertical_families );
1716 static void load_font_list_from_cache(HKEY hkey_font_cache)
1718 DWORD size, family_index = 0;
1719 Family *family;
1720 HKEY hkey_family;
1721 WCHAR buffer[4096];
1723 size = sizeof(buffer);
1724 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1726 WCHAR *english_family = NULL;
1727 WCHAR *family_name = strdupW( buffer );
1728 DWORD face_index = 0;
1730 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1731 TRACE("opened family key %s\n", debugstr_w(family_name));
1732 size = sizeof(buffer);
1733 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1734 english_family = strdupW( buffer );
1736 family = create_family(family_name, english_family);
1738 if(english_family)
1740 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1741 subst->from.name = strdupW(english_family);
1742 subst->from.charset = -1;
1743 subst->to.name = strdupW(family_name);
1744 subst->to.charset = -1;
1745 add_font_subst(&font_subst_list, subst, 0);
1748 size = sizeof(buffer);
1749 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1751 WCHAR *face_name = strdupW( buffer );
1752 HKEY hkey_face;
1754 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1756 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1757 RegCloseKey(hkey_face);
1759 HeapFree( GetProcessHeap(), 0, face_name );
1760 size = sizeof(buffer);
1762 RegCloseKey(hkey_family);
1763 release_family( family );
1764 size = sizeof(buffer);
1767 reorder_vertical_fonts();
1770 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1772 LONG ret;
1773 HKEY hkey_wine_fonts;
1775 /* We don't want to create the fonts key as volatile, so open this first */
1776 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1777 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1778 if(ret != ERROR_SUCCESS)
1780 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1781 return ret;
1784 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1785 KEY_ALL_ACCESS, NULL, hkey, disposition);
1786 RegCloseKey(hkey_wine_fonts);
1787 return ret;
1790 static void add_face_to_cache(Face *face)
1792 HKEY hkey_family, hkey_face;
1793 WCHAR *face_key_name;
1795 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1796 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1797 if(face->family->EnglishName)
1798 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1799 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1801 if(face->scalable)
1802 face_key_name = face->StyleName;
1803 else
1805 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1806 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1807 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1809 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1810 &hkey_face, NULL);
1811 if(!face->scalable)
1812 HeapFree(GetProcessHeap(), 0, face_key_name);
1814 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1815 (strlenW(face->file) + 1) * sizeof(WCHAR));
1816 if (face->FullName)
1817 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1818 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1820 reg_save_dword(hkey_face, face_index_value, face->face_index);
1821 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1822 reg_save_dword(hkey_face, face_version_value, face->font_version);
1823 if (face->flags) reg_save_dword(hkey_face, face_flags_value, face->flags);
1825 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1827 if(!face->scalable)
1829 reg_save_dword(hkey_face, face_height_value, face->size.height);
1830 reg_save_dword(hkey_face, face_width_value, face->size.width);
1831 reg_save_dword(hkey_face, face_size_value, face->size.size);
1832 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1833 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1834 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1836 RegCloseKey(hkey_face);
1837 RegCloseKey(hkey_family);
1840 static void remove_face_from_cache( Face *face )
1842 HKEY hkey_family;
1844 RegOpenKeyExW( hkey_font_cache, face->family->FamilyName, 0, KEY_ALL_ACCESS, &hkey_family );
1846 if (face->scalable)
1848 RegDeleteKeyW( hkey_family, face->StyleName );
1850 else
1852 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1853 WCHAR *face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1854 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1855 RegDeleteKeyW( hkey_family, face_key_name );
1856 HeapFree(GetProcessHeap(), 0, face_key_name);
1858 RegCloseKey(hkey_family);
1861 static WCHAR *prepend_at(WCHAR *family)
1863 WCHAR *str;
1865 if (!family)
1866 return NULL;
1868 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1869 str[0] = '@';
1870 strcpyW(str + 1, family);
1871 HeapFree(GetProcessHeap(), 0, family);
1872 return str;
1875 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1877 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT) );
1878 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1880 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1881 if (!*name)
1883 *name = *english;
1884 *english = NULL;
1886 else if (!strcmpiW( *name, *english ))
1888 HeapFree( GetProcessHeap(), 0, *english );
1889 *english = NULL;
1892 if (vertical)
1894 *name = prepend_at( *name );
1895 *english = prepend_at( *english );
1899 static Family *get_family( FT_Face ft_face, BOOL vertical )
1901 Family *family;
1902 WCHAR *name, *english_name;
1904 get_family_names( ft_face, &name, &english_name, vertical );
1906 family = find_family_from_name( name );
1908 if (!family)
1910 family = create_family( name, english_name );
1911 if (english_name)
1913 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1914 subst->from.name = strdupW( english_name );
1915 subst->from.charset = -1;
1916 subst->to.name = strdupW( name );
1917 subst->to.charset = -1;
1918 add_font_subst( &font_subst_list, subst, 0 );
1921 else
1923 HeapFree( GetProcessHeap(), 0, name );
1924 HeapFree( GetProcessHeap(), 0, english_name );
1925 family->refcount++;
1928 return family;
1931 static inline FT_Fixed get_font_version( FT_Face ft_face )
1933 FT_Fixed version = 0;
1934 TT_Header *header;
1936 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1937 if (header) version = header->Font_Revision;
1939 return version;
1942 static inline DWORD get_ntm_flags( FT_Face ft_face )
1944 DWORD flags = 0;
1945 FT_ULong table_size = 0;
1946 FT_WinFNT_HeaderRec winfnt_header;
1948 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1949 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1951 /* fixup the flag for our fake-bold implementation. */
1952 if (!FT_IS_SCALABLE( ft_face ) &&
1953 !pFT_Get_WinFNT_Header( ft_face, &winfnt_header ) &&
1954 winfnt_header.weight > FW_NORMAL )
1955 flags |= NTM_BOLD;
1957 if (flags == 0) flags = NTM_REGULAR;
1959 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1960 flags |= NTM_PS_OPENTYPE;
1962 return flags;
1965 static inline void get_bitmap_size( FT_Face ft_face, Bitmap_Size *face_size )
1967 My_FT_Bitmap_Size *size;
1968 FT_WinFNT_HeaderRec winfnt_header;
1970 size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1971 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1972 size->height, size->width, size->size >> 6,
1973 size->x_ppem >> 6, size->y_ppem >> 6);
1974 face_size->height = size->height;
1975 face_size->width = size->width;
1976 face_size->size = size->size;
1977 face_size->x_ppem = size->x_ppem;
1978 face_size->y_ppem = size->y_ppem;
1980 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header )) {
1981 face_size->internal_leading = winfnt_header.internal_leading;
1982 if (winfnt_header.external_leading > 0 &&
1983 (face_size->height ==
1984 winfnt_header.pixel_height + winfnt_header.external_leading))
1985 face_size->height = winfnt_header.pixel_height;
1989 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1991 TT_OS2 *os2;
1992 FT_UInt dummy;
1993 CHARSETINFO csi;
1994 FT_WinFNT_HeaderRec winfnt_header;
1995 int i;
1997 memset( fs, 0, sizeof(*fs) );
1999 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
2000 if (os2)
2002 fs->fsUsb[0] = os2->ulUnicodeRange1;
2003 fs->fsUsb[1] = os2->ulUnicodeRange2;
2004 fs->fsUsb[2] = os2->ulUnicodeRange3;
2005 fs->fsUsb[3] = os2->ulUnicodeRange4;
2007 if (os2->version == 0)
2009 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
2010 fs->fsCsb[0] = FS_LATIN1;
2011 else
2012 fs->fsCsb[0] = FS_SYMBOL;
2014 else
2016 fs->fsCsb[0] = os2->ulCodePageRange1;
2017 fs->fsCsb[1] = os2->ulCodePageRange2;
2020 else
2022 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
2024 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
2025 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
2026 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
2027 *fs = csi.fs;
2031 if (fs->fsCsb[0] == 0)
2033 /* let's see if we can find any interesting cmaps */
2034 for (i = 0; i < ft_face->num_charmaps; i++)
2036 switch (ft_face->charmaps[i]->encoding)
2038 case FT_ENCODING_UNICODE:
2039 case FT_ENCODING_APPLE_ROMAN:
2040 fs->fsCsb[0] |= FS_LATIN1;
2041 break;
2042 case FT_ENCODING_MS_SYMBOL:
2043 fs->fsCsb[0] |= FS_SYMBOL;
2044 break;
2045 default:
2046 break;
2052 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
2053 DWORD flags )
2055 struct stat st;
2056 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
2058 face->refcount = 1;
2059 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
2060 if (!face->StyleName) face->StyleName = towstr( CP_ACP, ft_face->style_name );
2062 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
2063 if (flags & ADDFONT_VERTICAL_FONT)
2064 face->FullName = prepend_at( face->FullName );
2066 face->dev = 0;
2067 face->ino = 0;
2068 if (file)
2070 face->file = towstr( CP_UNIXCP, file );
2071 face->font_data_ptr = NULL;
2072 face->font_data_size = 0;
2073 if (!stat( file, &st ))
2075 face->dev = st.st_dev;
2076 face->ino = st.st_ino;
2079 else
2081 face->file = NULL;
2082 face->font_data_ptr = font_data_ptr;
2083 face->font_data_size = font_data_size;
2086 face->face_index = face_index;
2087 get_fontsig( ft_face, &face->fs );
2088 face->ntmFlags = get_ntm_flags( ft_face );
2089 face->font_version = get_font_version( ft_face );
2091 if (FT_IS_SCALABLE( ft_face ))
2093 memset( &face->size, 0, sizeof(face->size) );
2094 face->scalable = TRUE;
2096 else
2098 get_bitmap_size( ft_face, &face->size );
2099 face->scalable = FALSE;
2102 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
2103 face->flags = flags;
2104 face->family = NULL;
2105 face->cached_enum_data = NULL;
2107 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
2108 face->fs.fsCsb[0], face->fs.fsCsb[1],
2109 face->fs.fsUsb[0], face->fs.fsUsb[1],
2110 face->fs.fsUsb[2], face->fs.fsUsb[3]);
2112 return face;
2115 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
2116 FT_Long face_index, DWORD flags )
2118 Face *face;
2119 Family *family;
2121 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags );
2122 family = get_family( ft_face, flags & ADDFONT_VERTICAL_FONT );
2123 if (strlenW(family->FamilyName) >= LF_FACESIZE)
2125 WARN("Ignoring %s because name is too long\n", debugstr_w(family->FamilyName));
2126 release_face( face );
2127 release_family( family );
2128 return;
2131 if (insert_face_in_family_list( face, family ))
2133 if (flags & ADDFONT_ADD_TO_CACHE)
2134 add_face_to_cache( face );
2136 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
2137 debugstr_w(face->StyleName));
2139 release_face( face );
2140 release_family( family );
2143 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
2144 FT_Long face_index, BOOL allow_bitmap )
2146 FT_Error err;
2147 TT_OS2 *pOS2;
2148 FT_Face ft_face;
2150 if (file)
2152 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
2153 err = pFT_New_Face(library, file, face_index, &ft_face);
2155 else
2157 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
2158 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
2161 if (err != 0)
2163 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
2164 return NULL;
2167 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
2168 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
2170 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
2171 goto fail;
2174 if (!FT_IS_SFNT( ft_face ))
2176 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
2178 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
2179 goto fail;
2182 else
2184 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
2185 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
2186 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
2188 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
2189 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
2190 goto fail;
2193 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
2194 we don't want to load these. */
2195 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
2197 FT_ULong len = 0;
2199 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
2201 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
2202 goto fail;
2207 if (!ft_face->family_name || !ft_face->style_name)
2209 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
2210 goto fail;
2213 return ft_face;
2214 fail:
2215 pFT_Done_Face( ft_face );
2216 return NULL;
2219 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
2221 FT_Face ft_face;
2222 FT_Long face_index = 0, num_faces;
2223 INT ret = 0;
2225 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
2226 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
2228 #ifdef HAVE_CARBON_CARBON_H
2229 if(file)
2231 char **mac_list = expand_mac_font(file);
2232 if(mac_list)
2234 BOOL had_one = FALSE;
2235 char **cursor;
2236 for(cursor = mac_list; *cursor; cursor++)
2238 had_one = TRUE;
2239 AddFontToList(*cursor, NULL, 0, flags);
2240 HeapFree(GetProcessHeap(), 0, *cursor);
2242 HeapFree(GetProcessHeap(), 0, mac_list);
2243 if(had_one)
2244 return 1;
2247 #endif /* HAVE_CARBON_CARBON_H */
2249 do {
2250 const DWORD FS_DBCS_MASK = FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB;
2251 FONTSIGNATURE fs;
2253 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_ALLOW_BITMAP );
2254 if (!ft_face) return 0;
2256 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
2258 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
2259 pFT_Done_Face(ft_face);
2260 return 0;
2263 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags);
2264 ++ret;
2266 get_fontsig(ft_face, &fs);
2267 if (fs.fsCsb[0] & FS_DBCS_MASK)
2269 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index,
2270 flags | ADDFONT_VERTICAL_FONT);
2271 ++ret;
2274 num_faces = ft_face->num_faces;
2275 pFT_Done_Face(ft_face);
2276 } while(num_faces > ++face_index);
2277 return ret;
2280 static int remove_font_resource( const char *file, DWORD flags )
2282 Family *family, *family_next;
2283 Face *face, *face_next;
2284 struct stat st;
2285 int count = 0;
2287 if (stat( file, &st ) == -1) return 0;
2288 LIST_FOR_EACH_ENTRY_SAFE( family, family_next, &font_list, Family, entry )
2290 family->refcount++;
2291 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, Face, entry )
2293 if (!face->file) continue;
2294 if (LOWORD(face->flags) != LOWORD(flags)) continue;
2295 if (st.st_dev == face->dev && st.st_ino == face->ino)
2297 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount );
2298 release_face( face );
2299 count++;
2302 release_family( family );
2304 return count;
2307 static void DumpFontList(void)
2309 Family *family;
2310 Face *face;
2312 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2313 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
2314 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2315 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
2316 if(!face->scalable)
2317 TRACE(" %d", face->size.height);
2318 TRACE("\n");
2323 static BOOL map_font_family(const WCHAR *orig, const WCHAR *repl)
2325 Family *family = find_family_from_any_name(repl);
2326 if (family != NULL)
2328 Family *new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2329 if (new_family != NULL)
2331 TRACE("mapping %s to %s\n", debugstr_w(repl), debugstr_w(orig));
2332 new_family->FamilyName = strdupW(orig);
2333 new_family->EnglishName = NULL;
2334 list_init(&new_family->faces);
2335 new_family->replacement = &family->faces;
2336 list_add_tail(&font_list, &new_family->entry);
2337 return TRUE;
2340 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(repl));
2341 return FALSE;
2344 /***********************************************************
2345 * The replacement list is a way to map an entire font
2346 * family onto another family. For example adding
2348 * [HKCU\Software\Wine\Fonts\Replacements]
2349 * "Wingdings"="Winedings"
2351 * would enumerate the Winedings font both as Winedings and
2352 * Wingdings. However if a real Wingdings font is present the
2353 * replacement does not take place.
2356 static void LoadReplaceList(void)
2358 HKEY hkey;
2359 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2360 LPWSTR value;
2361 LPVOID data;
2363 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2364 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
2366 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2367 &valuelen, &datalen, NULL, NULL);
2369 valuelen++; /* returned value doesn't include room for '\0' */
2370 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2371 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2373 dlen = datalen;
2374 vlen = valuelen;
2375 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data, &dlen) == ERROR_SUCCESS)
2377 /* "NewName"="Oldname" */
2378 if(!find_family_from_any_name(value))
2380 if (type == REG_MULTI_SZ)
2382 WCHAR *replace = data;
2383 while(*replace)
2385 if (map_font_family(value, replace))
2386 break;
2387 replace += strlenW(replace) + 1;
2390 else if (type == REG_SZ)
2391 map_font_family(value, data);
2393 else
2394 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2396 /* reset dlen and vlen */
2397 dlen = datalen;
2398 vlen = valuelen;
2400 HeapFree(GetProcessHeap(), 0, data);
2401 HeapFree(GetProcessHeap(), 0, value);
2402 RegCloseKey(hkey);
2406 static const WCHAR *font_links_list[] =
2408 Lucida_Sans_Unicode,
2409 Microsoft_Sans_Serif,
2410 Tahoma
2413 static const struct font_links_defaults_list
2415 /* Keyed off substitution for "MS Shell Dlg" */
2416 const WCHAR *shelldlg;
2417 /* Maximum of four substitutes, plus terminating NULL pointer */
2418 const WCHAR *substitutes[5];
2419 } font_links_defaults_list[] =
2421 /* Non East-Asian */
2422 { Tahoma, /* FIXME unverified ordering */
2423 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2425 /* Below lists are courtesy of
2426 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2428 /* Japanese */
2429 { MS_UI_Gothic,
2430 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2432 /* Chinese Simplified */
2433 { SimSun,
2434 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2436 /* Korean */
2437 { Gulim,
2438 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2440 /* Chinese Traditional */
2441 { PMingLiU,
2442 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2447 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2449 SYSTEM_LINKS *font_link;
2451 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2453 if(!strcmpiW(font_link->font_name, name))
2454 return font_link;
2457 return NULL;
2460 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2462 const WCHAR *value;
2463 int i;
2464 FontSubst *psub;
2465 Family *family;
2466 Face *face;
2467 const WCHAR *file;
2469 if (values)
2471 SYSTEM_LINKS *font_link;
2473 psub = get_font_subst(&font_subst_list, name, -1);
2474 /* Don't store fonts that are only substitutes for other fonts */
2475 if(psub)
2477 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2478 return;
2481 font_link = find_font_link(name);
2482 if (font_link == NULL)
2484 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2485 font_link->font_name = strdupW(name);
2486 list_init(&font_link->links);
2487 list_add_tail(&system_links, &font_link->entry);
2490 memset(&font_link->fs, 0, sizeof font_link->fs);
2491 for (i = 0; values[i] != NULL; i++)
2493 const struct list *face_list;
2494 CHILD_FONT *child_font;
2496 value = values[i];
2497 if (!strcmpiW(name,value))
2498 continue;
2499 psub = get_font_subst(&font_subst_list, value, -1);
2500 if(psub)
2501 value = psub->to.name;
2502 family = find_family_from_name(value);
2503 if (!family)
2504 continue;
2505 file = NULL;
2506 /* Use first extant filename for this Family */
2507 face_list = get_face_list_from_family(family);
2508 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2510 if (!face->file)
2511 continue;
2512 file = strrchrW(face->file, '/');
2513 if (!file)
2514 file = face->file;
2515 else
2516 file++;
2517 break;
2519 if (!file)
2520 continue;
2521 face = find_face_from_filename(file, value);
2522 if(!face)
2524 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2525 continue;
2528 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2529 child_font->face = face;
2530 child_font->font = NULL;
2531 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2532 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2533 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2534 child_font->face->face_index);
2535 list_add_tail(&font_link->links, &child_font->entry);
2537 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2543 /*************************************************************
2544 * init_system_links
2546 static BOOL init_system_links(void)
2548 HKEY hkey;
2549 BOOL ret = FALSE;
2550 DWORD type, max_val, max_data, val_len, data_len, index;
2551 WCHAR *value, *data;
2552 WCHAR *entry, *next;
2553 SYSTEM_LINKS *font_link, *system_font_link;
2554 CHILD_FONT *child_font;
2555 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2556 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2557 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2558 Face *face;
2559 FontSubst *psub;
2560 UINT i, j;
2562 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2564 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2565 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2566 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2567 val_len = max_val + 1;
2568 data_len = max_data;
2569 index = 0;
2570 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2572 psub = get_font_subst(&font_subst_list, value, -1);
2573 /* Don't store fonts that are only substitutes for other fonts */
2574 if(psub)
2576 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2577 goto next;
2579 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2580 font_link->font_name = strdupW(value);
2581 memset(&font_link->fs, 0, sizeof font_link->fs);
2582 list_init(&font_link->links);
2583 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2585 WCHAR *face_name;
2586 CHILD_FONT *child_font;
2588 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2590 next = entry + strlenW(entry) + 1;
2592 face_name = strchrW(entry, ',');
2593 if(face_name)
2595 *face_name++ = 0;
2596 while(isspaceW(*face_name))
2597 face_name++;
2599 psub = get_font_subst(&font_subst_list, face_name, -1);
2600 if(psub)
2601 face_name = psub->to.name;
2603 face = find_face_from_filename(entry, face_name);
2604 if(!face)
2606 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2607 continue;
2610 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2611 child_font->face = face;
2612 child_font->font = NULL;
2613 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2614 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2615 TRACE("Adding file %s index %ld\n",
2616 debugstr_w(child_font->face->file), child_font->face->face_index);
2617 list_add_tail(&font_link->links, &child_font->entry);
2619 list_add_tail(&system_links, &font_link->entry);
2620 next:
2621 val_len = max_val + 1;
2622 data_len = max_data;
2625 HeapFree(GetProcessHeap(), 0, value);
2626 HeapFree(GetProcessHeap(), 0, data);
2627 RegCloseKey(hkey);
2631 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2632 if (!psub) {
2633 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2634 goto skip_internal;
2637 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2639 const FontSubst *psub2;
2640 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2642 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2644 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2645 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2647 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2648 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2650 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2652 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2656 skip_internal:
2658 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2659 that Tahoma has */
2661 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2662 system_font_link->font_name = strdupW(System);
2663 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2664 list_init(&system_font_link->links);
2666 face = find_face_from_filename(tahoma_ttf, Tahoma);
2667 if(face)
2669 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2670 child_font->face = face;
2671 child_font->font = NULL;
2672 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2673 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2674 TRACE("Found Tahoma in %s index %ld\n",
2675 debugstr_w(child_font->face->file), child_font->face->face_index);
2676 list_add_tail(&system_font_link->links, &child_font->entry);
2678 font_link = find_font_link(Tahoma);
2679 if (font_link != NULL)
2681 CHILD_FONT *font_link_entry;
2682 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2684 CHILD_FONT *new_child;
2685 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2686 new_child->face = font_link_entry->face;
2687 new_child->font = NULL;
2688 new_child->face->refcount++;
2689 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2690 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2691 list_add_tail(&system_font_link->links, &new_child->entry);
2694 list_add_tail(&system_links, &system_font_link->entry);
2695 return ret;
2698 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2700 DIR *dir;
2701 struct dirent *dent;
2702 char path[MAX_PATH];
2704 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2706 dir = opendir(dirname);
2707 if(!dir) {
2708 WARN("Can't open directory %s\n", debugstr_a(dirname));
2709 return FALSE;
2711 while((dent = readdir(dir)) != NULL) {
2712 struct stat statbuf;
2714 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2715 continue;
2717 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2719 sprintf(path, "%s/%s", dirname, dent->d_name);
2721 if(stat(path, &statbuf) == -1)
2723 WARN("Can't stat %s\n", debugstr_a(path));
2724 continue;
2726 if(S_ISDIR(statbuf.st_mode))
2727 ReadFontDir(path, external_fonts);
2728 else
2730 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2731 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2732 AddFontToList(path, NULL, 0, addfont_flags);
2735 closedir(dir);
2736 return TRUE;
2739 #ifdef SONAME_LIBFONTCONFIG
2741 static BOOL fontconfig_enabled;
2743 static UINT parse_aa_pattern( FcPattern *pattern )
2745 FcBool antialias;
2746 int rgba;
2747 UINT aa_flags = 0;
2749 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2750 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2752 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2754 switch (rgba)
2756 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2757 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2758 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2759 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2760 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2763 return aa_flags;
2766 static void init_fontconfig(void)
2768 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2770 if (!fc_handle)
2772 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2773 return;
2776 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2777 LOAD_FUNCPTR(FcConfigSubstitute);
2778 LOAD_FUNCPTR(FcFontList);
2779 LOAD_FUNCPTR(FcFontSetDestroy);
2780 LOAD_FUNCPTR(FcInit);
2781 LOAD_FUNCPTR(FcObjectSetAdd);
2782 LOAD_FUNCPTR(FcObjectSetCreate);
2783 LOAD_FUNCPTR(FcObjectSetDestroy);
2784 LOAD_FUNCPTR(FcPatternCreate);
2785 LOAD_FUNCPTR(FcPatternDestroy);
2786 LOAD_FUNCPTR(FcPatternGetBool);
2787 LOAD_FUNCPTR(FcPatternGetInteger);
2788 LOAD_FUNCPTR(FcPatternGetString);
2789 #undef LOAD_FUNCPTR
2791 if (pFcInit())
2793 FcPattern *pattern = pFcPatternCreate();
2794 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2795 default_aa_flags = parse_aa_pattern( pattern );
2796 pFcPatternDestroy( pattern );
2797 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2798 fontconfig_enabled = TRUE;
2802 static void load_fontconfig_fonts(void)
2804 FcPattern *pat;
2805 FcObjectSet *os;
2806 FcFontSet *fontset;
2807 int i, len;
2808 char *file;
2809 const char *ext;
2811 if (!fontconfig_enabled) return;
2813 pat = pFcPatternCreate();
2814 os = pFcObjectSetCreate();
2815 pFcObjectSetAdd(os, FC_FILE);
2816 pFcObjectSetAdd(os, FC_SCALABLE);
2817 pFcObjectSetAdd(os, FC_ANTIALIAS);
2818 pFcObjectSetAdd(os, FC_RGBA);
2819 fontset = pFcFontList(NULL, pat, os);
2820 if(!fontset) return;
2821 for(i = 0; i < fontset->nfont; i++) {
2822 FcBool scalable;
2823 DWORD aa_flags;
2825 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2826 continue;
2828 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2830 /* We're just interested in OT/TT fonts for now, so this hack just
2831 picks up the scalable fonts without extensions .pf[ab] to save time
2832 loading every other font */
2834 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2836 TRACE("not scalable\n");
2837 continue;
2840 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2841 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2843 len = strlen( file );
2844 if(len < 4) continue;
2845 ext = &file[ len - 3 ];
2846 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2847 AddFontToList(file, NULL, 0,
2848 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2850 pFcFontSetDestroy(fontset);
2851 pFcObjectSetDestroy(os);
2852 pFcPatternDestroy(pat);
2855 #elif defined(HAVE_CARBON_CARBON_H)
2857 static void load_mac_font_callback(const void *value, void *context)
2859 CFStringRef pathStr = value;
2860 CFIndex len;
2861 char* path;
2863 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2864 path = HeapAlloc(GetProcessHeap(), 0, len);
2865 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2867 TRACE("font file %s\n", path);
2868 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2870 HeapFree(GetProcessHeap(), 0, path);
2873 static void load_mac_fonts(void)
2875 CFStringRef removeDupesKey;
2876 CFBooleanRef removeDupesValue;
2877 CFDictionaryRef options;
2878 CTFontCollectionRef col;
2879 CFArrayRef descs;
2880 CFMutableSetRef paths;
2881 CFIndex i;
2883 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2884 removeDupesValue = kCFBooleanTrue;
2885 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2886 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2887 col = CTFontCollectionCreateFromAvailableFonts(options);
2888 if (options) CFRelease(options);
2889 if (!col)
2891 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2892 return;
2895 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2896 CFRelease(col);
2897 if (!descs)
2899 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2900 return;
2903 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2904 if (!paths)
2906 WARN("CFSetCreateMutable failed\n");
2907 CFRelease(descs);
2908 return;
2911 for (i = 0; i < CFArrayGetCount(descs); i++)
2913 CTFontDescriptorRef desc;
2914 CTFontRef font;
2915 ATSFontRef atsFont;
2916 OSStatus status;
2917 FSRef fsref;
2918 CFURLRef url;
2919 CFStringRef ext;
2920 CFStringRef path;
2922 desc = CFArrayGetValueAtIndex(descs, i);
2924 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2925 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2926 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2927 if (!font) continue;
2929 atsFont = CTFontGetPlatformFont(font, NULL);
2930 if (!atsFont)
2932 CFRelease(font);
2933 continue;
2936 status = ATSFontGetFileReference(atsFont, &fsref);
2937 CFRelease(font);
2938 if (status != noErr) continue;
2940 url = CFURLCreateFromFSRef(NULL, &fsref);
2941 if (!url) continue;
2943 ext = CFURLCopyPathExtension(url);
2944 if (ext)
2946 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2947 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2948 CFRelease(ext);
2949 if (skip)
2951 CFRelease(url);
2952 continue;
2956 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2957 CFRelease(url);
2958 if (!path) continue;
2960 CFSetAddValue(paths, path);
2961 CFRelease(path);
2964 CFRelease(descs);
2966 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2967 CFRelease(paths);
2970 #endif
2972 static char *get_data_dir_path( LPCWSTR file )
2974 char *unix_name = NULL;
2975 const char *data_dir = wine_get_data_dir();
2977 if (!data_dir) data_dir = wine_get_build_dir();
2979 if (data_dir)
2981 INT len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2983 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2984 strcpy(unix_name, data_dir);
2985 strcat(unix_name, "/fonts/");
2987 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2989 return unix_name;
2992 static BOOL load_font_from_data_dir(LPCWSTR file)
2994 BOOL ret = FALSE;
2995 char *unix_name = get_data_dir_path( file );
2997 if (unix_name)
2999 EnterCriticalSection( &freetype_cs );
3000 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3001 LeaveCriticalSection( &freetype_cs );
3002 HeapFree(GetProcessHeap(), 0, unix_name);
3004 return ret;
3007 static char *get_winfonts_dir_path(LPCWSTR file)
3009 static const WCHAR slashW[] = {'\\','\0'};
3010 WCHAR windowsdir[MAX_PATH];
3012 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3013 strcatW(windowsdir, fontsW);
3014 strcatW(windowsdir, slashW);
3015 strcatW(windowsdir, file);
3016 return wine_get_unix_file_name( windowsdir );
3019 static void load_system_fonts(void)
3021 HKEY hkey;
3022 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
3023 const WCHAR * const *value;
3024 DWORD dlen, type;
3025 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3026 char *unixname;
3028 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
3029 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3030 strcatW(windowsdir, fontsW);
3031 for(value = SystemFontValues; *value; value++) {
3032 dlen = sizeof(data);
3033 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
3034 type == REG_SZ) {
3035 BOOL added = FALSE;
3037 sprintfW(pathW, fmtW, windowsdir, data);
3038 if((unixname = wine_get_unix_file_name(pathW))) {
3039 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3040 HeapFree(GetProcessHeap(), 0, unixname);
3042 if (!added)
3043 load_font_from_data_dir(data);
3046 RegCloseKey(hkey);
3050 /*************************************************************
3052 * This adds registry entries for any externally loaded fonts
3053 * (fonts from fontconfig or FontDirs). It also deletes entries
3054 * of no longer existing fonts.
3057 static void update_reg_entries(void)
3059 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
3060 LPWSTR valueW;
3061 DWORD len;
3062 Family *family;
3063 Face *face;
3064 WCHAR *file, *path;
3065 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
3067 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
3068 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
3069 ERR("Can't create Windows font reg key\n");
3070 goto end;
3073 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
3074 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
3075 ERR("Can't create Windows font reg key\n");
3076 goto end;
3079 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
3080 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
3081 ERR("Can't create external font reg key\n");
3082 goto end;
3085 /* enumerate the fonts and add external ones to the two keys */
3087 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
3088 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
3089 char *buffer;
3090 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
3092 if(face->FullName)
3094 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
3095 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3096 strcpyW(valueW, face->FullName);
3098 else
3100 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
3101 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3102 strcpyW(valueW, family->FamilyName);
3105 buffer = strWtoA( CP_UNIXCP, face->file );
3106 path = wine_get_dos_file_name( buffer );
3107 HeapFree( GetProcessHeap(), 0, buffer );
3109 if (path)
3110 file = path;
3111 else if ((file = strrchrW(face->file, '/')))
3112 file++;
3113 else
3114 file = face->file;
3116 len = strlenW(file) + 1;
3117 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3118 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3119 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3121 HeapFree(GetProcessHeap(), 0, path);
3122 HeapFree(GetProcessHeap(), 0, valueW);
3125 end:
3126 if(external_key) RegCloseKey(external_key);
3127 if(win9x_key) RegCloseKey(win9x_key);
3128 if(winnt_key) RegCloseKey(winnt_key);
3131 static void delete_external_font_keys(void)
3133 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
3134 DWORD dlen, vlen, datalen, valuelen, i, type;
3135 LPWSTR valueW;
3136 LPVOID data;
3138 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
3139 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
3140 ERR("Can't create Windows font reg key\n");
3141 goto end;
3144 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
3145 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
3146 ERR("Can't create Windows font reg key\n");
3147 goto end;
3150 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
3151 ERR("Can't create external font reg key\n");
3152 goto end;
3155 /* Delete all external fonts added last time */
3157 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3158 &valuelen, &datalen, NULL, NULL);
3159 valuelen++; /* returned value doesn't include room for '\0' */
3160 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3161 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3163 dlen = datalen * sizeof(WCHAR);
3164 vlen = valuelen;
3165 i = 0;
3166 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
3167 &dlen) == ERROR_SUCCESS) {
3169 RegDeleteValueW(winnt_key, valueW);
3170 RegDeleteValueW(win9x_key, valueW);
3171 /* reset dlen and vlen */
3172 dlen = datalen;
3173 vlen = valuelen;
3175 HeapFree(GetProcessHeap(), 0, data);
3176 HeapFree(GetProcessHeap(), 0, valueW);
3178 /* Delete the old external fonts key */
3179 RegCloseKey(external_key);
3180 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
3182 end:
3183 if(win9x_key) RegCloseKey(win9x_key);
3184 if(winnt_key) RegCloseKey(winnt_key);
3187 /*************************************************************
3188 * WineEngAddFontResourceEx
3191 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3193 INT ret = 0;
3195 GDI_CheckNotLock();
3197 if (ft_handle) /* do it only if we have freetype up and running */
3199 char *unixname;
3201 EnterCriticalSection( &freetype_cs );
3203 if((unixname = wine_get_unix_file_name(file)))
3205 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3207 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3208 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
3209 HeapFree(GetProcessHeap(), 0, unixname);
3211 if (!ret && !strchrW(file, '\\')) {
3212 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
3213 if ((unixname = get_winfonts_dir_path( file )))
3215 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3216 HeapFree(GetProcessHeap(), 0, unixname);
3218 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
3219 if (!ret && (unixname = get_data_dir_path( file )))
3221 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3222 HeapFree(GetProcessHeap(), 0, unixname);
3226 LeaveCriticalSection( &freetype_cs );
3228 return ret;
3231 /*************************************************************
3232 * WineEngAddFontMemResourceEx
3235 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3237 GDI_CheckNotLock();
3239 if (ft_handle) /* do it only if we have freetype up and running */
3241 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
3243 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
3244 memcpy(pFontCopy, pbFont, cbFont);
3246 EnterCriticalSection( &freetype_cs );
3247 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3248 LeaveCriticalSection( &freetype_cs );
3250 if (*pcFonts == 0)
3252 TRACE("AddFontToList failed\n");
3253 HeapFree(GetProcessHeap(), 0, pFontCopy);
3254 return 0;
3256 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
3257 * For now return something unique but quite random
3259 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
3260 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
3263 *pcFonts = 0;
3264 return 0;
3267 /*************************************************************
3268 * WineEngRemoveFontResourceEx
3271 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3273 INT ret = 0;
3275 GDI_CheckNotLock();
3277 if (ft_handle) /* do it only if we have freetype up and running */
3279 char *unixname;
3281 EnterCriticalSection( &freetype_cs );
3283 if ((unixname = wine_get_unix_file_name(file)))
3285 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3287 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3288 ret = remove_font_resource( unixname, addfont_flags );
3289 HeapFree(GetProcessHeap(), 0, unixname);
3291 if (!ret && !strchrW(file, '\\'))
3293 if ((unixname = get_winfonts_dir_path( file )))
3295 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3296 HeapFree(GetProcessHeap(), 0, unixname);
3298 if (!ret && (unixname = get_data_dir_path( file )))
3300 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3301 HeapFree(GetProcessHeap(), 0, unixname);
3305 LeaveCriticalSection( &freetype_cs );
3307 return ret;
3310 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
3312 WCHAR *fullname;
3313 char *unix_name;
3314 int file_len;
3316 if (!font_file) return NULL;
3318 file_len = strlenW( font_file );
3320 if (font_path && font_path[0])
3322 int path_len = strlenW( font_path );
3323 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
3324 if (!fullname) return NULL;
3325 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
3326 fullname[path_len] = '\\';
3327 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
3329 else
3331 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
3332 if (!len) return NULL;
3333 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3334 if (!fullname) return NULL;
3335 GetFullPathNameW( font_file, len, fullname, NULL );
3338 unix_name = wine_get_unix_file_name( fullname );
3339 HeapFree( GetProcessHeap(), 0, fullname );
3340 return unix_name;
3343 #include <pshpack1.h>
3344 struct fontdir
3346 WORD num_of_resources;
3347 WORD res_id;
3348 WORD dfVersion;
3349 DWORD dfSize;
3350 CHAR dfCopyright[60];
3351 WORD dfType;
3352 WORD dfPoints;
3353 WORD dfVertRes;
3354 WORD dfHorizRes;
3355 WORD dfAscent;
3356 WORD dfInternalLeading;
3357 WORD dfExternalLeading;
3358 BYTE dfItalic;
3359 BYTE dfUnderline;
3360 BYTE dfStrikeOut;
3361 WORD dfWeight;
3362 BYTE dfCharSet;
3363 WORD dfPixWidth;
3364 WORD dfPixHeight;
3365 BYTE dfPitchAndFamily;
3366 WORD dfAvgWidth;
3367 WORD dfMaxWidth;
3368 BYTE dfFirstChar;
3369 BYTE dfLastChar;
3370 BYTE dfDefaultChar;
3371 BYTE dfBreakChar;
3372 WORD dfWidthBytes;
3373 DWORD dfDevice;
3374 DWORD dfFace;
3375 DWORD dfReserved;
3376 CHAR szFaceName[LF_FACESIZE];
3379 #include <poppack.h>
3381 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
3382 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
3384 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
3386 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3387 Face *face;
3388 WCHAR *name, *english_name;
3389 ENUMLOGFONTEXW elf;
3390 NEWTEXTMETRICEXW ntm;
3391 DWORD type;
3393 if (!ft_face) return FALSE;
3394 face = create_face( ft_face, 0, unix_name, NULL, 0, 0 );
3395 get_family_names( ft_face, &name, &english_name, FALSE );
3396 pFT_Done_Face( ft_face );
3398 GetEnumStructs( face, name, &elf, &ntm, &type );
3399 release_face( face );
3400 HeapFree( GetProcessHeap(), 0, name );
3401 HeapFree( GetProcessHeap(), 0, english_name );
3403 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3405 memset( fd, 0, sizeof(*fd) );
3407 fd->num_of_resources = 1;
3408 fd->res_id = 0;
3409 fd->dfVersion = 0x200;
3410 fd->dfSize = sizeof(*fd);
3411 strcpy( fd->dfCopyright, "Wine fontdir" );
3412 fd->dfType = 0x4003; /* 0x0080 set if private */
3413 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3414 fd->dfVertRes = 72;
3415 fd->dfHorizRes = 72;
3416 fd->dfAscent = ntm.ntmTm.tmAscent;
3417 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3418 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3419 fd->dfItalic = ntm.ntmTm.tmItalic;
3420 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3421 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3422 fd->dfWeight = ntm.ntmTm.tmWeight;
3423 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3424 fd->dfPixWidth = 0;
3425 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3426 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3427 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3428 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3429 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3430 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3431 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3432 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3433 fd->dfWidthBytes = 0;
3434 fd->dfDevice = 0;
3435 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3436 fd->dfReserved = 0;
3437 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3439 return TRUE;
3442 #define NE_FFLAGS_LIBMODULE 0x8000
3443 #define NE_OSFLAGS_WINDOWS 0x02
3445 static const char dos_string[0x40] = "This is a TrueType resource file";
3446 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3448 #include <pshpack2.h>
3450 struct ne_typeinfo
3452 WORD type_id;
3453 WORD count;
3454 DWORD res;
3457 struct ne_nameinfo
3459 WORD off;
3460 WORD len;
3461 WORD flags;
3462 WORD id;
3463 DWORD res;
3466 struct rsrc_tab
3468 WORD align;
3469 struct ne_typeinfo fontdir_type;
3470 struct ne_nameinfo fontdir_name;
3471 struct ne_typeinfo scalable_type;
3472 struct ne_nameinfo scalable_name;
3473 WORD end_of_rsrc;
3474 BYTE fontdir_res_name[8];
3477 #include <poppack.h>
3479 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3481 BOOL ret = FALSE;
3482 HANDLE file;
3483 DWORD size, written;
3484 BYTE *ptr, *start;
3485 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3486 char *font_fileA, *last_part, *ext;
3487 IMAGE_DOS_HEADER dos;
3488 IMAGE_OS2_HEADER ne =
3490 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3491 0, 0, 0, 0, 0, 0,
3492 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3493 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3495 struct rsrc_tab rsrc_tab =
3498 { 0x8007, 1, 0 },
3499 { 0, 0, 0x0c50, 0x2c, 0 },
3500 { 0x80cc, 1, 0 },
3501 { 0, 0, 0x0c50, 0x8001, 0 },
3503 { 7,'F','O','N','T','D','I','R'}
3506 memset( &dos, 0, sizeof(dos) );
3507 dos.e_magic = IMAGE_DOS_SIGNATURE;
3508 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3510 /* import name is last part\0, resident name is last part without extension
3511 non-resident name is "FONTRES:" + lfFaceName */
3513 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3514 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3515 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3517 last_part = strrchr( font_fileA, '\\' );
3518 if (last_part) last_part++;
3519 else last_part = font_fileA;
3520 import_name_len = strlen( last_part ) + 1;
3522 ext = strchr( last_part, '.' );
3523 if (ext) res_name_len = ext - last_part;
3524 else res_name_len = import_name_len - 1;
3526 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3528 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3529 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3530 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3531 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3532 ne.ne_cbenttab = 2;
3533 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3535 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3536 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3537 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3538 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3540 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3541 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3543 if (!ptr)
3545 HeapFree( GetProcessHeap(), 0, font_fileA );
3546 return FALSE;
3549 memcpy( ptr, &dos, sizeof(dos) );
3550 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3551 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3553 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3554 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3556 ptr = start + dos.e_lfanew + ne.ne_restab;
3557 *ptr++ = res_name_len;
3558 memcpy( ptr, last_part, res_name_len );
3560 ptr = start + dos.e_lfanew + ne.ne_imptab;
3561 *ptr++ = import_name_len;
3562 memcpy( ptr, last_part, import_name_len );
3564 ptr = start + ne.ne_nrestab;
3565 *ptr++ = non_res_name_len;
3566 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3567 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3569 ptr = start + (rsrc_tab.scalable_name.off << 4);
3570 memcpy( ptr, font_fileA, font_file_len );
3572 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3573 memcpy( ptr, fontdir, fontdir->dfSize );
3575 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3576 if (file != INVALID_HANDLE_VALUE)
3578 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3579 ret = TRUE;
3580 CloseHandle( file );
3583 HeapFree( GetProcessHeap(), 0, start );
3584 HeapFree( GetProcessHeap(), 0, font_fileA );
3586 return ret;
3589 /*************************************************************
3590 * WineEngCreateScalableFontResource
3593 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3594 LPCWSTR font_file, LPCWSTR font_path )
3596 char *unix_name = get_ttf_file_name( font_file, font_path );
3597 struct fontdir fontdir;
3598 BOOL ret = FALSE;
3600 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3601 SetLastError( ERROR_INVALID_PARAMETER );
3602 else
3604 if (hidden) fontdir.dfType |= 0x80;
3605 ret = create_fot( resource, font_file, &fontdir );
3608 HeapFree( GetProcessHeap(), 0, unix_name );
3609 return ret;
3612 static const struct nls_update_font_list
3614 UINT ansi_cp, oem_cp;
3615 const char *oem, *fixed, *system;
3616 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3617 /* these are for font substitutes */
3618 const char *shelldlg, *tmsrmn;
3619 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3620 *helv_0, *tmsrmn_0;
3621 const struct subst
3623 const char *from, *to;
3624 } arial_0, courier_new_0, times_new_roman_0;
3625 } nls_update_font_list[] =
3627 /* Latin 1 (United States) */
3628 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3629 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3630 "Tahoma","Times New Roman",
3631 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3632 { 0 }, { 0 }, { 0 }
3634 /* Latin 1 (Multilingual) */
3635 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3636 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3637 "Tahoma","Times New Roman", /* FIXME unverified */
3638 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3639 { 0 }, { 0 }, { 0 }
3641 /* Eastern Europe */
3642 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3643 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3644 "Tahoma","Times New Roman", /* FIXME unverified */
3645 "Fixedsys,238", "System,238",
3646 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3647 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3648 { "Arial CE,0", "Arial,238" },
3649 { "Courier New CE,0", "Courier New,238" },
3650 { "Times New Roman CE,0", "Times New Roman,238" }
3652 /* Cyrillic */
3653 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3654 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3655 "Tahoma","Times New Roman", /* FIXME unverified */
3656 "Fixedsys,204", "System,204",
3657 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3658 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3659 { "Arial Cyr,0", "Arial,204" },
3660 { "Courier New Cyr,0", "Courier New,204" },
3661 { "Times New Roman Cyr,0", "Times New Roman,204" }
3663 /* Greek */
3664 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3665 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3666 "Tahoma","Times New Roman", /* FIXME unverified */
3667 "Fixedsys,161", "System,161",
3668 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3669 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3670 { "Arial Greek,0", "Arial,161" },
3671 { "Courier New Greek,0", "Courier New,161" },
3672 { "Times New Roman Greek,0", "Times New Roman,161" }
3674 /* Turkish */
3675 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3676 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3677 "Tahoma","Times New Roman", /* FIXME unverified */
3678 "Fixedsys,162", "System,162",
3679 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3680 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3681 { "Arial Tur,0", "Arial,162" },
3682 { "Courier New Tur,0", "Courier New,162" },
3683 { "Times New Roman Tur,0", "Times New Roman,162" }
3685 /* Hebrew */
3686 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3687 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3688 "Tahoma","Times New Roman", /* FIXME unverified */
3689 "Fixedsys,177", "System,177",
3690 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3691 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3692 { 0 }, { 0 }, { 0 }
3694 /* Arabic */
3695 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3696 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3697 "Microsoft Sans Serif","Times New Roman",
3698 "Fixedsys,178", "System,178",
3699 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3700 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3701 { 0 }, { 0 }, { 0 }
3703 /* Baltic */
3704 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3705 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3706 "Tahoma","Times New Roman", /* FIXME unverified */
3707 "Fixedsys,186", "System,186",
3708 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3709 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3710 { "Arial Baltic,0", "Arial,186" },
3711 { "Courier New Baltic,0", "Courier New,186" },
3712 { "Times New Roman Baltic,0", "Times New Roman,186" }
3714 /* Vietnamese */
3715 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3716 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3717 "Tahoma","Times New Roman", /* FIXME unverified */
3718 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3719 { 0 }, { 0 }, { 0 }
3721 /* Thai */
3722 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3723 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3724 "Tahoma","Times New Roman", /* FIXME unverified */
3725 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3726 { 0 }, { 0 }, { 0 }
3728 /* Japanese */
3729 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3730 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3731 "MS UI Gothic","MS Serif",
3732 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3733 { 0 }, { 0 }, { 0 }
3735 /* Chinese Simplified */
3736 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3737 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3738 "SimSun", "NSimSun",
3739 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3740 { 0 }, { 0 }, { 0 }
3742 /* Korean */
3743 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3744 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3745 "Gulim", "Batang",
3746 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3747 { 0 }, { 0 }, { 0 }
3749 /* Chinese Traditional */
3750 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3751 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3752 "PMingLiU", "MingLiU",
3753 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3754 { 0 }, { 0 }, { 0 }
3758 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3760 return ( ansi_cp == 932 /* CP932 for Japanese */
3761 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3762 || ansi_cp == 949 /* CP949 for Korean */
3763 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3766 static inline HKEY create_fonts_NT_registry_key(void)
3768 HKEY hkey = 0;
3770 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3771 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3772 return hkey;
3775 static inline HKEY create_fonts_9x_registry_key(void)
3777 HKEY hkey = 0;
3779 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3780 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3781 return hkey;
3784 static inline HKEY create_config_fonts_registry_key(void)
3786 HKEY hkey = 0;
3788 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3789 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3790 return hkey;
3793 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3795 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3797 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3798 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3799 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3800 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3803 static void set_value_key(HKEY hkey, const char *name, const char *value)
3805 if (value)
3806 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3807 else if (name)
3808 RegDeleteValueA(hkey, name);
3811 static void update_font_association_info(UINT current_ansi_codepage)
3813 static const char *font_assoc_reg_key = "System\\CurrentControlSet\\Control\\FontAssoc";
3814 static const char *assoc_charset_subkey = "Associated Charset";
3816 if (is_dbcs_ansi_cp(current_ansi_codepage))
3818 HKEY hkey;
3819 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, font_assoc_reg_key, &hkey) == ERROR_SUCCESS)
3821 HKEY hsubkey;
3822 if (RegCreateKeyA(hkey, assoc_charset_subkey, &hsubkey) == ERROR_SUCCESS)
3824 switch (current_ansi_codepage)
3826 case 932:
3827 set_value_key(hsubkey, "ANSI(00)", "NO");
3828 set_value_key(hsubkey, "OEM(FF)", "NO");
3829 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3830 break;
3831 case 936:
3832 case 949:
3833 case 950:
3834 set_value_key(hsubkey, "ANSI(00)", "YES");
3835 set_value_key(hsubkey, "OEM(FF)", "YES");
3836 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3837 break;
3839 RegCloseKey(hsubkey);
3842 /* TODO: Associated DefaultFonts */
3844 RegCloseKey(hkey);
3847 else
3848 RegDeleteTreeA(HKEY_LOCAL_MACHINE, font_assoc_reg_key);
3851 static void set_multi_value_key(HKEY hkey, const WCHAR *name, const WCHAR *value, DWORD len)
3853 if (value)
3854 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (const BYTE *)value, len);
3855 else if (name)
3856 RegDeleteValueW(hkey, name);
3859 static void update_font_system_link_info(UINT current_ansi_codepage)
3861 static const WCHAR system_link_simplified_chinese[] =
3862 {'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3863 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3864 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3865 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3866 '\0'};
3867 static const WCHAR system_link_traditional_chinese[] =
3868 {'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3869 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3870 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3871 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3872 '\0'};
3873 static const WCHAR system_link_japanese[] =
3874 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3875 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3876 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3877 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3878 '\0'};
3879 static const WCHAR system_link_korean[] =
3880 {'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3881 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3882 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3883 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3884 '\0'};
3885 static const WCHAR system_link_non_cjk[] =
3886 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3887 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3888 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3889 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3890 '\0'};
3891 HKEY hkey;
3893 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
3895 const WCHAR *link;
3896 DWORD len;
3898 switch (current_ansi_codepage)
3900 case 932:
3901 link = system_link_japanese;
3902 len = sizeof(system_link_japanese);
3903 break;
3904 case 936:
3905 link = system_link_simplified_chinese;
3906 len = sizeof(system_link_simplified_chinese);
3907 break;
3908 case 949:
3909 link = system_link_korean;
3910 len = sizeof(system_link_korean);
3911 break;
3912 case 950:
3913 link = system_link_traditional_chinese;
3914 len = sizeof(system_link_traditional_chinese);
3915 break;
3916 default:
3917 link = system_link_non_cjk;
3918 len = sizeof(system_link_non_cjk);
3920 set_multi_value_key(hkey, Lucida_Sans_Unicode, link, len);
3921 set_multi_value_key(hkey, Microsoft_Sans_Serif, link, len);
3922 set_multi_value_key(hkey, Tahoma, link, len);
3923 RegCloseKey(hkey);
3927 static void update_font_info(void)
3929 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3930 char buf[40], cpbuf[40];
3931 DWORD len, type;
3932 HKEY hkey = 0;
3933 UINT i, ansi_cp = 0, oem_cp = 0;
3934 DWORD screen_dpi = 96, font_dpi = 0;
3935 BOOL done = FALSE;
3937 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3938 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3939 &hkey) == ERROR_SUCCESS)
3941 reg_load_dword(hkey, logpixels, &screen_dpi);
3942 RegCloseKey(hkey);
3945 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3946 return;
3948 reg_load_dword(hkey, logpixels, &font_dpi);
3950 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3951 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3952 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3953 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3954 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3956 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3957 if (is_dbcs_ansi_cp(ansi_cp))
3958 use_default_fallback = TRUE;
3960 buf[0] = 0;
3961 len = sizeof(buf);
3962 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3964 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3966 RegCloseKey(hkey);
3967 return;
3969 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3970 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3972 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3973 ansi_cp, oem_cp, screen_dpi);
3975 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3976 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3977 RegCloseKey(hkey);
3979 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3981 HKEY hkey;
3983 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3984 nls_update_font_list[i].oem_cp == oem_cp)
3986 hkey = create_config_fonts_registry_key();
3987 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3988 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3989 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3990 RegCloseKey(hkey);
3992 hkey = create_fonts_NT_registry_key();
3993 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3994 RegCloseKey(hkey);
3996 hkey = create_fonts_9x_registry_key();
3997 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3998 RegCloseKey(hkey);
4000 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
4002 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
4003 strlen(nls_update_font_list[i].shelldlg)+1);
4004 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
4005 strlen(nls_update_font_list[i].tmsrmn)+1);
4007 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
4008 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
4009 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
4010 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
4011 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
4012 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
4013 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
4014 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
4016 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
4017 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
4018 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
4020 RegCloseKey(hkey);
4022 done = TRUE;
4024 else
4026 /* Delete the FontSubstitutes from other locales */
4027 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
4029 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
4030 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
4031 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
4032 RegCloseKey(hkey);
4036 if (!done)
4037 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
4039 /* update locale dependent font association info and font system link info in registry.
4040 update only when codepages changed, not logpixels. */
4041 if (strcmp(buf, cpbuf) != 0)
4043 update_font_association_info(ansi_cp);
4044 update_font_system_link_info(ansi_cp);
4048 static BOOL init_freetype(void)
4050 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
4051 if(!ft_handle) {
4052 WINE_MESSAGE(
4053 "Wine cannot find the FreeType font library. To enable Wine to\n"
4054 "use TrueType fonts please install a version of FreeType greater than\n"
4055 "or equal to 2.0.5.\n"
4056 "http://www.freetype.org\n");
4057 return FALSE;
4060 #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;}
4062 LOAD_FUNCPTR(FT_Done_Face)
4063 LOAD_FUNCPTR(FT_Get_Char_Index)
4064 LOAD_FUNCPTR(FT_Get_First_Char)
4065 LOAD_FUNCPTR(FT_Get_Next_Char)
4066 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
4067 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
4068 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
4069 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
4070 LOAD_FUNCPTR(FT_Init_FreeType)
4071 LOAD_FUNCPTR(FT_Library_Version)
4072 LOAD_FUNCPTR(FT_Load_Glyph)
4073 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
4074 LOAD_FUNCPTR(FT_Matrix_Multiply)
4075 #ifndef FT_MULFIX_INLINED
4076 LOAD_FUNCPTR(FT_MulFix)
4077 #endif
4078 LOAD_FUNCPTR(FT_New_Face)
4079 LOAD_FUNCPTR(FT_New_Memory_Face)
4080 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
4081 LOAD_FUNCPTR(FT_Outline_Get_CBox)
4082 LOAD_FUNCPTR(FT_Outline_Transform)
4083 LOAD_FUNCPTR(FT_Outline_Translate)
4084 LOAD_FUNCPTR(FT_Render_Glyph)
4085 LOAD_FUNCPTR(FT_Select_Charmap)
4086 LOAD_FUNCPTR(FT_Set_Charmap)
4087 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
4088 LOAD_FUNCPTR(FT_Vector_Length)
4089 LOAD_FUNCPTR(FT_Vector_Transform)
4090 LOAD_FUNCPTR(FT_Vector_Unit)
4091 #undef LOAD_FUNCPTR
4092 /* Don't warn if these ones are missing */
4093 pFT_Outline_Embolden = wine_dlsym(ft_handle, "FT_Outline_Embolden", NULL, 0);
4094 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
4095 #ifdef FT_LCD_FILTER_H
4096 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
4097 #endif
4099 if(pFT_Init_FreeType(&library) != 0) {
4100 ERR("Can't init FreeType library\n");
4101 wine_dlclose(ft_handle, NULL, 0);
4102 ft_handle = NULL;
4103 return FALSE;
4105 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
4107 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
4108 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
4109 ((FT_Version.minor << 8) & 0x00ff00) |
4110 ((FT_Version.patch ) & 0x0000ff);
4112 font_driver = &freetype_funcs;
4113 return TRUE;
4115 sym_not_found:
4116 WINE_MESSAGE(
4117 "Wine cannot find certain functions that it needs inside the FreeType\n"
4118 "font library. To enable Wine to use TrueType fonts please upgrade\n"
4119 "FreeType to at least version 2.1.4.\n"
4120 "http://www.freetype.org\n");
4121 wine_dlclose(ft_handle, NULL, 0);
4122 ft_handle = NULL;
4123 return FALSE;
4126 static void init_font_list(void)
4128 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
4129 static const WCHAR pathW[] = {'P','a','t','h',0};
4130 HKEY hkey;
4131 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
4132 WCHAR windowsdir[MAX_PATH];
4133 char *unixname;
4134 const char *data_dir;
4136 delete_external_font_keys();
4138 /* load the system bitmap fonts */
4139 load_system_fonts();
4141 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
4142 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
4143 strcatW(windowsdir, fontsW);
4144 if((unixname = wine_get_unix_file_name(windowsdir)))
4146 ReadFontDir(unixname, FALSE);
4147 HeapFree(GetProcessHeap(), 0, unixname);
4150 /* load the system truetype fonts */
4151 data_dir = wine_get_data_dir();
4152 if (!data_dir) data_dir = wine_get_build_dir();
4153 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
4155 strcpy(unixname, data_dir);
4156 strcat(unixname, "/fonts/");
4157 ReadFontDir(unixname, TRUE);
4158 HeapFree(GetProcessHeap(), 0, unixname);
4161 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
4162 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
4163 full path as the entry. Also look for any .fon fonts, since ReadFontDir
4164 will skip these. */
4165 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
4166 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
4167 &hkey) == ERROR_SUCCESS)
4169 LPWSTR data, valueW;
4170 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
4171 &valuelen, &datalen, NULL, NULL);
4173 valuelen++; /* returned value doesn't include room for '\0' */
4174 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
4175 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
4176 if (valueW && data)
4178 dlen = datalen * sizeof(WCHAR);
4179 vlen = valuelen;
4180 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
4181 &dlen) == ERROR_SUCCESS)
4183 if(data[0] && (data[1] == ':'))
4185 if((unixname = wine_get_unix_file_name(data)))
4187 AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
4188 HeapFree(GetProcessHeap(), 0, unixname);
4191 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
4193 WCHAR pathW[MAX_PATH];
4194 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
4195 BOOL added = FALSE;
4197 sprintfW(pathW, fmtW, windowsdir, data);
4198 if((unixname = wine_get_unix_file_name(pathW)))
4200 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
4201 HeapFree(GetProcessHeap(), 0, unixname);
4203 if (!added)
4204 load_font_from_data_dir(data);
4206 /* reset dlen and vlen */
4207 dlen = datalen;
4208 vlen = valuelen;
4211 HeapFree(GetProcessHeap(), 0, data);
4212 HeapFree(GetProcessHeap(), 0, valueW);
4213 RegCloseKey(hkey);
4216 #ifdef SONAME_LIBFONTCONFIG
4217 load_fontconfig_fonts();
4218 #elif defined(HAVE_CARBON_CARBON_H)
4219 load_mac_fonts();
4220 #endif
4222 /* then look in any directories that we've specified in the config file */
4223 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
4224 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
4226 DWORD len;
4227 LPWSTR valueW;
4228 LPSTR valueA, ptr;
4230 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
4232 len += sizeof(WCHAR);
4233 valueW = HeapAlloc( GetProcessHeap(), 0, len );
4234 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
4236 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
4237 valueA = HeapAlloc( GetProcessHeap(), 0, len );
4238 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
4239 TRACE( "got font path %s\n", debugstr_a(valueA) );
4240 ptr = valueA;
4241 while (ptr)
4243 const char* home;
4244 LPSTR next = strchr( ptr, ':' );
4245 if (next) *next++ = 0;
4246 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
4247 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
4249 strcpy( unixname, home );
4250 strcat( unixname, ptr + 1 );
4251 ReadFontDir( unixname, TRUE );
4252 HeapFree( GetProcessHeap(), 0, unixname );
4254 else
4255 ReadFontDir( ptr, TRUE );
4256 ptr = next;
4258 HeapFree( GetProcessHeap(), 0, valueA );
4260 HeapFree( GetProcessHeap(), 0, valueW );
4262 RegCloseKey(hkey);
4266 static BOOL move_to_front(const WCHAR *name)
4268 Family *family, *cursor2;
4269 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
4271 if(!strcmpiW(family->FamilyName, name))
4273 list_remove(&family->entry);
4274 list_add_head(&font_list, &family->entry);
4275 return TRUE;
4278 return FALSE;
4281 static BOOL set_default(const WCHAR **name_list)
4283 while (*name_list)
4285 if (move_to_front(*name_list)) return TRUE;
4286 name_list++;
4289 return FALSE;
4292 static void reorder_font_list(void)
4294 set_default( default_serif_list );
4295 set_default( default_fixed_list );
4296 set_default( default_sans_list );
4299 /*************************************************************
4300 * WineEngInit
4302 * Initialize FreeType library and create a list of available faces
4304 BOOL WineEngInit(void)
4306 HKEY hkey;
4307 DWORD disposition;
4308 HANDLE font_mutex;
4310 /* update locale dependent font info in registry */
4311 update_font_info();
4313 if(!init_freetype()) return FALSE;
4315 #ifdef SONAME_LIBFONTCONFIG
4316 init_fontconfig();
4317 #endif
4319 if (!RegOpenKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, KEY_READ, &hkey))
4321 static const WCHAR antialias_fake_bold_or_italic[] = { 'A','n','t','i','a','l','i','a','s','F','a','k','e',
4322 'B','o','l','d','O','r','I','t','a','l','i','c',0 };
4323 static const WCHAR true_options[] = { 'y','Y','t','T','1',0 };
4324 DWORD type, size;
4325 WCHAR buffer[20];
4327 size = sizeof(buffer);
4328 if (!RegQueryValueExW(hkey, antialias_fake_bold_or_italic, NULL, &type, (BYTE*)buffer, &size) &&
4329 type == REG_SZ && size >= 1)
4331 antialias_fakes = (strchrW(true_options, buffer[0]) != NULL);
4333 RegCloseKey(hkey);
4336 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
4338 ERR("Failed to create font mutex\n");
4339 return FALSE;
4341 WaitForSingleObject(font_mutex, INFINITE);
4343 create_font_cache_key(&hkey_font_cache, &disposition);
4345 if(disposition == REG_CREATED_NEW_KEY)
4346 init_font_list();
4347 else
4348 load_font_list_from_cache(hkey_font_cache);
4350 reorder_font_list();
4352 DumpFontList();
4353 LoadSubstList();
4354 DumpSubstList();
4355 LoadReplaceList();
4357 if(disposition == REG_CREATED_NEW_KEY)
4358 update_reg_entries();
4360 init_system_links();
4362 ReleaseMutex(font_mutex);
4363 return TRUE;
4366 /* Some fonts have large usWinDescent values, as a result of storing signed short
4367 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
4368 some font generation tools. */
4369 static inline USHORT get_fixed_windescent(USHORT windescent)
4371 return abs((SHORT)windescent);
4374 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
4376 TT_OS2 *pOS2;
4377 TT_HoriHeader *pHori;
4379 LONG ppem;
4380 const LONG MAX_PPEM = (1 << 16) - 1;
4382 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4383 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4385 if(height == 0) height = 16;
4387 /* Calc. height of EM square:
4389 * For +ve lfHeight we have
4390 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
4391 * Re-arranging gives:
4392 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4394 * For -ve lfHeight we have
4395 * |lfHeight| = ppem
4396 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4397 * with il = winAscent + winDescent - units_per_em]
4401 if(height > 0) {
4402 USHORT windescent = get_fixed_windescent(pOS2->usWinDescent);
4403 if(pOS2->usWinAscent + windescent == 0)
4404 ppem = MulDiv(ft_face->units_per_EM, height,
4405 pHori->Ascender - pHori->Descender);
4406 else
4407 ppem = MulDiv(ft_face->units_per_EM, height,
4408 pOS2->usWinAscent + windescent);
4409 if(ppem > MAX_PPEM) {
4410 WARN("Ignoring too large height %d, ppem %d\n", height, ppem);
4411 ppem = 1;
4414 else if(height >= -MAX_PPEM)
4415 ppem = -height;
4416 else {
4417 WARN("Ignoring too large height %d\n", height);
4418 ppem = 1;
4421 return ppem;
4424 static struct font_mapping *map_font_file( const char *name )
4426 struct font_mapping *mapping;
4427 struct stat st;
4428 int fd;
4430 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
4431 if (fstat( fd, &st ) == -1) goto error;
4433 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
4435 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
4437 mapping->refcount++;
4438 close( fd );
4439 return mapping;
4442 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
4443 goto error;
4445 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
4446 close( fd );
4448 if (mapping->data == MAP_FAILED)
4450 HeapFree( GetProcessHeap(), 0, mapping );
4451 return NULL;
4453 mapping->refcount = 1;
4454 mapping->dev = st.st_dev;
4455 mapping->ino = st.st_ino;
4456 mapping->size = st.st_size;
4457 list_add_tail( &mappings_list, &mapping->entry );
4458 return mapping;
4460 error:
4461 close( fd );
4462 return NULL;
4465 static void unmap_font_file( struct font_mapping *mapping )
4467 if (!--mapping->refcount)
4469 list_remove( &mapping->entry );
4470 munmap( mapping->data, mapping->size );
4471 HeapFree( GetProcessHeap(), 0, mapping );
4475 static LONG load_VDMX(GdiFont*, LONG);
4477 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
4479 FT_Error err;
4480 FT_Face ft_face;
4481 void *data_ptr;
4482 DWORD data_size;
4484 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
4486 if (face->file)
4488 char *filename = strWtoA( CP_UNIXCP, face->file );
4489 font->mapping = map_font_file( filename );
4490 HeapFree( GetProcessHeap(), 0, filename );
4491 if (!font->mapping)
4493 WARN("failed to map %s\n", debugstr_w(face->file));
4494 return 0;
4496 data_ptr = font->mapping->data;
4497 data_size = font->mapping->size;
4499 else
4501 data_ptr = face->font_data_ptr;
4502 data_size = face->font_data_size;
4505 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
4506 if(err) {
4507 ERR("FT_New_Face rets %d\n", err);
4508 return 0;
4511 /* set it here, as load_VDMX needs it */
4512 font->ft_face = ft_face;
4514 if(FT_IS_SCALABLE(ft_face)) {
4515 /* load the VDMX table if we have one */
4516 font->ppem = load_VDMX(font, height);
4517 if(font->ppem == 0)
4518 font->ppem = calc_ppem_for_height(ft_face, height);
4519 TRACE("height %d => ppem %d\n", height, font->ppem);
4521 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
4522 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
4523 } else {
4524 font->ppem = height;
4525 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
4526 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
4528 return ft_face;
4532 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
4534 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4535 a single face with the requested charset. The idea is to check if
4536 the selected font supports the current ANSI codepage, if it does
4537 return the corresponding charset, else return the first charset */
4539 CHARSETINFO csi;
4540 int acp = GetACP(), i;
4541 DWORD fs0;
4543 *cp = acp;
4544 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
4546 const SYSTEM_LINKS *font_link;
4548 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4549 return csi.ciCharset;
4551 font_link = find_font_link(family_name);
4552 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4553 return csi.ciCharset;
4556 for(i = 0; i < 32; i++) {
4557 fs0 = 1L << i;
4558 if(face->fs.fsCsb[0] & fs0) {
4559 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4560 *cp = csi.ciACP;
4561 return csi.ciCharset;
4563 else
4564 FIXME("TCI failing on %x\n", fs0);
4568 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4569 face->fs.fsCsb[0], debugstr_w(face->file));
4570 *cp = acp;
4571 return DEFAULT_CHARSET;
4574 static GdiFont *alloc_font(void)
4576 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4577 ret->refcount = 1;
4578 ret->gmsize = 1;
4579 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4580 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4581 ret->potm = NULL;
4582 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4583 ret->total_kern_pairs = (DWORD)-1;
4584 ret->kern_pairs = NULL;
4585 ret->instance_id = alloc_font_handle(ret);
4586 list_init(&ret->child_fonts);
4587 return ret;
4590 static void free_font(GdiFont *font)
4592 CHILD_FONT *child, *child_next;
4593 DWORD i;
4595 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
4597 list_remove(&child->entry);
4598 if(child->font)
4599 free_font(child->font);
4600 release_face( child->face );
4601 HeapFree(GetProcessHeap(), 0, child);
4604 HeapFree(GetProcessHeap(), 0, font->fileinfo);
4605 free_font_handle(font->instance_id);
4606 if (font->ft_face) pFT_Done_Face(font->ft_face);
4607 if (font->mapping) unmap_font_file( font->mapping );
4608 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4609 HeapFree(GetProcessHeap(), 0, font->potm);
4610 HeapFree(GetProcessHeap(), 0, font->name);
4611 for (i = 0; i < font->gmsize; i++)
4612 HeapFree(GetProcessHeap(),0,font->gm[i]);
4613 HeapFree(GetProcessHeap(), 0, font->gm);
4614 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4615 HeapFree(GetProcessHeap(), 0, font);
4619 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4621 FT_Face ft_face = font->ft_face;
4622 FT_ULong len;
4623 FT_Error err;
4625 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4627 if(!buf)
4628 len = 0;
4629 else
4630 len = cbData;
4632 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4634 /* make sure value of len is the value freetype says it needs */
4635 if (buf && len)
4637 FT_ULong needed = 0;
4638 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4639 if( !err && needed < len) len = needed;
4641 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4642 if (err)
4644 TRACE("Can't find table %c%c%c%c\n",
4645 /* bytes were reversed */
4646 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4647 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4648 return GDI_ERROR;
4650 return len;
4653 /*************************************************************
4654 * load_VDMX
4656 * load the vdmx entry for the specified height
4659 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4660 ( ( (FT_ULong)_x4 << 24 ) | \
4661 ( (FT_ULong)_x3 << 16 ) | \
4662 ( (FT_ULong)_x2 << 8 ) | \
4663 (FT_ULong)_x1 )
4665 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4667 typedef struct {
4668 WORD version;
4669 WORD numRecs;
4670 WORD numRatios;
4671 } VDMX_Header;
4673 typedef struct {
4674 BYTE bCharSet;
4675 BYTE xRatio;
4676 BYTE yStartRatio;
4677 BYTE yEndRatio;
4678 } Ratios;
4680 typedef struct {
4681 WORD recs;
4682 BYTE startsz;
4683 BYTE endsz;
4684 } VDMX_group;
4686 typedef struct {
4687 WORD yPelHeight;
4688 WORD yMax;
4689 WORD yMin;
4690 } VDMX_vTable;
4692 static LONG load_VDMX(GdiFont *font, LONG height)
4694 VDMX_Header hdr;
4695 VDMX_group group;
4696 BYTE devXRatio, devYRatio;
4697 USHORT numRecs, numRatios;
4698 DWORD result, offset = -1;
4699 LONG ppem = 0;
4700 int i;
4702 result = get_font_data(font, MS_VDMX_TAG, 0, &hdr, sizeof(hdr));
4704 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4705 return ppem;
4707 /* FIXME: need the real device aspect ratio */
4708 devXRatio = 1;
4709 devYRatio = 1;
4711 numRecs = GET_BE_WORD(hdr.numRecs);
4712 numRatios = GET_BE_WORD(hdr.numRatios);
4714 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr.version), numRecs, numRatios);
4715 for(i = 0; i < numRatios; i++) {
4716 Ratios ratio;
4718 offset = sizeof(hdr) + (i * sizeof(Ratios));
4719 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4720 offset = -1;
4722 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4724 if (!ratio.bCharSet) continue;
4726 if((ratio.xRatio == 0 &&
4727 ratio.yStartRatio == 0 &&
4728 ratio.yEndRatio == 0) ||
4729 (devXRatio == ratio.xRatio &&
4730 devYRatio >= ratio.yStartRatio &&
4731 devYRatio <= ratio.yEndRatio))
4733 WORD group_offset;
4735 offset = sizeof(hdr) + numRatios * sizeof(ratio) + i * sizeof(group_offset);
4736 get_font_data(font, MS_VDMX_TAG, offset, &group_offset, sizeof(group_offset));
4737 offset = GET_BE_WORD(group_offset);
4738 break;
4742 if(offset == -1) return 0;
4744 if(get_font_data(font, MS_VDMX_TAG, offset, &group, sizeof(group)) != GDI_ERROR) {
4745 USHORT recs;
4746 BYTE startsz, endsz;
4747 WORD *vTable;
4749 recs = GET_BE_WORD(group.recs);
4750 startsz = group.startsz;
4751 endsz = group.endsz;
4753 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4755 vTable = HeapAlloc(GetProcessHeap(), 0, recs * sizeof(VDMX_vTable));
4756 result = get_font_data(font, MS_VDMX_TAG, offset + sizeof(group), vTable, recs * sizeof(VDMX_vTable));
4757 if(result == GDI_ERROR) {
4758 FIXME("Failed to retrieve vTable\n");
4759 goto end;
4762 if(height > 0) {
4763 for(i = 0; i < recs; i++) {
4764 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4765 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4766 ppem = GET_BE_WORD(vTable[i * 3]);
4768 if(yMax + -yMin == height) {
4769 font->yMax = yMax;
4770 font->yMin = yMin;
4771 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4772 break;
4774 if(yMax + -yMin > height) {
4775 if(--i < 0) {
4776 ppem = 0;
4777 goto end; /* failed */
4779 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4780 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4781 ppem = GET_BE_WORD(vTable[i * 3]);
4782 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4783 break;
4786 if(!font->yMax) {
4787 ppem = 0;
4788 TRACE("ppem not found for height %d\n", height);
4790 } else {
4791 ppem = -height;
4792 if(ppem < startsz || ppem > endsz)
4794 ppem = 0;
4795 goto end;
4798 for(i = 0; i < recs; i++) {
4799 USHORT yPelHeight;
4800 yPelHeight = GET_BE_WORD(vTable[i * 3]);
4802 if(yPelHeight > ppem)
4804 ppem = 0;
4805 break; /* failed */
4808 if(yPelHeight == ppem) {
4809 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4810 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4811 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
4812 break;
4816 end:
4817 HeapFree(GetProcessHeap(), 0, vTable);
4820 return ppem;
4823 static void dump_gdi_font_list(void)
4825 GdiFont *font;
4827 TRACE("---------- Font Cache ----------\n");
4828 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct tagGdiFont, entry )
4829 TRACE("font=%p ref=%u %s %d\n", font, font->refcount,
4830 debugstr_w(font->font_desc.lf.lfFaceName), font->font_desc.lf.lfHeight);
4833 static void grab_font( GdiFont *font )
4835 if (!font->refcount++)
4837 list_remove( &font->unused_entry );
4838 unused_font_count--;
4842 static void release_font( GdiFont *font )
4844 if (!font) return;
4845 if (!--font->refcount)
4847 TRACE( "font %p\n", font );
4849 /* add it to the unused list */
4850 list_add_head( &unused_gdi_font_list, &font->unused_entry );
4851 if (unused_font_count > UNUSED_CACHE_SIZE)
4853 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct tagGdiFont, unused_entry );
4854 TRACE( "freeing %p\n", font );
4855 list_remove( &font->entry );
4856 list_remove( &font->unused_entry );
4857 free_font( font );
4859 else unused_font_count++;
4861 if (TRACE_ON(font)) dump_gdi_font_list();
4865 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4867 if(font->font_desc.hash != fd->hash) return TRUE;
4868 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4869 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4870 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4871 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4874 static void calc_hash(FONT_DESC *pfd)
4876 DWORD hash = 0, *ptr, two_chars;
4877 WORD *pwc;
4878 unsigned int i;
4880 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4881 hash ^= *ptr;
4882 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4883 hash ^= *ptr;
4884 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4885 two_chars = *ptr;
4886 pwc = (WCHAR *)&two_chars;
4887 if(!*pwc) break;
4888 *pwc = toupperW(*pwc);
4889 pwc++;
4890 *pwc = toupperW(*pwc);
4891 hash ^= two_chars;
4892 if(!*pwc) break;
4894 hash ^= !pfd->can_use_bitmap;
4895 pfd->hash = hash;
4898 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4900 GdiFont *ret;
4901 FONT_DESC fd;
4903 fd.lf = *plf;
4904 fd.matrix = *pmat;
4905 fd.can_use_bitmap = can_use_bitmap;
4906 calc_hash(&fd);
4908 /* try the in-use list */
4909 LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
4911 if(fontcmp(ret, &fd)) continue;
4912 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4913 list_remove( &ret->entry );
4914 list_add_head( &gdi_font_list, &ret->entry );
4915 grab_font( ret );
4916 return ret;
4918 return NULL;
4921 static void add_to_cache(GdiFont *font)
4923 static DWORD cache_num = 1;
4925 font->cache_num = cache_num++;
4926 list_add_head(&gdi_font_list, &font->entry);
4927 TRACE( "font %p\n", font );
4930 /*************************************************************
4931 * create_child_font_list
4933 static BOOL create_child_font_list(GdiFont *font)
4935 BOOL ret = FALSE;
4936 SYSTEM_LINKS *font_link;
4937 CHILD_FONT *font_link_entry, *new_child;
4938 FontSubst *psub;
4939 WCHAR* font_name;
4941 psub = get_font_subst(&font_subst_list, font->name, -1);
4942 font_name = psub ? psub->to.name : font->name;
4943 font_link = find_font_link(font_name);
4944 if (font_link != NULL)
4946 TRACE("found entry in system list\n");
4947 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4949 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4950 new_child->face = font_link_entry->face;
4951 new_child->font = NULL;
4952 new_child->face->refcount++;
4953 list_add_tail(&font->child_fonts, &new_child->entry);
4954 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4956 ret = TRUE;
4959 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4960 * Sans Serif. This is how asian windows get default fallbacks for fonts
4962 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4963 font->charset != OEM_CHARSET &&
4964 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4966 font_link = find_font_link(szDefaultFallbackLink);
4967 if (font_link != NULL)
4969 TRACE("found entry in default fallback list\n");
4970 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4972 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4973 new_child->face = font_link_entry->face;
4974 new_child->font = NULL;
4975 new_child->face->refcount++;
4976 list_add_tail(&font->child_fonts, &new_child->entry);
4977 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4979 ret = TRUE;
4983 return ret;
4986 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4988 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4990 if (pFT_Set_Charmap)
4992 FT_Int i;
4993 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4995 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4997 for (i = 0; i < ft_face->num_charmaps; i++)
4999 if (ft_face->charmaps[i]->encoding == encoding)
5001 TRACE("found cmap with platform_id %u, encoding_id %u\n",
5002 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
5004 switch (ft_face->charmaps[i]->platform_id)
5006 default:
5007 cmap_def = ft_face->charmaps[i];
5008 break;
5009 case 0: /* Apple Unicode */
5010 cmap0 = ft_face->charmaps[i];
5011 break;
5012 case 1: /* Macintosh */
5013 cmap1 = ft_face->charmaps[i];
5014 break;
5015 case 2: /* ISO */
5016 cmap2 = ft_face->charmaps[i];
5017 break;
5018 case 3: /* Microsoft */
5019 cmap3 = ft_face->charmaps[i];
5020 break;
5024 if (cmap3) /* prefer Microsoft cmap table */
5025 ft_err = pFT_Set_Charmap(ft_face, cmap3);
5026 else if (cmap1)
5027 ft_err = pFT_Set_Charmap(ft_face, cmap1);
5028 else if (cmap2)
5029 ft_err = pFT_Set_Charmap(ft_face, cmap2);
5030 else if (cmap0)
5031 ft_err = pFT_Set_Charmap(ft_face, cmap0);
5032 else if (cmap_def)
5033 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
5035 return ft_err == FT_Err_Ok;
5038 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
5042 /*************************************************************
5043 * freetype_CreateDC
5045 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
5046 LPCWSTR output, const DEVMODEW *devmode )
5048 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
5050 if (!physdev) return FALSE;
5051 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
5052 return TRUE;
5056 /*************************************************************
5057 * freetype_DeleteDC
5059 static BOOL freetype_DeleteDC( PHYSDEV dev )
5061 struct freetype_physdev *physdev = get_freetype_dev( dev );
5062 release_font( physdev->font );
5063 HeapFree( GetProcessHeap(), 0, physdev );
5064 return TRUE;
5067 static FT_Encoding pick_charmap( FT_Face face, int charset )
5069 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
5070 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
5071 const FT_Encoding *encs = regular_order;
5073 if (charset == SYMBOL_CHARSET) encs = symbol_order;
5075 while (*encs != 0)
5077 if (select_charmap( face, *encs )) break;
5078 encs++;
5080 return *encs;
5083 #define GASP_GRIDFIT 0x01
5084 #define GASP_DOGRAY 0x02
5085 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
5087 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
5089 DWORD size;
5090 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
5091 WORD *alloced = NULL, *ptr = buf;
5092 WORD num_recs, version;
5093 BOOL ret = FALSE;
5095 *flags = 0;
5096 size = get_font_data( font, GASP_TAG, 0, NULL, 0 );
5097 if (size == GDI_ERROR) return FALSE;
5098 if (size < 4 * sizeof(WORD)) return FALSE;
5099 if (size > sizeof(buf))
5101 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
5102 if (!ptr) return FALSE;
5105 get_font_data( font, GASP_TAG, 0, ptr, size );
5107 version = GET_BE_WORD( *ptr++ );
5108 num_recs = GET_BE_WORD( *ptr++ );
5110 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
5112 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
5113 goto done;
5116 while (num_recs--)
5118 *flags = GET_BE_WORD( *(ptr + 1) );
5119 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
5120 ptr += 2;
5122 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
5123 ret = TRUE;
5125 done:
5126 HeapFree( GetProcessHeap(), 0, alloced );
5127 return ret;
5130 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5132 const GSUB_ScriptList *script;
5133 const GSUB_Script *deflt = NULL;
5134 int i;
5135 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5137 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5138 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5140 const GSUB_Script *scr;
5141 int offset;
5143 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5144 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5146 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5147 return scr;
5148 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5149 deflt = scr;
5151 return deflt;
5154 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5156 int i;
5157 int offset;
5158 const GSUB_LangSys *Lang;
5160 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5162 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5164 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5165 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5167 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5168 return Lang;
5170 offset = GET_BE_WORD(script->DefaultLangSys);
5171 if (offset)
5173 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5174 return Lang;
5176 return NULL;
5179 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5181 int i;
5182 const GSUB_FeatureList *feature;
5183 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5185 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5186 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5188 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5189 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5191 const GSUB_Feature *feat;
5192 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5193 return feat;
5196 return NULL;
5199 static const char* get_opentype_script(const GdiFont *font)
5202 * I am not sure if this is the correct way to generate our script tag
5205 switch (font->charset)
5207 case ANSI_CHARSET: return "latn";
5208 case BALTIC_CHARSET: return "latn"; /* ?? */
5209 case CHINESEBIG5_CHARSET: return "hani";
5210 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5211 case GB2312_CHARSET: return "hani";
5212 case GREEK_CHARSET: return "grek";
5213 case HANGUL_CHARSET: return "hang";
5214 case RUSSIAN_CHARSET: return "cyrl";
5215 case SHIFTJIS_CHARSET: return "kana";
5216 case TURKISH_CHARSET: return "latn"; /* ?? */
5217 case VIETNAMESE_CHARSET: return "latn";
5218 case JOHAB_CHARSET: return "latn"; /* ?? */
5219 case ARABIC_CHARSET: return "arab";
5220 case HEBREW_CHARSET: return "hebr";
5221 case THAI_CHARSET: return "thai";
5222 default: return "latn";
5226 static const VOID * get_GSUB_vert_feature(const GdiFont *font)
5228 const GSUB_Header *header;
5229 const GSUB_Script *script;
5230 const GSUB_LangSys *language;
5231 const GSUB_Feature *feature;
5233 if (!font->GSUB_Table)
5234 return NULL;
5236 header = font->GSUB_Table;
5238 script = GSUB_get_script_table(header, get_opentype_script(font));
5239 if (!script)
5241 TRACE("Script not found\n");
5242 return NULL;
5244 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5245 if (!language)
5247 TRACE("Language not found\n");
5248 return NULL;
5250 feature = GSUB_get_feature(header, language, "vrt2");
5251 if (!feature)
5252 feature = GSUB_get_feature(header, language, "vert");
5253 if (!feature)
5255 TRACE("vrt2/vert feature not found\n");
5256 return NULL;
5258 return feature;
5261 static void fill_fileinfo_from_face( GdiFont *font, Face *face )
5263 WIN32_FILE_ATTRIBUTE_DATA info;
5264 int len;
5266 if (!face->file)
5268 font->fileinfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*font->fileinfo));
5269 return;
5272 len = strlenW(face->file);
5273 font->fileinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*font->fileinfo) + len * sizeof(WCHAR));
5274 if (GetFileAttributesExW(face->file, GetFileExInfoStandard, &info))
5276 font->fileinfo->writetime = info.ftLastWriteTime;
5277 font->fileinfo->size.QuadPart = (LONGLONG)info.nFileSizeHigh << 32 | info.nFileSizeLow;
5278 strcpyW(font->fileinfo->path, face->file);
5280 else
5281 memset(font->fileinfo, 0, sizeof(*font->fileinfo) + len * sizeof(WCHAR));
5284 /*************************************************************
5285 * freetype_SelectFont
5287 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
5289 struct freetype_physdev *physdev = get_freetype_dev( dev );
5290 GdiFont *ret;
5291 Face *face, *best, *best_bitmap;
5292 Family *family, *last_resort_family;
5293 const struct list *face_list;
5294 INT height, width = 0;
5295 unsigned int score = 0, new_score;
5296 signed int diff = 0, newdiff;
5297 BOOL bd, it, can_use_bitmap, want_vertical;
5298 LOGFONTW lf;
5299 CHARSETINFO csi;
5300 FMAT2 dcmat;
5301 FontSubst *psub = NULL;
5302 DC *dc = get_dc_ptr( dev->hdc );
5303 const SYSTEM_LINKS *font_link;
5305 if (!hfont) /* notification that the font has been changed by another driver */
5307 release_font( physdev->font );
5308 physdev->font = NULL;
5309 release_dc_ptr( dc );
5310 return 0;
5313 GetObjectW( hfont, sizeof(lf), &lf );
5314 lf.lfWidth = abs(lf.lfWidth);
5316 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
5318 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
5319 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
5320 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
5321 lf.lfEscapement);
5323 if(dc->GraphicsMode == GM_ADVANCED)
5325 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
5326 /* Try to avoid not necessary glyph transformations */
5327 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
5329 lf.lfHeight *= fabs(dcmat.eM11);
5330 lf.lfWidth *= fabs(dcmat.eM11);
5331 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
5334 else
5336 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
5337 font scaling abilities. */
5338 dcmat.eM11 = dcmat.eM22 = 1.0;
5339 dcmat.eM21 = dcmat.eM12 = 0;
5340 lf.lfOrientation = lf.lfEscapement;
5341 if (dc->vport2WorldValid)
5343 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
5344 lf.lfOrientation = -lf.lfOrientation;
5345 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
5346 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
5350 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
5351 dcmat.eM21, dcmat.eM22);
5353 GDI_CheckNotLock();
5354 EnterCriticalSection( &freetype_cs );
5356 /* check the cache first */
5357 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5358 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
5359 goto done;
5362 TRACE("not in cache\n");
5363 ret = alloc_font();
5365 ret->font_desc.matrix = dcmat;
5366 ret->font_desc.lf = lf;
5367 ret->font_desc.can_use_bitmap = can_use_bitmap;
5368 calc_hash(&ret->font_desc);
5370 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
5371 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
5372 original value lfCharSet. Note this is a special case for
5373 Symbol and doesn't happen at least for "Wingdings*" */
5375 if(!strcmpiW(lf.lfFaceName, SymbolW))
5376 lf.lfCharSet = SYMBOL_CHARSET;
5378 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
5379 switch(lf.lfCharSet) {
5380 case DEFAULT_CHARSET:
5381 csi.fs.fsCsb[0] = 0;
5382 break;
5383 default:
5384 FIXME("Untranslated charset %d\n", lf.lfCharSet);
5385 csi.fs.fsCsb[0] = 0;
5386 break;
5390 family = NULL;
5391 if(lf.lfFaceName[0] != '\0') {
5392 CHILD_FONT *font_link_entry;
5393 LPWSTR FaceName = lf.lfFaceName;
5395 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
5397 if(psub) {
5398 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
5399 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
5400 if (psub->to.charset != -1)
5401 lf.lfCharSet = psub->to.charset;
5404 /* We want a match on name and charset or just name if
5405 charset was DEFAULT_CHARSET. If the latter then
5406 we fixup the returned charset later in get_nearest_charset
5407 where we'll either use the charset of the current ansi codepage
5408 or if that's unavailable the first charset that the font supports.
5410 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5411 if (!strcmpiW(family->FamilyName, FaceName) ||
5412 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
5414 font_link = find_font_link(family->FamilyName);
5415 face_list = get_face_list_from_family(family);
5416 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5417 if (!(face->scalable || can_use_bitmap))
5418 continue;
5419 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5420 goto found;
5421 if (font_link != NULL &&
5422 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5423 goto found;
5424 if (!csi.fs.fsCsb[0])
5425 goto found;
5430 /* Search by full face name. */
5431 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5432 face_list = get_face_list_from_family(family);
5433 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5434 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
5435 (face->scalable || can_use_bitmap))
5437 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5438 goto found_face;
5439 font_link = find_font_link(family->FamilyName);
5440 if (font_link != NULL &&
5441 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5442 goto found_face;
5448 * Try check the SystemLink list first for a replacement font.
5449 * We may find good replacements there.
5451 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
5453 if(!strcmpiW(font_link->font_name, FaceName) ||
5454 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
5456 TRACE("found entry in system list\n");
5457 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5459 const SYSTEM_LINKS *links;
5461 face = font_link_entry->face;
5462 if (!(face->scalable || can_use_bitmap))
5463 continue;
5464 family = face->family;
5465 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5466 goto found;
5467 links = find_font_link(family->FamilyName);
5468 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
5469 goto found;
5475 psub = NULL; /* substitution is no more relevant */
5477 /* If requested charset was DEFAULT_CHARSET then try using charset
5478 corresponding to the current ansi codepage */
5479 if (!csi.fs.fsCsb[0])
5481 INT acp = GetACP();
5482 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
5483 FIXME("TCI failed on codepage %d\n", acp);
5484 csi.fs.fsCsb[0] = 0;
5485 } else
5486 lf.lfCharSet = csi.ciCharset;
5489 want_vertical = (lf.lfFaceName[0] == '@');
5491 /* Face families are in the top 4 bits of lfPitchAndFamily,
5492 so mask with 0xF0 before testing */
5494 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
5495 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
5496 strcpyW(lf.lfFaceName, defFixed);
5497 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
5498 strcpyW(lf.lfFaceName, defSerif);
5499 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
5500 strcpyW(lf.lfFaceName, defSans);
5501 else
5502 strcpyW(lf.lfFaceName, defSans);
5503 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5504 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
5505 font_link = find_font_link(family->FamilyName);
5506 face_list = get_face_list_from_family(family);
5507 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5508 if (!(face->scalable || can_use_bitmap))
5509 continue;
5510 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5511 goto found;
5512 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5513 goto found;
5518 last_resort_family = NULL;
5519 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5520 font_link = find_font_link(family->FamilyName);
5521 face_list = get_face_list_from_family(family);
5522 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5523 if(!(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical &&
5524 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5525 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
5526 if(face->scalable)
5527 goto found;
5528 if(can_use_bitmap && !last_resort_family)
5529 last_resort_family = family;
5534 if(last_resort_family) {
5535 family = last_resort_family;
5536 csi.fs.fsCsb[0] = 0;
5537 goto found;
5540 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5541 face_list = get_face_list_from_family(family);
5542 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5543 if(face->scalable && !(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical) {
5544 csi.fs.fsCsb[0] = 0;
5545 WARN("just using first face for now\n");
5546 goto found;
5548 if(can_use_bitmap && !last_resort_family)
5549 last_resort_family = family;
5552 if(!last_resort_family) {
5553 FIXME("can't find a single appropriate font - bailing\n");
5554 free_font(ret);
5555 ret = NULL;
5556 goto done;
5559 WARN("could only find a bitmap font - this will probably look awful!\n");
5560 family = last_resort_family;
5561 csi.fs.fsCsb[0] = 0;
5563 found:
5564 it = lf.lfItalic ? 1 : 0;
5565 bd = lf.lfWeight > 550 ? 1 : 0;
5567 height = lf.lfHeight;
5569 face = best = best_bitmap = NULL;
5570 font_link = find_font_link(family->FamilyName);
5571 face_list = get_face_list_from_family(family);
5572 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5574 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5575 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
5576 !csi.fs.fsCsb[0])
5578 BOOL italic, bold;
5580 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
5581 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
5582 new_score = (italic ^ it) + (bold ^ bd);
5583 if(!best || new_score <= score)
5585 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5586 italic, bold, it, bd);
5587 score = new_score;
5588 best = face;
5589 if(best->scalable && score == 0) break;
5590 if(!best->scalable)
5592 if(height > 0)
5593 newdiff = height - (signed int)(best->size.height);
5594 else
5595 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
5596 if(!best_bitmap || new_score < score ||
5597 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
5599 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
5600 diff = newdiff;
5601 best_bitmap = best;
5602 if(score == 0 && diff == 0) break;
5608 if(best)
5609 face = best->scalable ? best : best_bitmap;
5610 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
5611 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
5613 found_face:
5614 height = lf.lfHeight;
5616 ret->fs = face->fs;
5618 if(csi.fs.fsCsb[0]) {
5619 ret->charset = lf.lfCharSet;
5620 ret->codepage = csi.ciACP;
5622 else
5623 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
5625 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
5626 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
5628 ret->aveWidth = height ? lf.lfWidth : 0;
5630 if(!face->scalable) {
5631 /* Windows uses integer scaling factors for bitmap fonts */
5632 INT scale, scaled_height;
5633 GdiFont *cachedfont;
5635 /* FIXME: rotation of bitmap fonts is ignored */
5636 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
5637 if (ret->aveWidth)
5638 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
5639 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
5640 dcmat.eM11 = dcmat.eM22 = 1.0;
5641 /* As we changed the matrix, we need to search the cache for the font again,
5642 * otherwise we might explode the cache. */
5643 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5644 TRACE("Found cached font after non-scalable matrix rescale!\n");
5645 free_font( ret );
5646 ret = cachedfont;
5647 goto done;
5649 calc_hash(&ret->font_desc);
5651 if (height != 0) height = diff;
5652 height += face->size.height;
5654 scale = (height + face->size.height - 1) / face->size.height;
5655 scaled_height = scale * face->size.height;
5656 /* Only jump to the next height if the difference <= 25% original height */
5657 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
5658 /* The jump between unscaled and doubled is delayed by 1 */
5659 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
5660 ret->scale_y = scale;
5662 width = face->size.x_ppem >> 6;
5663 height = face->size.y_ppem >> 6;
5665 else
5666 ret->scale_y = 1.0;
5667 TRACE("font scale y: %f\n", ret->scale_y);
5669 ret->ft_face = OpenFontFace(ret, face, width, height);
5671 if (!ret->ft_face)
5673 free_font( ret );
5674 ret = NULL;
5675 goto done;
5678 fill_fileinfo_from_face( ret, face );
5679 ret->ntmFlags = face->ntmFlags;
5681 pick_charmap( ret->ft_face, ret->charset );
5683 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
5684 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
5685 ret->underline = lf.lfUnderline ? 0xff : 0;
5686 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
5687 create_child_font_list(ret);
5689 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
5691 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
5692 if (length != GDI_ERROR)
5694 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
5695 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
5696 TRACE("Loaded GSUB table of %i bytes\n",length);
5697 ret->vert_feature = get_GSUB_vert_feature(ret);
5698 if (!ret->vert_feature)
5700 TRACE("Vertical feature not found\n");
5701 HeapFree(GetProcessHeap(), 0, ret->GSUB_Table);
5702 ret->GSUB_Table = NULL;
5706 ret->aa_flags = HIWORD( face->flags );
5708 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
5710 add_to_cache(ret);
5711 done:
5712 if (ret)
5714 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
5716 switch (lf.lfQuality)
5718 case NONANTIALIASED_QUALITY:
5719 case ANTIALIASED_QUALITY:
5720 next->funcs->pSelectFont( dev, hfont, aa_flags );
5721 break;
5722 case CLEARTYPE_QUALITY:
5723 case CLEARTYPE_NATURAL_QUALITY:
5724 default:
5725 if (!*aa_flags) *aa_flags = ret->aa_flags;
5726 next->funcs->pSelectFont( dev, hfont, aa_flags );
5728 /* fixup the antialiasing flags for that font */
5729 switch (*aa_flags)
5731 case WINE_GGO_HRGB_BITMAP:
5732 case WINE_GGO_HBGR_BITMAP:
5733 case WINE_GGO_VRGB_BITMAP:
5734 case WINE_GGO_VBGR_BITMAP:
5735 if (is_subpixel_rendering_enabled()) break;
5736 *aa_flags = GGO_GRAY4_BITMAP;
5737 /* fall through */
5738 case GGO_GRAY2_BITMAP:
5739 case GGO_GRAY4_BITMAP:
5740 case GGO_GRAY8_BITMAP:
5741 case WINE_GGO_GRAY16_BITMAP:
5742 if ((!antialias_fakes || (!ret->fake_bold && !ret->fake_italic)) && is_hinting_enabled())
5744 WORD gasp_flags;
5745 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
5747 TRACE( "font %s %d aa disabled by GASP\n",
5748 debugstr_w(lf.lfFaceName), lf.lfHeight );
5749 *aa_flags = GGO_BITMAP;
5754 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5755 release_font( physdev->font );
5756 physdev->font = ret;
5758 LeaveCriticalSection( &freetype_cs );
5759 release_dc_ptr( dc );
5760 return ret ? hfont : 0;
5763 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5765 HRSRC rsrc;
5766 HGLOBAL hMem;
5767 WCHAR *p;
5768 int i;
5770 id += IDS_FIRST_SCRIPT;
5771 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5772 if (!rsrc) return 0;
5773 hMem = LoadResource( gdi32_module, rsrc );
5774 if (!hMem) return 0;
5776 p = LockResource( hMem );
5777 id &= 0x000f;
5778 while (id--) p += *p + 1;
5780 i = min(LF_FACESIZE - 1, *p);
5781 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5782 buffer[i] = 0;
5783 return i;
5786 static inline BOOL is_complex_script_ansi_cp(UINT ansi_cp)
5788 return (ansi_cp == 874 /* Thai */
5789 || ansi_cp == 1255 /* Hebrew */
5790 || ansi_cp == 1256 /* Arabic */
5794 /***************************************************
5795 * create_enum_charset_list
5797 * This function creates charset enumeration list because in DEFAULT_CHARSET
5798 * case, the ANSI codepage's charset takes precedence over other charsets.
5799 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
5800 * This function works as a filter other than DEFAULT_CHARSET case.
5802 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5804 CHARSETINFO csi;
5805 DWORD n = 0;
5807 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5808 csi.fs.fsCsb[0] != 0) {
5809 list->element[n].mask = csi.fs.fsCsb[0];
5810 list->element[n].charset = csi.ciCharset;
5811 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5812 n++;
5814 else { /* charset is DEFAULT_CHARSET or invalid. */
5815 INT acp, i;
5816 DWORD mask = 0;
5818 /* Set the current codepage's charset as the first element. */
5819 acp = GetACP();
5820 if (!is_complex_script_ansi_cp(acp) &&
5821 TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5822 csi.fs.fsCsb[0] != 0) {
5823 list->element[n].mask = csi.fs.fsCsb[0];
5824 list->element[n].charset = csi.ciCharset;
5825 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5826 mask |= csi.fs.fsCsb[0];
5827 n++;
5830 /* Fill out left elements. */
5831 for (i = 0; i < 32; i++) {
5832 FONTSIGNATURE fs;
5833 fs.fsCsb[0] = 1L << i;
5834 fs.fsCsb[1] = 0;
5835 if (fs.fsCsb[0] & mask)
5836 continue; /* skip, already added. */
5837 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5838 continue; /* skip, this is an invalid fsCsb bit. */
5840 list->element[n].mask = fs.fsCsb[0];
5841 list->element[n].charset = csi.ciCharset;
5842 load_script_name( i, list->element[n].name );
5843 mask |= fs.fsCsb[0];
5844 n++;
5847 /* add catch all mask for remaining bits */
5848 if (~mask)
5850 list->element[n].mask = ~mask;
5851 list->element[n].charset = DEFAULT_CHARSET;
5852 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5853 n++;
5856 list->total = n;
5858 return n;
5861 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
5862 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5864 GdiFont *font;
5865 LONG width, height;
5867 if (face->cached_enum_data)
5869 TRACE("Cached\n");
5870 *pelf = face->cached_enum_data->elf;
5871 *pntm = face->cached_enum_data->ntm;
5872 *ptype = face->cached_enum_data->type;
5873 return;
5876 font = alloc_font();
5878 if(face->scalable) {
5879 height = 100;
5880 width = 0;
5881 } else {
5882 height = face->size.y_ppem >> 6;
5883 width = face->size.x_ppem >> 6;
5885 font->scale_y = 1.0;
5887 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5889 free_font(font);
5890 return;
5893 font->name = strdupW( family_name );
5894 font->ntmFlags = face->ntmFlags;
5896 if (get_outline_text_metrics(font))
5898 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5900 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5901 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5902 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5904 lstrcpynW(pelf->elfLogFont.lfFaceName,
5905 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5906 LF_FACESIZE);
5907 lstrcpynW(pelf->elfFullName,
5908 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5909 LF_FULLFACESIZE);
5910 lstrcpynW(pelf->elfStyle,
5911 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5912 LF_FACESIZE);
5914 else
5916 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5918 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5919 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5920 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5922 lstrcpynW(pelf->elfLogFont.lfFaceName, family_name, LF_FACESIZE);
5923 if (face->FullName)
5924 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5925 else
5926 lstrcpynW(pelf->elfFullName, family_name, LF_FULLFACESIZE);
5927 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5930 pntm->ntmTm.ntmFlags = face->ntmFlags;
5931 pntm->ntmFontSig = face->fs;
5933 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5935 pelf->elfLogFont.lfEscapement = 0;
5936 pelf->elfLogFont.lfOrientation = 0;
5937 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5938 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5939 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5940 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5941 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5942 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5943 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5944 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5945 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5946 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5947 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5949 *ptype = 0;
5950 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5951 *ptype |= TRUETYPE_FONTTYPE;
5952 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5953 *ptype |= DEVICE_FONTTYPE;
5954 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5955 *ptype |= RASTER_FONTTYPE;
5957 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5958 if (face->cached_enum_data)
5960 face->cached_enum_data->elf = *pelf;
5961 face->cached_enum_data->ntm = *pntm;
5962 face->cached_enum_data->type = *ptype;
5965 free_font(font);
5968 static BOOL family_matches(Family *family, const WCHAR *face_name)
5970 Face *face;
5971 const struct list *face_list;
5973 if (!strcmpiW(face_name, family->FamilyName)) return TRUE;
5975 face_list = get_face_list_from_family(family);
5976 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5977 if (face->FullName && !strcmpiW(face_name, face->FullName)) return TRUE;
5979 return FALSE;
5982 static BOOL face_matches(const WCHAR *family_name, Face *face, const WCHAR *face_name)
5984 if (!strcmpiW(face_name, family_name)) return TRUE;
5986 return (face->FullName && !strcmpiW(face_name, face->FullName));
5989 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5990 FONTENUMPROCW proc, LPARAM lparam, const WCHAR *subst)
5992 ENUMLOGFONTEXW elf;
5993 NEWTEXTMETRICEXW ntm;
5994 DWORD type = 0;
5995 DWORD i;
5997 GetEnumStructs(face, face->family->FamilyName, &elf, &ntm, &type);
5998 for(i = 0; i < list->total; i++) {
5999 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
6000 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
6001 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
6002 i = list->total; /* break out of loop after enumeration */
6004 else
6006 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
6007 /* use the DEFAULT_CHARSET case only if no other charset is present */
6008 if (list->element[i].charset == DEFAULT_CHARSET &&
6009 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
6010 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
6011 strcpyW(elf.elfScript, list->element[i].name);
6012 if (!elf.elfScript[0])
6013 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
6015 /* Font Replacement */
6016 if (family != face->family)
6018 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
6019 if (face->FullName)
6020 strcpyW(elf.elfFullName, face->FullName);
6021 else
6022 strcpyW(elf.elfFullName, family->FamilyName);
6024 if (subst)
6025 strcpyW(elf.elfLogFont.lfFaceName, subst);
6026 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
6027 debugstr_w(elf.elfLogFont.lfFaceName),
6028 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
6029 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
6030 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
6031 ntm.ntmTm.ntmFlags);
6032 /* release section before callback (FIXME) */
6033 LeaveCriticalSection( &freetype_cs );
6034 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
6035 EnterCriticalSection( &freetype_cs );
6037 return TRUE;
6040 /*************************************************************
6041 * freetype_EnumFonts
6043 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
6045 Family *family;
6046 Face *face;
6047 const struct list *face_list;
6048 LOGFONTW lf;
6049 struct enum_charset_list enum_charsets;
6051 if (!plf)
6053 lf.lfCharSet = DEFAULT_CHARSET;
6054 lf.lfPitchAndFamily = 0;
6055 lf.lfFaceName[0] = 0;
6056 plf = &lf;
6059 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
6061 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
6063 GDI_CheckNotLock();
6064 EnterCriticalSection( &freetype_cs );
6065 if(plf->lfFaceName[0]) {
6066 WCHAR *face_name = plf->lfFaceName;
6067 FontSubst *psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
6069 if(psub) {
6070 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
6071 debugstr_w(psub->to.name));
6072 face_name = psub->to.name;
6075 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
6076 if (!family_matches(family, face_name)) continue;
6077 face_list = get_face_list_from_family(family);
6078 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
6079 if (!face_matches(family->FamilyName, face, face_name)) continue;
6080 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam, psub ? psub->from.name : NULL)) return FALSE;
6083 } else {
6084 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
6085 face_list = get_face_list_from_family(family);
6086 face = LIST_ENTRY(list_head(face_list), Face, entry);
6087 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam, NULL)) return FALSE;
6090 LeaveCriticalSection( &freetype_cs );
6091 return TRUE;
6094 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
6096 pt->x.value = vec->x >> 6;
6097 pt->x.fract = (vec->x & 0x3f) << 10;
6098 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
6099 pt->y.value = vec->y >> 6;
6100 pt->y.fract = (vec->y & 0x3f) << 10;
6101 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
6104 /***************************************************
6105 * According to the MSDN documentation on WideCharToMultiByte,
6106 * certain codepages cannot set the default_used parameter.
6107 * This returns TRUE if the codepage can set that parameter, false else
6108 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
6110 static BOOL codepage_sets_default_used(UINT codepage)
6112 switch (codepage)
6114 case CP_UTF7:
6115 case CP_UTF8:
6116 case CP_SYMBOL:
6117 return FALSE;
6118 default:
6119 return TRUE;
6124 * GSUB Table handling functions
6127 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
6129 const GSUB_CoverageFormat1* cf1;
6131 cf1 = table;
6133 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
6135 int count = GET_BE_WORD(cf1->GlyphCount);
6136 int i;
6137 TRACE("Coverage Format 1, %i glyphs\n",count);
6138 for (i = 0; i < count; i++)
6139 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
6140 return i;
6141 return -1;
6143 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
6145 const GSUB_CoverageFormat2* cf2;
6146 int i;
6147 int count;
6148 cf2 = (const GSUB_CoverageFormat2*)cf1;
6150 count = GET_BE_WORD(cf2->RangeCount);
6151 TRACE("Coverage Format 2, %i ranges\n",count);
6152 for (i = 0; i < count; i++)
6154 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
6155 return -1;
6156 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
6157 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
6159 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
6160 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
6163 return -1;
6165 else
6166 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
6168 return -1;
6171 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
6173 int i;
6174 int offset;
6175 const GSUB_LookupList *lookup;
6176 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
6178 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
6179 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
6181 const GSUB_LookupTable *look;
6182 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
6183 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
6184 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
6185 if (GET_BE_WORD(look->LookupType) != 1)
6186 FIXME("We only handle SubType 1\n");
6187 else
6189 int j;
6191 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
6193 const GSUB_SingleSubstFormat1 *ssf1;
6194 offset = GET_BE_WORD(look->SubTable[j]);
6195 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
6196 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
6198 int offset = GET_BE_WORD(ssf1->Coverage);
6199 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
6200 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
6202 TRACE(" Glyph 0x%x ->",glyph);
6203 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
6204 TRACE(" 0x%x\n",glyph);
6207 else
6209 const GSUB_SingleSubstFormat2 *ssf2;
6210 INT index;
6211 INT offset;
6213 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
6214 offset = GET_BE_WORD(ssf1->Coverage);
6215 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
6216 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
6217 TRACE(" Coverage index %i\n",index);
6218 if (index != -1)
6220 TRACE(" Glyph is 0x%x ->",glyph);
6221 glyph = GET_BE_WORD(ssf2->Substitute[index]);
6222 TRACE("0x%x\n",glyph);
6228 return glyph;
6232 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
6234 const GSUB_Header *header;
6235 const GSUB_Feature *feature;
6237 if (!font->GSUB_Table)
6238 return glyph;
6240 header = font->GSUB_Table;
6241 feature = font->vert_feature;
6243 return GSUB_apply_feature(header, feature, glyph);
6246 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
6248 FT_UInt glyphId;
6250 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
6251 WCHAR wc = (WCHAR)glyph;
6252 BOOL default_used;
6253 BOOL *default_used_pointer;
6254 FT_UInt ret;
6255 char buf;
6256 default_used_pointer = NULL;
6257 default_used = FALSE;
6258 if (codepage_sets_default_used(font->codepage))
6259 default_used_pointer = &default_used;
6260 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
6262 if (font->codepage == CP_SYMBOL && wc < 0x100)
6263 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
6264 else
6265 ret = 0;
6267 else
6268 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
6269 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6270 return ret;
6273 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
6275 if (glyph < 0x100) glyph += 0xf000;
6276 /* there is a number of old pre-Unicode "broken" TTFs, which
6277 do have symbols at U+00XX instead of U+f0XX */
6278 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
6279 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
6281 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
6283 return glyphId;
6286 /* helper for freetype_GetGlyphIndices */
6287 static FT_UInt get_gdi_glyph_index(const GdiFont *font, UINT glyph)
6289 WCHAR wc = (WCHAR)glyph;
6290 BOOL default_used = FALSE;
6291 BOOL *default_used_pointer = NULL;
6292 FT_UInt ret;
6293 char buf;
6295 if(font->ft_face->charmap->encoding != FT_ENCODING_NONE)
6296 return get_glyph_index(font, glyph);
6298 if (codepage_sets_default_used(font->codepage))
6299 default_used_pointer = &default_used;
6300 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer)
6301 || default_used)
6303 if (font->codepage == CP_SYMBOL && wc < 0x100)
6304 ret = (unsigned char)wc;
6305 else
6306 ret = 0;
6308 else
6309 ret = (unsigned char)buf;
6310 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6311 return ret;
6314 static FT_UInt get_default_char_index(GdiFont *font)
6316 FT_UInt default_char;
6318 if (FT_IS_SFNT(font->ft_face))
6320 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
6321 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
6323 else
6325 TEXTMETRICW textm;
6326 get_text_metrics(font, &textm);
6327 default_char = textm.tmDefaultChar;
6330 return default_char;
6333 /*************************************************************
6334 * freetype_GetGlyphIndices
6336 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
6338 struct freetype_physdev *physdev = get_freetype_dev( dev );
6339 int i;
6340 WORD default_char;
6341 BOOL got_default = FALSE;
6343 if (!physdev->font)
6345 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
6346 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
6349 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
6351 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
6352 got_default = TRUE;
6355 GDI_CheckNotLock();
6356 EnterCriticalSection( &freetype_cs );
6358 for(i = 0; i < count; i++)
6360 pgi[i] = get_gdi_glyph_index(physdev->font, lpstr[i]);
6361 if (pgi[i] == 0)
6363 if (!got_default)
6365 default_char = get_default_char_index(physdev->font);
6366 got_default = TRUE;
6368 pgi[i] = default_char;
6370 else
6371 pgi[i] = get_GSUB_vert_glyph(physdev->font, pgi[i]);
6373 LeaveCriticalSection( &freetype_cs );
6374 return count;
6377 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
6379 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
6380 return !memcmp(matrix, &identity, sizeof(FMAT2));
6383 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
6385 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
6386 return !memcmp(matrix, &identity, sizeof(MAT2));
6389 static inline FT_Vector normalize_vector(FT_Vector *vec)
6391 FT_Vector out;
6392 FT_Fixed len;
6393 len = pFT_Vector_Length(vec);
6394 if (len) {
6395 out.x = (vec->x << 6) / len;
6396 out.y = (vec->y << 6) / len;
6398 else
6399 out.x = out.y = 0;
6400 return out;
6403 static BOOL get_bold_glyph_outline(FT_GlyphSlot glyph, LONG ppem, FT_Glyph_Metrics *metrics)
6405 FT_Error err;
6406 FT_Pos strength;
6407 FT_BBox bbox;
6409 if(glyph->format != FT_GLYPH_FORMAT_OUTLINE)
6410 return FALSE;
6411 if(!pFT_Outline_Embolden)
6412 return FALSE;
6414 strength = MulDiv(ppem, 1 << 6, 24);
6415 err = pFT_Outline_Embolden(&glyph->outline, strength);
6416 if(err) {
6417 TRACE("FT_Ouline_Embolden returns %d\n", err);
6418 return FALSE;
6421 pFT_Outline_Get_CBox(&glyph->outline, &bbox);
6422 metrics->width = bbox.xMax - bbox.xMin;
6423 metrics->height = bbox.yMax - bbox.yMin;
6424 metrics->horiBearingX = bbox.xMin;
6425 metrics->horiBearingY = bbox.yMax;
6426 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
6427 metrics->vertBearingY = (metrics->vertAdvance - metrics->height) / 2;
6428 return TRUE;
6431 static inline BYTE get_max_level( UINT format )
6433 switch( format )
6435 case GGO_GRAY2_BITMAP: return 4;
6436 case GGO_GRAY4_BITMAP: return 16;
6437 case GGO_GRAY8_BITMAP: return 64;
6439 return 255;
6442 extern const unsigned short vertical_orientation_table[] DECLSPEC_HIDDEN;
6444 static BOOL check_unicode_tategaki(WCHAR uchar)
6446 unsigned short orientation = vertical_orientation_table[vertical_orientation_table[vertical_orientation_table[uchar >> 8]+((uchar >> 4) & 0x0f)]+ (uchar & 0xf)];
6448 /* We only reach this code if typographical substitution did not occur */
6449 /* Type: U or Type: Tu */
6450 return (orientation == 1 || orientation == 3);
6453 static FT_Vector get_advance_metric(GdiFont *incoming_font, GdiFont *font,
6454 const FT_Glyph_Metrics *metrics,
6455 const FT_Matrix *transMat, BOOL vertical_metrics)
6457 FT_Vector adv;
6458 FT_Fixed base_advance, em_scale = 0;
6459 BOOL fixed_pitch_full = FALSE;
6461 if (vertical_metrics)
6462 base_advance = metrics->vertAdvance;
6463 else
6464 base_advance = metrics->horiAdvance;
6466 adv.x = base_advance;
6467 adv.y = 0;
6469 /* In fixed-pitch font, we adjust the fullwidth character advance so that
6470 they have double halfwidth character width. E.g. if the font is 19 ppem,
6471 we return 20 (not 19) for fullwidth characters as we return 10 for
6472 halfwidth characters. */
6473 if(FT_IS_SCALABLE(incoming_font->ft_face) &&
6474 (incoming_font->potm || get_outline_text_metrics(incoming_font)) &&
6475 !(incoming_font->potm->otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
6476 UINT avg_advance;
6477 em_scale = MulDiv(incoming_font->ppem, 1 << 16,
6478 incoming_font->ft_face->units_per_EM);
6479 avg_advance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
6480 fixed_pitch_full = (avg_advance > 0 &&
6481 (base_advance + 63) >> 6 ==
6482 pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale));
6483 if (fixed_pitch_full && !transMat)
6484 adv.x = (avg_advance * 2) << 6;
6487 if (transMat) {
6488 pFT_Vector_Transform(&adv, transMat);
6489 if (fixed_pitch_full && adv.y == 0) {
6490 FT_Vector vec;
6491 vec.x = incoming_font->ntmAvgWidth;
6492 vec.y = 0;
6493 pFT_Vector_Transform(&vec, transMat);
6494 adv.x = (pFT_MulFix(vec.x, em_scale) * 2) << 6;
6498 if (font->fake_bold) {
6499 if (!transMat)
6500 adv.x += 1 << 6;
6501 else {
6502 FT_Vector fake_bold_adv, vec = { 1 << 6, 0 };
6503 pFT_Vector_Transform(&vec, transMat);
6504 fake_bold_adv = normalize_vector(&vec);
6505 adv.x += fake_bold_adv.x;
6506 adv.y += fake_bold_adv.y;
6510 adv.x = (adv.x + 63) & -64;
6511 adv.y = -((adv.y + 63) & -64);
6512 return adv;
6515 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
6517 TTPOLYGONHEADER *pph;
6518 TTPOLYCURVE *ppc;
6519 unsigned int needed = 0, point = 0, contour, first_pt;
6520 unsigned int pph_start, cpfx;
6521 DWORD type;
6523 for (contour = 0; contour < outline->n_contours; contour++)
6525 /* Ignore contours containing one point */
6526 if (point == outline->contours[contour])
6528 point++;
6529 continue;
6532 pph_start = needed;
6533 pph = (TTPOLYGONHEADER *)(buf + needed);
6534 first_pt = point;
6535 if (buf)
6537 pph->dwType = TT_POLYGON_TYPE;
6538 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6540 needed += sizeof(*pph);
6541 point++;
6542 while (point <= outline->contours[contour])
6544 ppc = (TTPOLYCURVE *)(buf + needed);
6545 type = outline->tags[point] & FT_Curve_Tag_On ?
6546 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6547 cpfx = 0;
6550 if (buf)
6551 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6552 cpfx++;
6553 point++;
6554 } while (point <= outline->contours[contour] &&
6555 (outline->tags[point] & FT_Curve_Tag_On) ==
6556 (outline->tags[point-1] & FT_Curve_Tag_On));
6557 /* At the end of a contour Windows adds the start point, but
6558 only for Beziers */
6559 if (point > outline->contours[contour] &&
6560 !(outline->tags[point-1] & FT_Curve_Tag_On))
6562 if (buf)
6563 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6564 cpfx++;
6566 else if (point <= outline->contours[contour] &&
6567 outline->tags[point] & FT_Curve_Tag_On)
6569 /* add closing pt for bezier */
6570 if (buf)
6571 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6572 cpfx++;
6573 point++;
6575 if (buf)
6577 ppc->wType = type;
6578 ppc->cpfx = cpfx;
6580 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6582 if (buf)
6583 pph->cb = needed - pph_start;
6585 return needed;
6588 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
6590 /* Convert the quadratic Beziers to cubic Beziers.
6591 The parametric eqn for a cubic Bezier is, from PLRM:
6592 r(t) = at^3 + bt^2 + ct + r0
6593 with the control points:
6594 r1 = r0 + c/3
6595 r2 = r1 + (c + b)/3
6596 r3 = r0 + c + b + a
6598 A quadratic Bezier has the form:
6599 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6601 So equating powers of t leads to:
6602 r1 = 2/3 p1 + 1/3 p0
6603 r2 = 2/3 p1 + 1/3 p2
6604 and of course r0 = p0, r3 = p2
6606 int contour, point = 0, first_pt;
6607 TTPOLYGONHEADER *pph;
6608 TTPOLYCURVE *ppc;
6609 DWORD pph_start, cpfx, type;
6610 FT_Vector cubic_control[4];
6611 unsigned int needed = 0;
6613 for (contour = 0; contour < outline->n_contours; contour++)
6615 pph_start = needed;
6616 pph = (TTPOLYGONHEADER *)(buf + needed);
6617 first_pt = point;
6618 if (buf)
6620 pph->dwType = TT_POLYGON_TYPE;
6621 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6623 needed += sizeof(*pph);
6624 point++;
6625 while (point <= outline->contours[contour])
6627 ppc = (TTPOLYCURVE *)(buf + needed);
6628 type = outline->tags[point] & FT_Curve_Tag_On ?
6629 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6630 cpfx = 0;
6633 if (type == TT_PRIM_LINE)
6635 if (buf)
6636 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6637 cpfx++;
6638 point++;
6640 else
6642 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6643 so cpfx = 3n */
6645 /* FIXME: Possible optimization in endpoint calculation
6646 if there are two consecutive curves */
6647 cubic_control[0] = outline->points[point-1];
6648 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
6650 cubic_control[0].x += outline->points[point].x + 1;
6651 cubic_control[0].y += outline->points[point].y + 1;
6652 cubic_control[0].x >>= 1;
6653 cubic_control[0].y >>= 1;
6655 if (point+1 > outline->contours[contour])
6656 cubic_control[3] = outline->points[first_pt];
6657 else
6659 cubic_control[3] = outline->points[point+1];
6660 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
6662 cubic_control[3].x += outline->points[point].x + 1;
6663 cubic_control[3].y += outline->points[point].y + 1;
6664 cubic_control[3].x >>= 1;
6665 cubic_control[3].y >>= 1;
6668 /* r1 = 1/3 p0 + 2/3 p1
6669 r2 = 1/3 p2 + 2/3 p1 */
6670 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6671 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6672 cubic_control[2] = cubic_control[1];
6673 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6674 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6675 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6676 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6677 if (buf)
6679 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6680 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6681 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6683 cpfx += 3;
6684 point++;
6686 } while (point <= outline->contours[contour] &&
6687 (outline->tags[point] & FT_Curve_Tag_On) ==
6688 (outline->tags[point-1] & FT_Curve_Tag_On));
6689 /* At the end of a contour Windows adds the start point,
6690 but only for Beziers and we've already done that.
6692 if (point <= outline->contours[contour] &&
6693 outline->tags[point] & FT_Curve_Tag_On)
6695 /* This is the closing pt of a bezier, but we've already
6696 added it, so just inc point and carry on */
6697 point++;
6699 if (buf)
6701 ppc->wType = type;
6702 ppc->cpfx = cpfx;
6704 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6706 if (buf)
6707 pph->cb = needed - pph_start;
6709 return needed;
6712 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6714 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
6715 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
6716 const MAT2* lpmat)
6718 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
6719 GLYPHMETRICS gm;
6720 FT_Face ft_face = incoming_font->ft_face;
6721 GdiFont *font = incoming_font;
6722 FT_Glyph_Metrics metrics;
6723 FT_UInt glyph_index;
6724 DWORD width, height, pitch, needed = 0;
6725 FT_Bitmap ft_bitmap;
6726 FT_Error err;
6727 INT left, right, top = 0, bottom = 0;
6728 FT_Vector adv;
6729 INT origin_x = 0, origin_y = 0;
6730 FT_Angle angle = 0;
6731 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
6732 double widthRatio = 1.0;
6733 FT_Matrix transMat = identityMat;
6734 FT_Matrix transMatUnrotated;
6735 FT_Matrix transMatTategaki;
6736 BOOL needsTransform = FALSE;
6737 BOOL tategaki = (font->name[0] == '@');
6738 BOOL vertical_metrics;
6739 UINT original_index;
6741 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
6742 buflen, buf, lpmat);
6744 TRACE("font transform %f %f %f %f\n",
6745 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
6746 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
6748 if(format & GGO_GLYPH_INDEX) {
6749 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
6750 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
6751 as glyph index. "Treasure Adventure Game" depends on this. */
6752 glyph_index = pFT_Get_Char_Index(font->ft_face, glyph);
6753 TRACE("translate glyph index %04x -> %04x\n", glyph, glyph_index);
6754 } else
6755 glyph_index = glyph;
6756 original_index = glyph_index;
6757 format &= ~GGO_GLYPH_INDEX;
6758 /* TODO: Window also turns off tategaki for glyphs passed in by index
6759 if their unicode code points fall outside of the range that is
6760 rotated. */
6761 } else {
6762 BOOL vert;
6763 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index, &vert);
6764 ft_face = font->ft_face;
6765 original_index = glyph_index;
6766 if (!vert && tategaki)
6767 tategaki = check_unicode_tategaki(glyph);
6770 if(format & GGO_UNHINTED) {
6771 load_flags |= FT_LOAD_NO_HINTING;
6772 format &= ~GGO_UNHINTED;
6775 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
6776 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
6777 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
6778 font->gmsize * sizeof(GM*));
6779 } else {
6780 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
6781 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
6783 *lpgm = FONT_GM(font,original_index)->gm;
6784 *abc = FONT_GM(font,original_index)->abc;
6785 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6786 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6787 lpgm->gmCellIncX, lpgm->gmCellIncY);
6788 return 1; /* FIXME */
6792 if (!font->gm[original_index / GM_BLOCK_SIZE])
6793 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
6795 /* Scaling factor */
6796 if (font->aveWidth)
6798 TEXTMETRICW tm;
6800 get_text_metrics(font, &tm);
6802 widthRatio = (double)font->aveWidth;
6803 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6805 else
6806 widthRatio = font->scale_y;
6808 /* Scaling transform */
6809 if (widthRatio != 1.0 || font->scale_y != 1.0)
6811 FT_Matrix scaleMat;
6812 scaleMat.xx = FT_FixedFromFloat(widthRatio);
6813 scaleMat.xy = 0;
6814 scaleMat.yx = 0;
6815 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
6817 pFT_Matrix_Multiply(&scaleMat, &transMat);
6818 needsTransform = TRUE;
6821 /* Slant transform */
6822 if (font->fake_italic) {
6823 FT_Matrix slantMat;
6825 slantMat.xx = (1 << 16);
6826 slantMat.xy = ((1 << 16) >> 2);
6827 slantMat.yx = 0;
6828 slantMat.yy = (1 << 16);
6829 pFT_Matrix_Multiply(&slantMat, &transMat);
6830 needsTransform = TRUE;
6833 /* Rotation transform */
6834 transMatUnrotated = transMat;
6835 transMatTategaki = transMat;
6836 if(font->orientation || tategaki) {
6837 FT_Matrix rotationMat;
6838 FT_Matrix taterotationMat;
6839 FT_Vector vecAngle;
6841 double orient = font->orientation / 10.0;
6842 double tate_orient = 0.f;
6844 if (tategaki)
6845 tate_orient = ((font->orientation+900)%3600)/10.0;
6846 else
6847 tate_orient = font->orientation/10.0;
6849 if (orient)
6851 angle = FT_FixedFromFloat(orient);
6852 pFT_Vector_Unit(&vecAngle, angle);
6853 rotationMat.xx = vecAngle.x;
6854 rotationMat.xy = -vecAngle.y;
6855 rotationMat.yx = -rotationMat.xy;
6856 rotationMat.yy = rotationMat.xx;
6858 pFT_Matrix_Multiply(&rotationMat, &transMat);
6861 if (tate_orient)
6863 angle = FT_FixedFromFloat(tate_orient);
6864 pFT_Vector_Unit(&vecAngle, angle);
6865 taterotationMat.xx = vecAngle.x;
6866 taterotationMat.xy = -vecAngle.y;
6867 taterotationMat.yx = -taterotationMat.xy;
6868 taterotationMat.yy = taterotationMat.xx;
6869 pFT_Matrix_Multiply(&taterotationMat, &transMatTategaki);
6872 needsTransform = TRUE;
6875 /* World transform */
6876 if (!is_identity_FMAT2(&font->font_desc.matrix))
6878 FT_Matrix worldMat;
6879 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
6880 worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21);
6881 worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12);
6882 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
6883 pFT_Matrix_Multiply(&worldMat, &transMat);
6884 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
6885 pFT_Matrix_Multiply(&worldMat, &transMatTategaki);
6886 needsTransform = TRUE;
6889 /* Extra transformation specified by caller */
6890 if (!is_identity_MAT2(lpmat))
6892 FT_Matrix extraMat;
6893 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
6894 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
6895 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
6896 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
6897 pFT_Matrix_Multiply(&extraMat, &transMat);
6898 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
6899 pFT_Matrix_Multiply(&extraMat, &transMatTategaki);
6900 needsTransform = TRUE;
6903 vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face));
6904 /* there is a freetype bug where vertical metrics are only
6905 properly scaled and correct in 2.4.0 or greater */
6906 if ((vertical_metrics) && (FT_Version.major < 2 || (FT_Version.major == 2 && FT_Version.minor < 4)))
6907 vertical_metrics = FALSE;
6909 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
6910 if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
6912 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
6914 if(err) {
6915 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
6916 return GDI_ERROR;
6919 metrics = ft_face->glyph->metrics;
6920 if(font->fake_bold) {
6921 if (!get_bold_glyph_outline(ft_face->glyph, font->ppem, &metrics) && metrics.width)
6922 metrics.width += 1 << 6;
6925 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6926 * by the text metrics. The proper behavior is to clip the glyph metrics to
6927 * fit within the maximums specified in the text metrics. */
6928 if(incoming_font->potm || get_outline_text_metrics(incoming_font) ||
6929 get_bitmap_text_metrics(incoming_font)) {
6930 TEXTMETRICW *ptm = &incoming_font->potm->otmTextMetrics;
6931 top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
6932 bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
6933 metrics.horiBearingY = top;
6934 metrics.height = top - bottom;
6936 /* TODO: Are we supposed to clip the width as well...? */
6937 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6940 if(!needsTransform) {
6941 left = (INT)(metrics.horiBearingX) & -64;
6942 right = (INT)((metrics.horiBearingX + metrics.width) + 63) & -64;
6943 top = (metrics.horiBearingY + 63) & -64;
6944 bottom = (metrics.horiBearingY - metrics.height) & -64;
6945 adv = get_advance_metric(incoming_font, font, &metrics, NULL, vertical_metrics);
6946 gm.gmCellIncX = adv.x >> 6;
6947 gm.gmCellIncY = 0;
6948 origin_x = left;
6949 origin_y = top;
6950 abc->abcA = origin_x >> 6;
6951 abc->abcB = metrics.width >> 6;
6952 } else {
6953 INT xc, yc;
6954 FT_Vector vec;
6955 FT_Pos lsb;
6957 left = right = 0;
6959 for(xc = 0; xc < 2; xc++) {
6960 for(yc = 0; yc < 2; yc++) {
6961 vec.x = metrics.horiBearingX + xc * metrics.width;
6962 vec.y = metrics.horiBearingY - yc * metrics.height;
6963 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
6964 pFT_Vector_Transform(&vec, &transMatTategaki);
6965 if(xc == 0 && yc == 0) {
6966 left = right = vec.x;
6967 top = bottom = vec.y;
6968 } else {
6969 if(vec.x < left) left = vec.x;
6970 else if(vec.x > right) right = vec.x;
6971 if(vec.y < bottom) bottom = vec.y;
6972 else if(vec.y > top) top = vec.y;
6976 left = left & -64;
6977 right = (right + 63) & -64;
6978 bottom = bottom & -64;
6979 top = (top + 63) & -64;
6981 if (tategaki && (font->potm || get_outline_text_metrics(font)))
6983 if (vertical_metrics)
6984 lsb = metrics.horiBearingY + metrics.vertBearingY;
6985 else
6986 lsb = metrics.vertAdvance + (font->potm->otmDescent << 6);
6987 vec.x = lsb;
6988 vec.y = font->potm->otmDescent << 6;
6989 TRACE ("Vec %ld,%ld\n", vec.x>>6, vec.y>>6);
6990 pFT_Vector_Transform(&vec, &transMat);
6991 origin_x = (vec.x + left) & -64;
6992 origin_y = (vec.y + top + 63) & -64;
6994 else
6996 origin_x = left;
6997 origin_y = top;
6998 lsb = metrics.horiBearingX;
7001 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
7002 adv = get_advance_metric(incoming_font, font, &metrics, &transMat, vertical_metrics);
7003 gm.gmCellIncX = adv.x >> 6;
7004 gm.gmCellIncY = adv.y >> 6;
7006 adv = get_advance_metric(incoming_font, font, &metrics, &transMatUnrotated, vertical_metrics);
7008 vec.x = lsb;
7009 vec.y = 0;
7010 pFT_Vector_Transform(&vec, &transMatUnrotated);
7011 abc->abcA = vec.x >> 6;
7013 vec.x = metrics.width;
7014 vec.y = 0;
7015 pFT_Vector_Transform(&vec, &transMatUnrotated);
7016 if (vec.x >= 0)
7017 abc->abcB = vec.x >> 6;
7018 else
7019 abc->abcB = -vec.x >> 6;
7022 width = (right - left) >> 6;
7023 height = (top - bottom) >> 6;
7024 gm.gmBlackBoxX = width ? width : 1;
7025 gm.gmBlackBoxY = height ? height : 1;
7026 gm.gmptGlyphOrigin.x = origin_x >> 6;
7027 gm.gmptGlyphOrigin.y = origin_y >> 6;
7028 if (!abc->abcB) abc->abcB = 1;
7029 abc->abcC = (adv.x >> 6) - abc->abcA - abc->abcB;
7031 TRACE("%u,%u,%s,%d,%d\n", gm.gmBlackBoxX, gm.gmBlackBoxY,
7032 wine_dbgstr_point(&gm.gmptGlyphOrigin),
7033 gm.gmCellIncX, gm.gmCellIncY);
7035 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
7036 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
7038 FONT_GM(font,original_index)->gm = gm;
7039 FONT_GM(font,original_index)->abc = *abc;
7040 FONT_GM(font,original_index)->init = TRUE;
7043 if(format == GGO_METRICS)
7045 *lpgm = gm;
7046 return 1; /* FIXME */
7049 if(ft_face->glyph->format != ft_glyph_format_outline &&
7050 (format == GGO_NATIVE || format == GGO_BEZIER))
7052 TRACE("loaded a bitmap\n");
7053 return GDI_ERROR;
7056 switch(format) {
7057 case GGO_BITMAP:
7058 pitch = ((width + 31) >> 5) << 2;
7059 needed = pitch * height;
7061 if(!buf || !buflen) break;
7062 if (!needed) return GDI_ERROR; /* empty glyph */
7063 if (needed > buflen)
7064 return GDI_ERROR;
7066 switch(ft_face->glyph->format) {
7067 case ft_glyph_format_bitmap:
7069 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
7070 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
7071 INT h = min( height, ft_face->glyph->bitmap.rows );
7072 while(h--) {
7073 if (!font->fake_bold)
7074 memcpy(dst, src, w);
7075 else {
7076 INT x;
7077 dst[0] = 0;
7078 for (x = 0; x < w; x++) {
7079 dst[x ] = (dst[x] & 0x80) | (src[x] >> 1) | src[x];
7080 if (x+1 < pitch)
7081 dst[x+1] = (src[x] & 0x01) << 7;
7084 src += ft_face->glyph->bitmap.pitch;
7085 dst += pitch;
7087 break;
7090 case ft_glyph_format_outline:
7091 ft_bitmap.width = width;
7092 ft_bitmap.rows = height;
7093 ft_bitmap.pitch = pitch;
7094 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
7095 ft_bitmap.buffer = buf;
7097 if(needsTransform)
7098 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
7100 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
7102 /* Note: FreeType will only set 'black' bits for us. */
7103 memset(buf, 0, needed);
7104 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
7105 break;
7107 default:
7108 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
7109 return GDI_ERROR;
7111 break;
7113 case GGO_GRAY2_BITMAP:
7114 case GGO_GRAY4_BITMAP:
7115 case GGO_GRAY8_BITMAP:
7116 case WINE_GGO_GRAY16_BITMAP:
7118 unsigned int max_level, row, col;
7119 BYTE *start, *ptr;
7121 pitch = (width + 3) / 4 * 4;
7122 needed = pitch * height;
7124 if(!buf || !buflen) break;
7125 if (!needed) return GDI_ERROR; /* empty glyph */
7126 if (needed > buflen)
7127 return GDI_ERROR;
7129 max_level = get_max_level( format );
7131 switch(ft_face->glyph->format) {
7132 case ft_glyph_format_bitmap:
7134 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
7135 INT h = min( height, ft_face->glyph->bitmap.rows );
7136 INT x;
7137 memset( buf, 0, needed );
7138 while(h--) {
7139 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++) {
7140 if (src[x / 8] & masks[x % 8]) {
7141 dst[x] = max_level;
7142 if (font->fake_bold && x+1 < pitch) dst[x+1] = max_level;
7145 src += ft_face->glyph->bitmap.pitch;
7146 dst += pitch;
7148 break;
7150 case ft_glyph_format_outline:
7152 ft_bitmap.width = width;
7153 ft_bitmap.rows = height;
7154 ft_bitmap.pitch = pitch;
7155 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
7156 ft_bitmap.buffer = buf;
7158 if(needsTransform)
7159 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
7161 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
7163 memset(ft_bitmap.buffer, 0, buflen);
7165 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
7167 if (max_level != 255)
7169 for (row = 0, start = buf; row < height; row++)
7171 for (col = 0, ptr = start; col < width; col++, ptr++)
7172 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
7173 start += pitch;
7176 break;
7179 default:
7180 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
7181 return GDI_ERROR;
7183 break;
7186 case WINE_GGO_HRGB_BITMAP:
7187 case WINE_GGO_HBGR_BITMAP:
7188 case WINE_GGO_VRGB_BITMAP:
7189 case WINE_GGO_VBGR_BITMAP:
7190 #ifdef FT_LCD_FILTER_H
7192 switch (ft_face->glyph->format)
7194 case FT_GLYPH_FORMAT_BITMAP:
7196 BYTE *src, *dst;
7197 INT src_pitch, x;
7199 pitch = width * 4;
7200 needed = pitch * height;
7202 if (!buf || !buflen) break;
7203 if (!needed) return GDI_ERROR; /* empty glyph */
7204 if (needed > buflen)
7205 return GDI_ERROR;
7207 memset(buf, 0, buflen);
7208 dst = buf;
7209 src = ft_face->glyph->bitmap.buffer;
7210 src_pitch = ft_face->glyph->bitmap.pitch;
7212 height = min( height, ft_face->glyph->bitmap.rows );
7213 while ( height-- )
7215 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
7217 if ( src[x / 8] & masks[x % 8] )
7219 ((unsigned int *)dst)[x] = ~0u;
7220 if (font->fake_bold && x+1 < width) ((unsigned int *)dst)[x+1] = ~0u;
7223 src += src_pitch;
7224 dst += pitch;
7227 break;
7230 case FT_GLYPH_FORMAT_OUTLINE:
7232 unsigned int *dst;
7233 BYTE *src;
7234 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
7235 INT x_shift, y_shift;
7236 BOOL rgb;
7237 FT_Render_Mode render_mode =
7238 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
7239 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
7241 if (!width || !height)
7243 if (!buf || !buflen) break;
7244 return GDI_ERROR;
7247 if ( render_mode == FT_RENDER_MODE_LCD)
7249 gm.gmBlackBoxX += 2;
7250 gm.gmptGlyphOrigin.x -= 1;
7251 left -= (1 << 6);
7253 else
7255 gm.gmBlackBoxY += 2;
7256 gm.gmptGlyphOrigin.y += 1;
7257 top += (1 << 6);
7260 width = gm.gmBlackBoxX;
7261 height = gm.gmBlackBoxY;
7262 pitch = width * 4;
7263 needed = pitch * height;
7265 if (!buf || !buflen) break;
7266 if (needed > buflen)
7267 return GDI_ERROR;
7269 memset(buf, 0, buflen);
7270 dst = buf;
7271 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
7273 if ( needsTransform )
7274 pFT_Outline_Transform (&ft_face->glyph->outline, &transMatTategaki);
7276 if ( pFT_Library_SetLcdFilter )
7277 pFT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT );
7278 pFT_Render_Glyph (ft_face->glyph, render_mode);
7280 src = ft_face->glyph->bitmap.buffer;
7281 src_pitch = ft_face->glyph->bitmap.pitch;
7282 src_width = ft_face->glyph->bitmap.width;
7283 src_height = ft_face->glyph->bitmap.rows;
7285 if ( render_mode == FT_RENDER_MODE_LCD)
7287 rgb_interval = 1;
7288 hmul = 3;
7289 vmul = 1;
7291 else
7293 rgb_interval = src_pitch;
7294 hmul = 1;
7295 vmul = 3;
7298 x_shift = ft_face->glyph->bitmap_left - (left >> 6);
7299 if ( x_shift < 0 )
7301 src += hmul * -x_shift;
7302 src_width -= hmul * -x_shift;
7304 else if ( x_shift > 0 )
7306 dst += x_shift;
7307 width -= x_shift;
7310 y_shift = (top >> 6) - ft_face->glyph->bitmap_top;
7311 if ( y_shift < 0 )
7313 src += src_pitch * vmul * -y_shift;
7314 src_height -= vmul * -y_shift;
7316 else if ( y_shift > 0 )
7318 dst += y_shift * ( pitch / sizeof(*dst) );
7319 height -= y_shift;
7322 width = min( width, src_width / hmul );
7323 height = min( height, src_height / vmul );
7325 while ( height-- )
7327 for ( x = 0; x < width; x++ )
7329 if ( rgb )
7331 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
7332 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
7333 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
7334 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
7336 else
7338 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
7339 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
7340 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
7341 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
7344 src += src_pitch * vmul;
7345 dst += pitch / sizeof(*dst);
7348 break;
7351 default:
7352 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
7353 return GDI_ERROR;
7356 break;
7358 #else
7359 return GDI_ERROR;
7360 #endif
7362 case GGO_NATIVE:
7364 FT_Outline *outline = &ft_face->glyph->outline;
7366 if(buflen == 0) buf = NULL;
7368 if (needsTransform && buf)
7369 pFT_Outline_Transform(outline, &transMatTategaki);
7371 needed = get_native_glyph_outline(outline, buflen, NULL);
7373 if (!buf || !buflen)
7374 break;
7375 if (needed > buflen)
7376 return GDI_ERROR;
7378 get_native_glyph_outline(outline, buflen, buf);
7379 break;
7381 case GGO_BEZIER:
7383 FT_Outline *outline = &ft_face->glyph->outline;
7384 if(buflen == 0) buf = NULL;
7386 if (needsTransform && buf)
7387 pFT_Outline_Transform(outline, &transMat);
7389 needed = get_bezier_glyph_outline(outline, buflen, NULL);
7391 if (!buf || !buflen)
7392 break;
7393 if (needed > buflen)
7394 return GDI_ERROR;
7396 get_bezier_glyph_outline(outline, buflen, buf);
7397 break;
7400 default:
7401 FIXME("Unsupported format %d\n", format);
7402 return GDI_ERROR;
7404 *lpgm = gm;
7405 return needed;
7408 static BOOL get_bitmap_text_metrics(GdiFont *font)
7410 FT_Face ft_face = font->ft_face;
7411 FT_WinFNT_HeaderRec winfnt_header;
7412 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
7413 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
7414 font->potm->otmSize = size;
7416 #define TM font->potm->otmTextMetrics
7417 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
7419 TM.tmHeight = winfnt_header.pixel_height;
7420 TM.tmAscent = winfnt_header.ascent;
7421 TM.tmDescent = TM.tmHeight - TM.tmAscent;
7422 TM.tmInternalLeading = winfnt_header.internal_leading;
7423 TM.tmExternalLeading = winfnt_header.external_leading;
7424 TM.tmAveCharWidth = winfnt_header.avg_width;
7425 TM.tmMaxCharWidth = winfnt_header.max_width;
7426 TM.tmWeight = winfnt_header.weight;
7427 TM.tmOverhang = 0;
7428 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
7429 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
7430 TM.tmFirstChar = winfnt_header.first_char;
7431 TM.tmLastChar = winfnt_header.last_char;
7432 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
7433 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
7434 TM.tmItalic = winfnt_header.italic;
7435 TM.tmUnderlined = font->underline;
7436 TM.tmStruckOut = font->strikeout;
7437 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
7438 TM.tmCharSet = winfnt_header.charset;
7440 else
7442 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
7443 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
7444 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7445 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
7446 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
7447 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
7448 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
7449 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
7450 TM.tmOverhang = 0;
7451 TM.tmDigitizedAspectX = 96; /* FIXME */
7452 TM.tmDigitizedAspectY = 96; /* FIXME */
7453 TM.tmFirstChar = 1;
7454 TM.tmLastChar = 255;
7455 TM.tmDefaultChar = 32;
7456 TM.tmBreakChar = 32;
7457 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
7458 TM.tmUnderlined = font->underline;
7459 TM.tmStruckOut = font->strikeout;
7460 /* NB inverted meaning of TMPF_FIXED_PITCH */
7461 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
7462 TM.tmCharSet = font->charset;
7464 #undef TM
7466 return TRUE;
7470 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
7472 double scale_x, scale_y;
7474 if (font->aveWidth)
7476 scale_x = (double)font->aveWidth;
7477 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7479 else
7480 scale_x = font->scale_y;
7482 scale_x *= fabs(font->font_desc.matrix.eM11);
7483 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7485 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7486 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7488 SCALE_Y(ptm->tmHeight);
7489 SCALE_Y(ptm->tmAscent);
7490 SCALE_Y(ptm->tmDescent);
7491 SCALE_Y(ptm->tmInternalLeading);
7492 SCALE_Y(ptm->tmExternalLeading);
7493 SCALE_Y(ptm->tmOverhang);
7495 SCALE_X(ptm->tmAveCharWidth);
7496 SCALE_X(ptm->tmMaxCharWidth);
7498 #undef SCALE_X
7499 #undef SCALE_Y
7502 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
7504 double scale_x, scale_y;
7506 if (font->aveWidth)
7508 scale_x = (double)font->aveWidth;
7509 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7511 else
7512 scale_x = font->scale_y;
7514 scale_x *= fabs(font->font_desc.matrix.eM11);
7515 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7517 scale_font_metrics(font, &potm->otmTextMetrics);
7519 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7520 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7522 SCALE_Y(potm->otmAscent);
7523 SCALE_Y(potm->otmDescent);
7524 SCALE_Y(potm->otmLineGap);
7525 SCALE_Y(potm->otmsCapEmHeight);
7526 SCALE_Y(potm->otmsXHeight);
7527 SCALE_Y(potm->otmrcFontBox.top);
7528 SCALE_Y(potm->otmrcFontBox.bottom);
7529 SCALE_X(potm->otmrcFontBox.left);
7530 SCALE_X(potm->otmrcFontBox.right);
7531 SCALE_Y(potm->otmMacAscent);
7532 SCALE_Y(potm->otmMacDescent);
7533 SCALE_Y(potm->otmMacLineGap);
7534 SCALE_X(potm->otmptSubscriptSize.x);
7535 SCALE_Y(potm->otmptSubscriptSize.y);
7536 SCALE_X(potm->otmptSubscriptOffset.x);
7537 SCALE_Y(potm->otmptSubscriptOffset.y);
7538 SCALE_X(potm->otmptSuperscriptSize.x);
7539 SCALE_Y(potm->otmptSuperscriptSize.y);
7540 SCALE_X(potm->otmptSuperscriptOffset.x);
7541 SCALE_Y(potm->otmptSuperscriptOffset.y);
7542 SCALE_Y(potm->otmsStrikeoutSize);
7543 SCALE_Y(potm->otmsStrikeoutPosition);
7544 SCALE_Y(potm->otmsUnderscoreSize);
7545 SCALE_Y(potm->otmsUnderscorePosition);
7547 #undef SCALE_X
7548 #undef SCALE_Y
7551 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
7553 if(!font->potm)
7555 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
7557 /* Make sure that the font has sane width/height ratio */
7558 if (font->aveWidth)
7560 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
7562 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
7563 font->aveWidth = 0;
7567 *ptm = font->potm->otmTextMetrics;
7568 scale_font_metrics(font, ptm);
7569 return TRUE;
7572 static BOOL face_has_symbol_charmap(FT_Face ft_face)
7574 int i;
7576 for(i = 0; i < ft_face->num_charmaps; i++)
7578 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
7579 return TRUE;
7581 return FALSE;
7584 static BOOL get_outline_text_metrics(GdiFont *font)
7586 BOOL ret = FALSE;
7587 FT_Face ft_face = font->ft_face;
7588 UINT needed, lenfam, lensty, lenface, lenfull;
7589 TT_OS2 *pOS2;
7590 TT_HoriHeader *pHori;
7591 TT_Postscript *pPost;
7592 FT_Fixed em_scale;
7593 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
7594 char *cp;
7595 INT ascent, descent;
7596 USHORT windescent;
7598 TRACE("font=%p\n", font);
7600 if(!FT_IS_SCALABLE(ft_face))
7601 return FALSE;
7603 needed = sizeof(*font->potm);
7605 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
7606 family_nameW = strdupW(font->name);
7608 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
7609 if (!style_nameW)
7611 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
7612 style_nameW = towstr( CP_ACP, ft_face->style_name );
7614 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
7616 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
7617 if (!face_nameW)
7619 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
7620 face_nameW = strdupW(font->name);
7622 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
7623 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
7625 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
7626 if (!full_nameW)
7628 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
7629 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
7630 full_nameW = strdupW(fake_nameW);
7632 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
7634 /* These names should be read from the TT name table */
7636 /* length of otmpFamilyName */
7637 needed += lenfam;
7639 /* length of otmpFaceName */
7640 needed += lenface;
7642 /* length of otmpStyleName */
7643 needed += lensty;
7645 /* length of otmpFullName */
7646 needed += lenfull;
7649 em_scale = (FT_Fixed)MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
7651 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
7652 if(!pOS2) {
7653 FIXME("Can't find OS/2 table - not TT font?\n");
7654 goto end;
7657 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
7658 if(!pHori) {
7659 FIXME("Can't find HHEA table - not TT font?\n");
7660 goto end;
7663 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
7665 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",
7666 pOS2->usWinAscent, pOS2->usWinDescent,
7667 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
7668 pOS2->xAvgCharWidth,
7669 ft_face->ascender, ft_face->descender, ft_face->height,
7670 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
7671 ft_face->bbox.yMax, ft_face->bbox.yMin);
7673 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
7674 font->potm->otmSize = needed;
7676 #define TM font->potm->otmTextMetrics
7678 windescent = get_fixed_windescent(pOS2->usWinDescent);
7679 if(pOS2->usWinAscent + windescent == 0) {
7680 ascent = pHori->Ascender;
7681 descent = -pHori->Descender;
7682 } else {
7683 ascent = pOS2->usWinAscent;
7684 descent = windescent;
7687 font->ntmCellHeight = ascent + descent;
7688 font->ntmAvgWidth = pOS2->xAvgCharWidth;
7690 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7691 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7693 if(font->yMax) {
7694 TM.tmAscent = font->yMax;
7695 TM.tmDescent = -font->yMin;
7696 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
7697 } else {
7698 TM.tmAscent = SCALE_Y(ascent);
7699 TM.tmDescent = SCALE_Y(descent);
7700 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
7703 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7705 /* MSDN says:
7706 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7708 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
7709 ((ascent + descent) -
7710 (pHori->Ascender - pHori->Descender))));
7712 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
7713 if (TM.tmAveCharWidth == 0) {
7714 TM.tmAveCharWidth = 1;
7716 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
7717 TM.tmWeight = FW_REGULAR;
7718 if (font->fake_bold) {
7719 TM.tmAveCharWidth++;
7720 TM.tmMaxCharWidth++;
7721 TM.tmWeight = FW_BOLD;
7723 else
7725 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
7727 if (pOS2->usWeightClass > FW_MEDIUM)
7728 TM.tmWeight = pOS2->usWeightClass;
7730 else if (pOS2->usWeightClass <= FW_MEDIUM)
7731 TM.tmWeight = pOS2->usWeightClass;
7733 TM.tmOverhang = 0;
7734 TM.tmDigitizedAspectX = 96; /* FIXME */
7735 TM.tmDigitizedAspectY = 96; /* FIXME */
7736 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7737 * symbol range to 0 - f0ff
7740 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
7742 TM.tmFirstChar = 0;
7743 switch(GetACP())
7745 case 1255: /* Hebrew */
7746 TM.tmLastChar = 0xf896;
7747 break;
7748 case 1257: /* Baltic */
7749 TM.tmLastChar = 0xf8fd;
7750 break;
7751 default:
7752 TM.tmLastChar = 0xf0ff;
7754 TM.tmBreakChar = 0x20;
7755 TM.tmDefaultChar = 0x1f;
7757 else
7759 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
7760 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
7762 if(pOS2->usFirstCharIndex <= 1)
7763 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
7764 else if (pOS2->usFirstCharIndex > 0xff)
7765 TM.tmBreakChar = 0x20;
7766 else
7767 TM.tmBreakChar = pOS2->usFirstCharIndex;
7768 TM.tmDefaultChar = TM.tmBreakChar - 1;
7770 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
7771 TM.tmUnderlined = font->underline;
7772 TM.tmStruckOut = font->strikeout;
7774 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7775 if(!FT_IS_FIXED_WIDTH(ft_face) &&
7776 (pOS2->version == 0xFFFFU ||
7777 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
7778 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
7779 else
7780 TM.tmPitchAndFamily = 0;
7782 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
7784 case PAN_FAMILY_SCRIPT:
7785 TM.tmPitchAndFamily |= FF_SCRIPT;
7786 break;
7788 case PAN_FAMILY_DECORATIVE:
7789 TM.tmPitchAndFamily |= FF_DECORATIVE;
7790 break;
7792 case PAN_ANY:
7793 case PAN_NO_FIT:
7794 case PAN_FAMILY_TEXT_DISPLAY:
7795 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
7796 /* which is clearly not what the panose spec says. */
7797 default:
7798 if(TM.tmPitchAndFamily == 0 || /* fixed */
7799 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
7800 TM.tmPitchAndFamily = FF_MODERN;
7801 else
7803 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
7805 case PAN_ANY:
7806 case PAN_NO_FIT:
7807 default:
7808 TM.tmPitchAndFamily |= FF_DONTCARE;
7809 break;
7811 case PAN_SERIF_COVE:
7812 case PAN_SERIF_OBTUSE_COVE:
7813 case PAN_SERIF_SQUARE_COVE:
7814 case PAN_SERIF_OBTUSE_SQUARE_COVE:
7815 case PAN_SERIF_SQUARE:
7816 case PAN_SERIF_THIN:
7817 case PAN_SERIF_BONE:
7818 case PAN_SERIF_EXAGGERATED:
7819 case PAN_SERIF_TRIANGLE:
7820 TM.tmPitchAndFamily |= FF_ROMAN;
7821 break;
7823 case PAN_SERIF_NORMAL_SANS:
7824 case PAN_SERIF_OBTUSE_SANS:
7825 case PAN_SERIF_PERP_SANS:
7826 case PAN_SERIF_FLARED:
7827 case PAN_SERIF_ROUNDED:
7828 TM.tmPitchAndFamily |= FF_SWISS;
7829 break;
7832 break;
7835 if(FT_IS_SCALABLE(ft_face))
7836 TM.tmPitchAndFamily |= TMPF_VECTOR;
7838 if(FT_IS_SFNT(ft_face))
7840 if (font->ntmFlags & NTM_PS_OPENTYPE)
7841 TM.tmPitchAndFamily |= TMPF_DEVICE;
7842 else
7843 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
7846 TM.tmCharSet = font->charset;
7848 font->potm->otmFiller = 0;
7849 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
7850 font->potm->otmfsSelection = pOS2->fsSelection;
7851 if (font->fake_italic)
7852 font->potm->otmfsSelection |= 1;
7853 if (font->fake_bold)
7854 font->potm->otmfsSelection |= 1 << 5;
7855 font->potm->otmfsType = pOS2->fsType;
7856 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
7857 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
7858 font->potm->otmItalicAngle = 0; /* POST table */
7859 font->potm->otmEMSquare = ft_face->units_per_EM;
7860 font->potm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
7861 font->potm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
7862 font->potm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
7863 font->potm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
7864 font->potm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
7865 font->potm->otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
7866 font->potm->otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
7867 font->potm->otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
7868 font->potm->otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
7869 font->potm->otmMacAscent = TM.tmAscent;
7870 font->potm->otmMacDescent = -TM.tmDescent;
7871 font->potm->otmMacLineGap = font->potm->otmLineGap;
7872 font->potm->otmusMinimumPPEM = 0; /* TT Header */
7873 font->potm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
7874 font->potm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
7875 font->potm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
7876 font->potm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
7877 font->potm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
7878 font->potm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
7879 font->potm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
7880 font->potm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
7881 font->potm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
7882 font->potm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
7883 if(!pPost) {
7884 font->potm->otmsUnderscoreSize = 0;
7885 font->potm->otmsUnderscorePosition = 0;
7886 } else {
7887 font->potm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
7888 font->potm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
7890 #undef SCALE_X
7891 #undef SCALE_Y
7892 #undef TM
7894 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7895 cp = (char*)font->potm + sizeof(*font->potm);
7896 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
7897 strcpyW((WCHAR*)cp, family_nameW);
7898 cp += lenfam;
7899 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
7900 strcpyW((WCHAR*)cp, style_nameW);
7901 cp += lensty;
7902 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7903 strcpyW((WCHAR*)cp, face_nameW);
7904 cp += lenface;
7905 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
7906 strcpyW((WCHAR*)cp, full_nameW);
7907 ret = TRUE;
7909 end:
7910 HeapFree(GetProcessHeap(), 0, style_nameW);
7911 HeapFree(GetProcessHeap(), 0, family_nameW);
7912 HeapFree(GetProcessHeap(), 0, face_nameW);
7913 HeapFree(GetProcessHeap(), 0, full_nameW);
7914 return ret;
7917 /*************************************************************
7918 * freetype_GetGlyphOutline
7920 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
7921 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7923 struct freetype_physdev *physdev = get_freetype_dev( dev );
7924 DWORD ret;
7925 ABC abc;
7927 if (!physdev->font)
7929 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
7930 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
7933 GDI_CheckNotLock();
7934 EnterCriticalSection( &freetype_cs );
7935 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
7936 LeaveCriticalSection( &freetype_cs );
7937 return ret;
7940 /*************************************************************
7941 * freetype_GetTextMetrics
7943 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
7945 struct freetype_physdev *physdev = get_freetype_dev( dev );
7946 BOOL ret;
7948 if (!physdev->font)
7950 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
7951 return dev->funcs->pGetTextMetrics( dev, metrics );
7954 GDI_CheckNotLock();
7955 EnterCriticalSection( &freetype_cs );
7956 ret = get_text_metrics( physdev->font, metrics );
7957 LeaveCriticalSection( &freetype_cs );
7958 return ret;
7961 /*************************************************************
7962 * freetype_GetOutlineTextMetrics
7964 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
7966 struct freetype_physdev *physdev = get_freetype_dev( dev );
7967 UINT ret = 0;
7969 if (!physdev->font)
7971 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
7972 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
7975 TRACE("font=%p\n", physdev->font);
7977 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
7979 GDI_CheckNotLock();
7980 EnterCriticalSection( &freetype_cs );
7982 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
7984 if(potm && cbSize >= physdev->font->potm->otmSize)
7986 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
7987 scale_outline_font_metrics(physdev->font, potm);
7989 ret = physdev->font->potm->otmSize;
7991 LeaveCriticalSection( &freetype_cs );
7992 return ret;
7995 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
7997 child->font = alloc_font();
7998 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
7999 if(!child->font->ft_face)
8001 free_font(child->font);
8002 child->font = NULL;
8003 return FALSE;
8006 child->font->font_desc = font->font_desc;
8007 child->font->ntmFlags = child->face->ntmFlags;
8008 child->font->orientation = font->orientation;
8009 child->font->scale_y = font->scale_y;
8010 child->font->name = strdupW(child->face->family->FamilyName);
8011 child->font->base_font = font;
8012 TRACE("created child font %p for base %p\n", child->font, font);
8013 return TRUE;
8016 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL* vert)
8018 FT_UInt g,o;
8019 CHILD_FONT *child_font;
8021 if(font->base_font)
8022 font = font->base_font;
8024 *linked_font = font;
8026 if((*glyph = get_glyph_index(font, c)))
8028 o = *glyph;
8029 *glyph = get_GSUB_vert_glyph(font, *glyph);
8030 *vert = (o != *glyph);
8031 return TRUE;
8034 if (c < 32) goto done; /* don't check linked fonts for control characters */
8036 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
8038 if(!child_font->font)
8039 if(!load_child_font(font, child_font))
8040 continue;
8042 if(!child_font->font->ft_face)
8043 continue;
8044 g = get_glyph_index(child_font->font, c);
8045 o = g;
8046 g = get_GSUB_vert_glyph(child_font->font, g);
8047 if(g)
8049 *glyph = g;
8050 *linked_font = child_font->font;
8051 *vert = (o != g);
8052 return TRUE;
8056 done:
8057 *vert = FALSE;
8058 return FALSE;
8061 /*************************************************************
8062 * freetype_GetCharWidth
8064 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
8066 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8067 UINT c;
8068 GLYPHMETRICS gm;
8069 ABC abc;
8070 struct freetype_physdev *physdev = get_freetype_dev( dev );
8072 if (!physdev->font)
8074 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
8075 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
8078 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
8080 GDI_CheckNotLock();
8081 EnterCriticalSection( &freetype_cs );
8082 for(c = firstChar; c <= lastChar; c++) {
8083 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
8084 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
8086 LeaveCriticalSection( &freetype_cs );
8087 return TRUE;
8090 /*************************************************************
8091 * freetype_GetCharABCWidths
8093 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
8095 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8096 UINT c;
8097 GLYPHMETRICS gm;
8098 struct freetype_physdev *physdev = get_freetype_dev( dev );
8100 if (!physdev->font)
8102 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
8103 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
8106 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
8108 GDI_CheckNotLock();
8109 EnterCriticalSection( &freetype_cs );
8111 for(c = firstChar; c <= lastChar; c++, buffer++)
8112 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
8114 LeaveCriticalSection( &freetype_cs );
8115 return TRUE;
8118 /*************************************************************
8119 * freetype_GetCharABCWidthsI
8121 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
8123 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8124 UINT c;
8125 GLYPHMETRICS gm;
8126 struct freetype_physdev *physdev = get_freetype_dev( dev );
8128 if (!physdev->font)
8130 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
8131 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
8134 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
8135 return FALSE;
8137 GDI_CheckNotLock();
8138 EnterCriticalSection( &freetype_cs );
8140 for(c = 0; c < count; c++, buffer++)
8141 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
8142 &gm, buffer, 0, NULL, &identity );
8144 LeaveCriticalSection( &freetype_cs );
8145 return TRUE;
8148 /*************************************************************
8149 * freetype_GetTextExtentExPoint
8151 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
8153 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8154 INT idx, pos;
8155 ABC abc;
8156 GLYPHMETRICS gm;
8157 struct freetype_physdev *physdev = get_freetype_dev( dev );
8159 if (!physdev->font)
8161 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
8162 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
8165 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
8167 GDI_CheckNotLock();
8168 EnterCriticalSection( &freetype_cs );
8170 for (idx = pos = 0; idx < count; idx++)
8172 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
8173 pos += abc.abcA + abc.abcB + abc.abcC;
8174 dxs[idx] = pos;
8177 LeaveCriticalSection( &freetype_cs );
8178 return TRUE;
8181 /*************************************************************
8182 * freetype_GetTextExtentExPointI
8184 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
8186 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8187 INT idx, pos;
8188 ABC abc;
8189 GLYPHMETRICS gm;
8190 struct freetype_physdev *physdev = get_freetype_dev( dev );
8192 if (!physdev->font)
8194 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
8195 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
8198 TRACE("%p, %p, %d\n", physdev->font, indices, count);
8200 GDI_CheckNotLock();
8201 EnterCriticalSection( &freetype_cs );
8203 for (idx = pos = 0; idx < count; idx++)
8205 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
8206 &gm, &abc, 0, NULL, &identity );
8207 pos += abc.abcA + abc.abcB + abc.abcC;
8208 dxs[idx] = pos;
8211 LeaveCriticalSection( &freetype_cs );
8212 return TRUE;
8215 /*************************************************************
8216 * freetype_GetFontData
8218 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
8220 struct freetype_physdev *physdev = get_freetype_dev( dev );
8222 if (!physdev->font)
8224 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
8225 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
8228 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
8229 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
8230 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
8232 return get_font_data( physdev->font, table, offset, buf, cbData );
8235 /*************************************************************
8236 * freetype_GetTextFace
8238 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
8240 INT n;
8241 struct freetype_physdev *physdev = get_freetype_dev( dev );
8243 if (!physdev->font)
8245 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
8246 return dev->funcs->pGetTextFace( dev, count, str );
8249 n = strlenW(physdev->font->name) + 1;
8250 if (str)
8252 lstrcpynW(str, physdev->font->name, count);
8253 n = min(count, n);
8255 return n;
8258 /*************************************************************
8259 * freetype_GetTextCharsetInfo
8261 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
8263 struct freetype_physdev *physdev = get_freetype_dev( dev );
8265 if (!physdev->font)
8267 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
8268 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
8270 if (fs) *fs = physdev->font->fs;
8271 return physdev->font->charset;
8274 /* Retrieve a list of supported Unicode ranges for a given font.
8275 * Can be called with NULL gs to calculate the buffer size. Returns
8276 * the number of ranges found.
8278 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
8280 DWORD num_ranges = 0;
8282 if (face->charmap->encoding == FT_ENCODING_UNICODE)
8284 FT_UInt glyph_code;
8285 FT_ULong char_code, char_code_prev;
8287 glyph_code = 0;
8288 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
8290 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
8291 face->num_glyphs, glyph_code, char_code);
8293 if (!glyph_code) return 0;
8295 if (gs)
8297 gs->ranges[0].wcLow = (USHORT)char_code;
8298 gs->ranges[0].cGlyphs = 0;
8299 gs->cGlyphsSupported = 0;
8302 num_ranges = 1;
8303 while (glyph_code)
8305 if (char_code < char_code_prev)
8307 ERR("expected increasing char code from FT_Get_Next_Char\n");
8308 return 0;
8310 if (char_code - char_code_prev > 1)
8312 num_ranges++;
8313 if (gs)
8315 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
8316 gs->ranges[num_ranges - 1].cGlyphs = 1;
8317 gs->cGlyphsSupported++;
8320 else if (gs)
8322 gs->ranges[num_ranges - 1].cGlyphs++;
8323 gs->cGlyphsSupported++;
8325 char_code_prev = char_code;
8326 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
8329 else
8330 FIXME("encoding %u not supported\n", face->charmap->encoding);
8332 return num_ranges;
8335 /*************************************************************
8336 * freetype_GetFontUnicodeRanges
8338 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
8340 struct freetype_physdev *physdev = get_freetype_dev( dev );
8341 DWORD size, num_ranges;
8343 if (!physdev->font)
8345 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
8346 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
8349 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
8350 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
8351 if (glyphset)
8353 glyphset->cbThis = size;
8354 glyphset->cRanges = num_ranges;
8355 glyphset->flAccel = 0;
8357 return size;
8360 /*************************************************************
8361 * freetype_FontIsLinked
8363 static BOOL freetype_FontIsLinked( PHYSDEV dev )
8365 struct freetype_physdev *physdev = get_freetype_dev( dev );
8366 BOOL ret;
8368 if (!physdev->font)
8370 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
8371 return dev->funcs->pFontIsLinked( dev );
8374 GDI_CheckNotLock();
8375 EnterCriticalSection( &freetype_cs );
8376 ret = !list_empty(&physdev->font->child_fonts);
8377 LeaveCriticalSection( &freetype_cs );
8378 return ret;
8381 /*************************************************************************
8382 * GetRasterizerCaps (GDI32.@)
8384 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8386 lprs->nSize = sizeof(RASTERIZER_STATUS);
8387 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
8388 lprs->nLanguageID = 0;
8389 return TRUE;
8392 /*************************************************************
8393 * freetype_GetFontRealizationInfo
8395 static BOOL freetype_GetFontRealizationInfo( PHYSDEV dev, void *ptr )
8397 struct freetype_physdev *physdev = get_freetype_dev( dev );
8398 struct font_realization_info *info = ptr;
8400 if (!physdev->font)
8402 dev = GET_NEXT_PHYSDEV( dev, pGetFontRealizationInfo );
8403 return dev->funcs->pGetFontRealizationInfo( dev, ptr );
8406 TRACE("(%p, %p)\n", physdev->font, info);
8408 info->flags = 1;
8409 if(FT_IS_SCALABLE(physdev->font->ft_face))
8410 info->flags |= 2;
8412 info->cache_num = physdev->font->cache_num;
8413 info->instance_id = physdev->font->instance_id;
8414 if (info->size == sizeof(*info))
8416 info->unk = 0;
8417 info->face_index = physdev->font->ft_face->face_index;
8418 info->simulations = 0;
8419 if (physdev->font->fake_bold)
8420 info->simulations |= 0x1;
8421 if (physdev->font->fake_italic)
8422 info->simulations |= 0x2;
8425 return TRUE;
8428 /*************************************************************************
8429 * GetFontFileInfo (GDI32.@)
8431 BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_fileinfo *info, DWORD size, DWORD *needed )
8433 struct font_handle_entry *entry = handle_entry( instance_id );
8434 const GdiFont *font;
8436 if (!entry)
8438 SetLastError(ERROR_INVALID_PARAMETER);
8439 return FALSE;
8442 font = entry->obj;
8443 *needed = sizeof(*info) + strlenW(font->fileinfo->path) * sizeof(WCHAR);
8444 if (*needed > size)
8446 SetLastError(ERROR_INSUFFICIENT_BUFFER);
8447 return FALSE;
8450 /* path is included too */
8451 memcpy(info, font->fileinfo, *needed);
8452 return TRUE;
8455 /*************************************************************************
8456 * Kerning support for TrueType fonts
8458 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
8460 struct TT_kern_table
8462 USHORT version;
8463 USHORT nTables;
8466 struct TT_kern_subtable
8468 USHORT version;
8469 USHORT length;
8470 union
8472 USHORT word;
8473 struct
8475 USHORT horizontal : 1;
8476 USHORT minimum : 1;
8477 USHORT cross_stream: 1;
8478 USHORT override : 1;
8479 USHORT reserved1 : 4;
8480 USHORT format : 8;
8481 } bits;
8482 } coverage;
8485 struct TT_format0_kern_subtable
8487 USHORT nPairs;
8488 USHORT searchRange;
8489 USHORT entrySelector;
8490 USHORT rangeShift;
8493 struct TT_kern_pair
8495 USHORT left;
8496 USHORT right;
8497 short value;
8500 static DWORD parse_format0_kern_subtable(GdiFont *font,
8501 const struct TT_format0_kern_subtable *tt_f0_ks,
8502 const USHORT *glyph_to_char,
8503 KERNINGPAIR *kern_pair, DWORD cPairs)
8505 USHORT i, nPairs;
8506 const struct TT_kern_pair *tt_kern_pair;
8508 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
8510 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
8512 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8513 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
8514 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
8516 if (!kern_pair || !cPairs)
8517 return nPairs;
8519 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
8521 nPairs = min(nPairs, cPairs);
8523 for (i = 0; i < nPairs; i++)
8525 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
8526 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
8527 /* this algorithm appears to better match what Windows does */
8528 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
8529 if (kern_pair->iKernAmount < 0)
8531 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
8532 kern_pair->iKernAmount -= font->ppem;
8534 else if (kern_pair->iKernAmount > 0)
8536 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
8537 kern_pair->iKernAmount += font->ppem;
8539 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
8541 TRACE("left %u right %u value %d\n",
8542 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
8544 kern_pair++;
8546 TRACE("copied %u entries\n", nPairs);
8547 return nPairs;
8550 /*************************************************************
8551 * freetype_GetKerningPairs
8553 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
8555 DWORD length;
8556 void *buf;
8557 const struct TT_kern_table *tt_kern_table;
8558 const struct TT_kern_subtable *tt_kern_subtable;
8559 USHORT i, nTables;
8560 USHORT *glyph_to_char;
8561 GdiFont *font;
8562 struct freetype_physdev *physdev = get_freetype_dev( dev );
8564 if (!(font = physdev->font))
8566 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
8567 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
8570 GDI_CheckNotLock();
8571 EnterCriticalSection( &freetype_cs );
8572 if (font->total_kern_pairs != (DWORD)-1)
8574 if (cPairs && kern_pair)
8576 cPairs = min(cPairs, font->total_kern_pairs);
8577 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8579 else cPairs = font->total_kern_pairs;
8581 LeaveCriticalSection( &freetype_cs );
8582 return cPairs;
8585 font->total_kern_pairs = 0;
8587 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
8589 if (length == GDI_ERROR)
8591 TRACE("no kerning data in the font\n");
8592 LeaveCriticalSection( &freetype_cs );
8593 return 0;
8596 buf = HeapAlloc(GetProcessHeap(), 0, length);
8597 if (!buf)
8599 WARN("Out of memory\n");
8600 LeaveCriticalSection( &freetype_cs );
8601 return 0;
8604 get_font_data(font, MS_KERN_TAG, 0, buf, length);
8606 /* build a glyph index to char code map */
8607 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
8608 if (!glyph_to_char)
8610 WARN("Out of memory allocating a glyph index to char code map\n");
8611 HeapFree(GetProcessHeap(), 0, buf);
8612 LeaveCriticalSection( &freetype_cs );
8613 return 0;
8616 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
8618 FT_UInt glyph_code;
8619 FT_ULong char_code;
8621 glyph_code = 0;
8622 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
8624 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
8625 font->ft_face->num_glyphs, glyph_code, char_code);
8627 while (glyph_code)
8629 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
8631 /* FIXME: This doesn't match what Windows does: it does some fancy
8632 * things with duplicate glyph index to char code mappings, while
8633 * we just avoid overriding existing entries.
8635 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
8636 glyph_to_char[glyph_code] = (USHORT)char_code;
8638 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
8641 else
8643 ULONG n;
8645 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
8646 for (n = 0; n <= 65535; n++)
8647 glyph_to_char[n] = (USHORT)n;
8650 tt_kern_table = buf;
8651 nTables = GET_BE_WORD(tt_kern_table->nTables);
8652 TRACE("version %u, nTables %u\n",
8653 GET_BE_WORD(tt_kern_table->version), nTables);
8655 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
8657 for (i = 0; i < nTables; i++)
8659 struct TT_kern_subtable tt_kern_subtable_copy;
8661 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
8662 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
8663 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
8665 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8666 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
8667 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
8669 /* According to the TrueType specification this is the only format
8670 * that will be properly interpreted by Windows and OS/2
8672 if (tt_kern_subtable_copy.coverage.bits.format == 0)
8674 DWORD new_chunk, old_total = font->total_kern_pairs;
8676 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8677 glyph_to_char, NULL, 0);
8678 font->total_kern_pairs += new_chunk;
8680 if (!font->kern_pairs)
8681 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
8682 font->total_kern_pairs * sizeof(*font->kern_pairs));
8683 else
8684 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
8685 font->total_kern_pairs * sizeof(*font->kern_pairs));
8687 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8688 glyph_to_char, font->kern_pairs + old_total, new_chunk);
8690 else
8691 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
8693 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
8696 HeapFree(GetProcessHeap(), 0, glyph_to_char);
8697 HeapFree(GetProcessHeap(), 0, buf);
8699 if (cPairs && kern_pair)
8701 cPairs = min(cPairs, font->total_kern_pairs);
8702 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8704 else cPairs = font->total_kern_pairs;
8706 LeaveCriticalSection( &freetype_cs );
8707 return cPairs;
8710 static const struct gdi_dc_funcs freetype_funcs =
8712 NULL, /* pAbortDoc */
8713 NULL, /* pAbortPath */
8714 NULL, /* pAlphaBlend */
8715 NULL, /* pAngleArc */
8716 NULL, /* pArc */
8717 NULL, /* pArcTo */
8718 NULL, /* pBeginPath */
8719 NULL, /* pBlendImage */
8720 NULL, /* pChord */
8721 NULL, /* pCloseFigure */
8722 NULL, /* pCreateCompatibleDC */
8723 freetype_CreateDC, /* pCreateDC */
8724 freetype_DeleteDC, /* pDeleteDC */
8725 NULL, /* pDeleteObject */
8726 NULL, /* pDeviceCapabilities */
8727 NULL, /* pEllipse */
8728 NULL, /* pEndDoc */
8729 NULL, /* pEndPage */
8730 NULL, /* pEndPath */
8731 freetype_EnumFonts, /* pEnumFonts */
8732 NULL, /* pEnumICMProfiles */
8733 NULL, /* pExcludeClipRect */
8734 NULL, /* pExtDeviceMode */
8735 NULL, /* pExtEscape */
8736 NULL, /* pExtFloodFill */
8737 NULL, /* pExtSelectClipRgn */
8738 NULL, /* pExtTextOut */
8739 NULL, /* pFillPath */
8740 NULL, /* pFillRgn */
8741 NULL, /* pFlattenPath */
8742 freetype_FontIsLinked, /* pFontIsLinked */
8743 NULL, /* pFrameRgn */
8744 NULL, /* pGdiComment */
8745 NULL, /* pGetBoundsRect */
8746 freetype_GetCharABCWidths, /* pGetCharABCWidths */
8747 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
8748 freetype_GetCharWidth, /* pGetCharWidth */
8749 NULL, /* pGetDeviceCaps */
8750 NULL, /* pGetDeviceGammaRamp */
8751 freetype_GetFontData, /* pGetFontData */
8752 freetype_GetFontRealizationInfo, /* pGetFontRealizationInfo */
8753 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
8754 freetype_GetGlyphIndices, /* pGetGlyphIndices */
8755 freetype_GetGlyphOutline, /* pGetGlyphOutline */
8756 NULL, /* pGetICMProfile */
8757 NULL, /* pGetImage */
8758 freetype_GetKerningPairs, /* pGetKerningPairs */
8759 NULL, /* pGetNearestColor */
8760 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
8761 NULL, /* pGetPixel */
8762 NULL, /* pGetSystemPaletteEntries */
8763 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
8764 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
8765 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
8766 freetype_GetTextFace, /* pGetTextFace */
8767 freetype_GetTextMetrics, /* pGetTextMetrics */
8768 NULL, /* pGradientFill */
8769 NULL, /* pIntersectClipRect */
8770 NULL, /* pInvertRgn */
8771 NULL, /* pLineTo */
8772 NULL, /* pModifyWorldTransform */
8773 NULL, /* pMoveTo */
8774 NULL, /* pOffsetClipRgn */
8775 NULL, /* pOffsetViewportOrg */
8776 NULL, /* pOffsetWindowOrg */
8777 NULL, /* pPaintRgn */
8778 NULL, /* pPatBlt */
8779 NULL, /* pPie */
8780 NULL, /* pPolyBezier */
8781 NULL, /* pPolyBezierTo */
8782 NULL, /* pPolyDraw */
8783 NULL, /* pPolyPolygon */
8784 NULL, /* pPolyPolyline */
8785 NULL, /* pPolygon */
8786 NULL, /* pPolyline */
8787 NULL, /* pPolylineTo */
8788 NULL, /* pPutImage */
8789 NULL, /* pRealizeDefaultPalette */
8790 NULL, /* pRealizePalette */
8791 NULL, /* pRectangle */
8792 NULL, /* pResetDC */
8793 NULL, /* pRestoreDC */
8794 NULL, /* pRoundRect */
8795 NULL, /* pSaveDC */
8796 NULL, /* pScaleViewportExt */
8797 NULL, /* pScaleWindowExt */
8798 NULL, /* pSelectBitmap */
8799 NULL, /* pSelectBrush */
8800 NULL, /* pSelectClipPath */
8801 freetype_SelectFont, /* pSelectFont */
8802 NULL, /* pSelectPalette */
8803 NULL, /* pSelectPen */
8804 NULL, /* pSetArcDirection */
8805 NULL, /* pSetBkColor */
8806 NULL, /* pSetBkMode */
8807 NULL, /* pSetDCBrushColor */
8808 NULL, /* pSetDCPenColor */
8809 NULL, /* pSetDIBColorTable */
8810 NULL, /* pSetDIBitsToDevice */
8811 NULL, /* pSetDeviceClipping */
8812 NULL, /* pSetDeviceGammaRamp */
8813 NULL, /* pSetLayout */
8814 NULL, /* pSetMapMode */
8815 NULL, /* pSetMapperFlags */
8816 NULL, /* pSetPixel */
8817 NULL, /* pSetPolyFillMode */
8818 NULL, /* pSetROP2 */
8819 NULL, /* pSetRelAbs */
8820 NULL, /* pSetStretchBltMode */
8821 NULL, /* pSetTextAlign */
8822 NULL, /* pSetTextCharacterExtra */
8823 NULL, /* pSetTextColor */
8824 NULL, /* pSetTextJustification */
8825 NULL, /* pSetViewportExt */
8826 NULL, /* pSetViewportOrg */
8827 NULL, /* pSetWindowExt */
8828 NULL, /* pSetWindowOrg */
8829 NULL, /* pSetWorldTransform */
8830 NULL, /* pStartDoc */
8831 NULL, /* pStartPage */
8832 NULL, /* pStretchBlt */
8833 NULL, /* pStretchDIBits */
8834 NULL, /* pStrokeAndFillPath */
8835 NULL, /* pStrokePath */
8836 NULL, /* pUnrealizePalette */
8837 NULL, /* pWidenPath */
8838 NULL, /* wine_get_wgl_driver */
8839 GDI_PRIORITY_FONT_DRV /* priority */
8842 #else /* HAVE_FREETYPE */
8844 struct font_fileinfo;
8846 /*************************************************************************/
8848 BOOL WineEngInit(void)
8850 return FALSE;
8853 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8855 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8856 return 1;
8859 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8861 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8862 return TRUE;
8865 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
8867 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
8868 return NULL;
8871 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
8872 LPCWSTR font_file, LPCWSTR font_path )
8874 FIXME("stub\n");
8875 return FALSE;
8878 /*************************************************************************
8879 * GetRasterizerCaps (GDI32.@)
8881 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8883 lprs->nSize = sizeof(RASTERIZER_STATUS);
8884 lprs->wFlags = 0;
8885 lprs->nLanguageID = 0;
8886 return TRUE;
8889 /*************************************************************************
8890 * GetFontFileInfo (GDI32.@)
8892 BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_fileinfo *info, DWORD size, DWORD *needed)
8894 *needed = 0;
8895 return FALSE;
8898 #endif /* HAVE_FREETYPE */