wined3d: Store sub-resource map counts in the sub-resource structure.
[wine.git] / dlls / gdi32 / freetype.c
blobf8b4235d853f2578f667d65c5a334aa8fd66a300
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 #ifndef WINE_FONT_DIR
218 #define WINE_FONT_DIR "fonts"
219 #endif
221 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
222 typedef struct {
223 FT_Short height;
224 FT_Short width;
225 FT_Pos size;
226 FT_Pos x_ppem;
227 FT_Pos y_ppem;
228 FT_Short internal_leading;
229 } Bitmap_Size;
231 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
232 So to let this compile on older versions of FreeType we'll define the
233 new structure here. */
234 typedef struct {
235 FT_Short height, width;
236 FT_Pos size, x_ppem, y_ppem;
237 } My_FT_Bitmap_Size;
239 struct enum_data
241 ENUMLOGFONTEXW elf;
242 NEWTEXTMETRICEXW ntm;
243 DWORD type;
246 typedef struct tagFace {
247 struct list entry;
248 unsigned int refcount;
249 WCHAR *StyleName;
250 WCHAR *FullName;
251 WCHAR *file;
252 dev_t dev;
253 ino_t ino;
254 void *font_data_ptr;
255 DWORD font_data_size;
256 FT_Long face_index;
257 FONTSIGNATURE fs;
258 DWORD ntmFlags;
259 FT_Fixed font_version;
260 BOOL scalable;
261 Bitmap_Size size; /* set if face is a bitmap */
262 DWORD flags; /* ADDFONT flags */
263 struct tagFamily *family;
264 /* Cached data for Enum */
265 struct enum_data *cached_enum_data;
266 } Face;
268 #define ADDFONT_EXTERNAL_FONT 0x01
269 #define ADDFONT_ALLOW_BITMAP 0x02
270 #define ADDFONT_ADD_TO_CACHE 0x04
271 #define ADDFONT_ADD_RESOURCE 0x08 /* added through AddFontResource */
272 #define ADDFONT_VERTICAL_FONT 0x10
273 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
275 typedef struct tagFamily {
276 struct list entry;
277 unsigned int refcount;
278 WCHAR *FamilyName;
279 WCHAR *EnglishName;
280 struct list faces;
281 struct list *replacement;
282 } Family;
284 typedef struct {
285 GLYPHMETRICS gm;
286 ABC abc; /* metrics of the unrotated char */
287 BOOL init;
288 } GM;
290 typedef struct {
291 FLOAT eM11, eM12;
292 FLOAT eM21, eM22;
293 } FMAT2;
295 typedef struct {
296 DWORD hash;
297 LOGFONTW lf;
298 FMAT2 matrix;
299 BOOL can_use_bitmap;
300 } FONT_DESC;
302 typedef struct tagGdiFont GdiFont;
304 #define FIRST_FONT_HANDLE 1
305 #define MAX_FONT_HANDLES 256
307 struct font_handle_entry
309 void *obj;
310 WORD generation; /* generation count for reusing handle values */
313 static struct font_handle_entry font_handles[MAX_FONT_HANDLES];
314 static struct font_handle_entry *next_free;
315 static struct font_handle_entry *next_unused = font_handles;
317 static inline DWORD entry_to_handle( struct font_handle_entry *entry )
319 unsigned int idx = entry - font_handles + FIRST_FONT_HANDLE;
320 return idx | (entry->generation << 16);
323 static inline struct font_handle_entry *handle_entry( DWORD handle )
325 unsigned int idx = LOWORD(handle) - FIRST_FONT_HANDLE;
327 if (idx < MAX_FONT_HANDLES)
329 if (!HIWORD( handle ) || HIWORD( handle ) == font_handles[idx].generation)
330 return &font_handles[idx];
332 if (handle) WARN( "invalid handle 0x%08x\n", handle );
333 return NULL;
336 static DWORD alloc_font_handle( void *obj )
338 struct font_handle_entry *entry;
340 entry = next_free;
341 if (entry)
342 next_free = entry->obj;
343 else if (next_unused < font_handles + MAX_FONT_HANDLES)
344 entry = next_unused++;
345 else
347 ERR( "out of realized font handles\n" );
348 return 0;
350 entry->obj = obj;
351 if (++entry->generation == 0xffff) entry->generation = 1;
352 return entry_to_handle( entry );
355 static void free_font_handle( DWORD handle )
357 struct font_handle_entry *entry;
359 if ((entry = handle_entry( handle )))
361 entry->obj = next_free;
362 next_free = entry;
366 typedef struct {
367 struct list entry;
368 Face *face;
369 GdiFont *font;
370 } CHILD_FONT;
372 struct font_fileinfo {
373 FILETIME writetime;
374 LARGE_INTEGER size;
375 WCHAR path[1];
378 struct tagGdiFont {
379 struct list entry;
380 struct list unused_entry;
381 unsigned int refcount;
382 GM **gm;
383 DWORD gmsize;
384 OUTLINETEXTMETRICW *potm;
385 DWORD total_kern_pairs;
386 KERNINGPAIR *kern_pairs;
387 struct list child_fonts;
389 /* the following members can be accessed without locking, they are never modified after creation */
390 FT_Face ft_face;
391 struct font_mapping *mapping;
392 LPWSTR name;
393 int charset;
394 int codepage;
395 BOOL fake_italic;
396 BOOL fake_bold;
397 BYTE underline;
398 BYTE strikeout;
399 INT orientation;
400 FONT_DESC font_desc;
401 LONG aveWidth, ppem;
402 double scale_y;
403 SHORT yMax;
404 SHORT yMin;
405 DWORD ntmFlags;
406 DWORD aa_flags;
407 UINT ntmCellHeight, ntmAvgWidth;
408 FONTSIGNATURE fs;
409 GdiFont *base_font;
410 VOID *GSUB_Table;
411 const VOID *vert_feature;
412 DWORD cache_num;
413 DWORD instance_id;
414 struct font_fileinfo *fileinfo;
417 typedef struct {
418 struct list entry;
419 const WCHAR *font_name;
420 FONTSIGNATURE fs;
421 struct list links;
422 } SYSTEM_LINKS;
424 struct enum_charset_element {
425 DWORD mask;
426 DWORD charset;
427 WCHAR name[LF_FACESIZE];
430 struct enum_charset_list {
431 DWORD total;
432 struct enum_charset_element element[32];
435 #define GM_BLOCK_SIZE 128
436 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
438 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
439 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
440 static unsigned int unused_font_count;
441 #define UNUSED_CACHE_SIZE 10
442 static struct list system_links = LIST_INIT(system_links);
444 static struct list font_subst_list = LIST_INIT(font_subst_list);
446 static struct list font_list = LIST_INIT(font_list);
448 struct freetype_physdev
450 struct gdi_physdev dev;
451 GdiFont *font;
454 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
456 return (struct freetype_physdev *)dev;
459 static const struct gdi_dc_funcs freetype_funcs;
461 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
462 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
463 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
465 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
466 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
467 'W','i','n','d','o','w','s','\\',
468 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
469 'F','o','n','t','s','\0'};
471 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
472 'W','i','n','d','o','w','s',' ','N','T','\\',
473 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
474 'F','o','n','t','s','\0'};
476 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
477 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
478 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
479 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
481 static const WCHAR * const SystemFontValues[] = {
482 System_Value,
483 OEMFont_Value,
484 FixedSys_Value,
485 NULL
488 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
489 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
491 /* Interesting and well-known (frequently-assumed!) font names */
492 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
493 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 };
494 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
495 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
496 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
497 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
498 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
499 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
501 static const WCHAR arial[] = {'A','r','i','a','l',0};
502 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
503 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};
504 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};
505 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
506 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
507 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
508 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
509 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
510 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
512 static const WCHAR *default_serif_list[] =
514 times_new_roman,
515 liberation_serif,
516 bitstream_vera_serif,
517 NULL
520 static const WCHAR *default_fixed_list[] =
522 courier_new,
523 liberation_mono,
524 bitstream_vera_sans_mono,
525 NULL
528 static const WCHAR *default_sans_list[] =
530 arial,
531 liberation_sans,
532 bitstream_vera_sans,
533 NULL
536 typedef struct {
537 WCHAR *name;
538 INT charset;
539 } NameCs;
541 typedef struct tagFontSubst {
542 struct list entry;
543 NameCs from;
544 NameCs to;
545 } FontSubst;
547 /* Registry font cache key and value names */
548 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
549 'F','o','n','t','s',0};
550 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
551 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
552 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
553 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
554 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
555 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
556 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
557 static const WCHAR face_size_value[] = {'S','i','z','e',0};
558 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
559 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
560 static const WCHAR face_flags_value[] = {'F','l','a','g','s',0};
561 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
562 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
563 static const WCHAR face_file_name_value[] = {'F','i','l','e',' ','N','a','m','e','\0'};
564 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
567 struct font_mapping
569 struct list entry;
570 int refcount;
571 dev_t dev;
572 ino_t ino;
573 void *data;
574 size_t size;
577 static struct list mappings_list = LIST_INIT( mappings_list );
579 static UINT default_aa_flags;
580 static HKEY hkey_font_cache;
581 static BOOL antialias_fakes = TRUE;
583 static CRITICAL_SECTION freetype_cs;
584 static CRITICAL_SECTION_DEBUG critsect_debug =
586 0, 0, &freetype_cs,
587 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
588 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
590 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
592 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
594 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
595 static BOOL use_default_fallback = FALSE;
597 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL *vert);
598 static BOOL get_outline_text_metrics(GdiFont *font);
599 static BOOL get_bitmap_text_metrics(GdiFont *font);
600 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
601 static void remove_face_from_cache( Face *face );
603 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
604 'W','i','n','d','o','w','s',' ','N','T','\\',
605 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
606 'S','y','s','t','e','m','L','i','n','k',0};
608 /****************************************
609 * Notes on .fon files
611 * The fonts System, FixedSys and Terminal are special. There are typically multiple
612 * versions installed for different resolutions and codepages. Windows stores which one to use
613 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
614 * Key Meaning
615 * FIXEDFON.FON FixedSys
616 * FONTS.FON System
617 * OEMFONT.FON Terminal
618 * LogPixels Current dpi set by the display control panel applet
619 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
620 * also has a LogPixels value that appears to mirror this)
622 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
623 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
624 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
625 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
626 * so that makes sense.
628 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
629 * to be mapped into the registry on Windows 2000 at least).
630 * I have
631 * woafont=app850.fon
632 * ega80woa.fon=ega80850.fon
633 * ega40woa.fon=ega40850.fon
634 * cga80woa.fon=cga80850.fon
635 * cga40woa.fon=cga40850.fon
638 /* These are all structures needed for the GSUB table */
640 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
642 typedef struct {
643 DWORD version;
644 WORD ScriptList;
645 WORD FeatureList;
646 WORD LookupList;
647 } GSUB_Header;
649 typedef struct {
650 CHAR ScriptTag[4];
651 WORD Script;
652 } GSUB_ScriptRecord;
654 typedef struct {
655 WORD ScriptCount;
656 GSUB_ScriptRecord ScriptRecord[1];
657 } GSUB_ScriptList;
659 typedef struct {
660 CHAR LangSysTag[4];
661 WORD LangSys;
662 } GSUB_LangSysRecord;
664 typedef struct {
665 WORD DefaultLangSys;
666 WORD LangSysCount;
667 GSUB_LangSysRecord LangSysRecord[1];
668 } GSUB_Script;
670 typedef struct {
671 WORD LookupOrder; /* Reserved */
672 WORD ReqFeatureIndex;
673 WORD FeatureCount;
674 WORD FeatureIndex[1];
675 } GSUB_LangSys;
677 typedef struct {
678 CHAR FeatureTag[4];
679 WORD Feature;
680 } GSUB_FeatureRecord;
682 typedef struct {
683 WORD FeatureCount;
684 GSUB_FeatureRecord FeatureRecord[1];
685 } GSUB_FeatureList;
687 typedef struct {
688 WORD FeatureParams; /* Reserved */
689 WORD LookupCount;
690 WORD LookupListIndex[1];
691 } GSUB_Feature;
693 typedef struct {
694 WORD LookupCount;
695 WORD Lookup[1];
696 } GSUB_LookupList;
698 typedef struct {
699 WORD LookupType;
700 WORD LookupFlag;
701 WORD SubTableCount;
702 WORD SubTable[1];
703 } GSUB_LookupTable;
705 typedef struct {
706 WORD CoverageFormat;
707 WORD GlyphCount;
708 WORD GlyphArray[1];
709 } GSUB_CoverageFormat1;
711 typedef struct {
712 WORD Start;
713 WORD End;
714 WORD StartCoverageIndex;
715 } GSUB_RangeRecord;
717 typedef struct {
718 WORD CoverageFormat;
719 WORD RangeCount;
720 GSUB_RangeRecord RangeRecord[1];
721 } GSUB_CoverageFormat2;
723 typedef struct {
724 WORD SubstFormat; /* = 1 */
725 WORD Coverage;
726 WORD DeltaGlyphID;
727 } GSUB_SingleSubstFormat1;
729 typedef struct {
730 WORD SubstFormat; /* = 2 */
731 WORD Coverage;
732 WORD GlyphCount;
733 WORD Substitute[1];
734 }GSUB_SingleSubstFormat2;
736 #ifdef HAVE_CARBON_CARBON_H
737 static char *find_cache_dir(void)
739 FSRef ref;
740 OSErr err;
741 static char cached_path[MAX_PATH];
742 static const char *wine = "/Wine", *fonts = "/Fonts";
744 if(*cached_path) return cached_path;
746 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
747 if(err != noErr)
749 WARN("can't create cached data folder\n");
750 return NULL;
752 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
753 if(err != noErr)
755 WARN("can't create cached data path\n");
756 *cached_path = '\0';
757 return NULL;
759 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
761 ERR("Could not create full path\n");
762 *cached_path = '\0';
763 return NULL;
765 strcat(cached_path, wine);
767 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
769 WARN("Couldn't mkdir %s\n", cached_path);
770 *cached_path = '\0';
771 return NULL;
773 strcat(cached_path, fonts);
774 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
776 WARN("Couldn't mkdir %s\n", cached_path);
777 *cached_path = '\0';
778 return NULL;
780 return cached_path;
783 /******************************************************************
784 * expand_mac_font
786 * Extracts individual TrueType font files from a Mac suitcase font
787 * and saves them into the user's caches directory (see
788 * find_cache_dir()).
789 * Returns a NULL terminated array of filenames.
791 * We do this because they are apps that try to read ttf files
792 * themselves and they don't like Mac suitcase files.
794 static char **expand_mac_font(const char *path)
796 FSRef ref;
797 SInt16 res_ref;
798 OSStatus s;
799 unsigned int idx;
800 const char *out_dir;
801 const char *filename;
802 int output_len;
803 struct {
804 char **array;
805 unsigned int size, max_size;
806 } ret;
808 TRACE("path %s\n", path);
810 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
811 if(s != noErr)
813 WARN("failed to get ref\n");
814 return NULL;
817 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
818 if(s != noErr)
820 TRACE("no data fork, so trying resource fork\n");
821 res_ref = FSOpenResFile(&ref, fsRdPerm);
822 if(res_ref == -1)
824 TRACE("unable to open resource fork\n");
825 return NULL;
829 ret.size = 0;
830 ret.max_size = 10;
831 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
832 if(!ret.array)
834 CloseResFile(res_ref);
835 return NULL;
838 out_dir = find_cache_dir();
840 filename = strrchr(path, '/');
841 if(!filename) filename = path;
842 else filename++;
844 /* output filename has the form out_dir/filename_%04x.ttf */
845 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
847 UseResFile(res_ref);
848 idx = 1;
849 while(1)
851 FamRec *fam_rec;
852 unsigned short *num_faces_ptr, num_faces, face;
853 AsscEntry *assoc;
854 Handle fond;
855 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
857 fond = Get1IndResource(fond_res, idx);
858 if(!fond) break;
859 TRACE("got fond resource %d\n", idx);
860 HLock(fond);
862 fam_rec = *(FamRec**)fond;
863 num_faces_ptr = (unsigned short *)(fam_rec + 1);
864 num_faces = GET_BE_WORD(*num_faces_ptr);
865 num_faces++;
866 assoc = (AsscEntry*)(num_faces_ptr + 1);
867 TRACE("num faces %04x\n", num_faces);
868 for(face = 0; face < num_faces; face++, assoc++)
870 Handle sfnt;
871 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
872 unsigned short size, font_id;
873 char *output;
875 size = GET_BE_WORD(assoc->fontSize);
876 font_id = GET_BE_WORD(assoc->fontID);
877 if(size != 0)
879 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
880 continue;
883 TRACE("trying to load sfnt id %04x\n", font_id);
884 sfnt = GetResource(sfnt_res, font_id);
885 if(!sfnt)
887 TRACE("can't get sfnt resource %04x\n", font_id);
888 continue;
891 output = HeapAlloc(GetProcessHeap(), 0, output_len);
892 if(output)
894 int fd;
896 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
898 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
899 if(fd != -1 || errno == EEXIST)
901 if(fd != -1)
903 unsigned char *sfnt_data;
905 HLock(sfnt);
906 sfnt_data = *(unsigned char**)sfnt;
907 write(fd, sfnt_data, GetHandleSize(sfnt));
908 HUnlock(sfnt);
909 close(fd);
911 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
913 ret.max_size *= 2;
914 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
916 ret.array[ret.size++] = output;
918 else
920 WARN("unable to create %s\n", output);
921 HeapFree(GetProcessHeap(), 0, output);
924 ReleaseResource(sfnt);
926 HUnlock(fond);
927 ReleaseResource(fond);
928 idx++;
930 CloseResFile(res_ref);
932 return ret.array;
935 #endif /* HAVE_CARBON_CARBON_H */
937 static inline BOOL is_win9x(void)
939 return GetVersion() & 0x80000000;
942 This function builds an FT_Fixed from a double. It fails if the absolute
943 value of the float number is greater than 32768.
945 static inline FT_Fixed FT_FixedFromFloat(double f)
947 return f * 0x10000;
951 This function builds an FT_Fixed from a FIXED. It simply put f.value
952 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
954 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
956 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
959 static BOOL is_hinting_enabled(void)
961 static int enabled = -1;
963 if (enabled == -1)
965 /* Use the >= 2.2.0 function if available */
966 if (pFT_Get_TrueType_Engine_Type)
968 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
969 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
971 else enabled = FALSE;
972 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
974 return enabled;
977 static BOOL is_subpixel_rendering_enabled( void )
979 #ifdef FT_LCD_FILTER_H
980 static int enabled = -1;
981 if (enabled == -1)
983 enabled = (pFT_Library_SetLcdFilter &&
984 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature);
985 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
987 return enabled;
988 #else
989 return FALSE;
990 #endif
994 static const struct list *get_face_list_from_family(const Family *family)
996 if (!list_empty(&family->faces))
997 return &family->faces;
998 else
999 return family->replacement;
1002 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
1004 Family *family;
1005 Face *face;
1006 const WCHAR *file;
1008 TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
1010 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1012 const struct list *face_list;
1013 if(face_name && strcmpiW(face_name, family->FamilyName))
1014 continue;
1015 face_list = get_face_list_from_family(family);
1016 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
1018 if (!face->file)
1019 continue;
1020 file = strrchrW(face->file, '/');
1021 if(!file)
1022 file = face->file;
1023 else
1024 file++;
1025 if(strcmpiW(file, file_name)) continue;
1026 face->refcount++;
1027 return face;
1030 return NULL;
1033 static Family *find_family_from_name(const WCHAR *name)
1035 Family *family;
1037 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1039 if(!strcmpiW(family->FamilyName, name))
1040 return family;
1043 return NULL;
1046 static Family *find_family_from_any_name(const WCHAR *name)
1048 Family *family;
1050 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1052 if(!strcmpiW(family->FamilyName, name))
1053 return family;
1054 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
1055 return family;
1058 return NULL;
1061 static void DumpSubstList(void)
1063 FontSubst *psub;
1065 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
1067 if(psub->from.charset != -1 || psub->to.charset != -1)
1068 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
1069 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
1070 else
1071 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
1072 debugstr_w(psub->to.name));
1076 static LPWSTR strdupW(LPCWSTR p)
1078 LPWSTR ret;
1079 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
1080 ret = HeapAlloc(GetProcessHeap(), 0, len);
1081 memcpy(ret, p, len);
1082 return ret;
1085 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1086 INT from_charset)
1088 FontSubst *element;
1090 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1092 if(!strcmpiW(element->from.name, from_name) &&
1093 (element->from.charset == from_charset ||
1094 element->from.charset == -1))
1095 return element;
1098 return NULL;
1101 #define ADD_FONT_SUBST_FORCE 1
1103 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1105 FontSubst *from_exist, *to_exist;
1107 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1109 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1111 list_remove(&from_exist->entry);
1112 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
1113 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
1114 HeapFree(GetProcessHeap(), 0, from_exist);
1115 from_exist = NULL;
1118 if(!from_exist)
1120 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1122 if(to_exist)
1124 HeapFree(GetProcessHeap(), 0, subst->to.name);
1125 subst->to.name = strdupW(to_exist->to.name);
1128 list_add_tail(subst_list, &subst->entry);
1130 return TRUE;
1133 HeapFree(GetProcessHeap(), 0, subst->from.name);
1134 HeapFree(GetProcessHeap(), 0, subst->to.name);
1135 HeapFree(GetProcessHeap(), 0, subst);
1136 return FALSE;
1139 static WCHAR *towstr(UINT cp, const char *str)
1141 int len;
1142 WCHAR *wstr;
1144 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1145 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1146 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1147 return wstr;
1150 static char *strWtoA(UINT cp, const WCHAR *str)
1152 int len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL );
1153 char *ret = HeapAlloc( GetProcessHeap(), 0, len );
1154 WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL );
1155 return ret;
1158 static void split_subst_info(NameCs *nc, LPSTR str)
1160 CHAR *p = strrchr(str, ',');
1162 nc->charset = -1;
1163 if(p && *(p+1)) {
1164 nc->charset = strtol(p+1, NULL, 10);
1165 *p = '\0';
1167 nc->name = towstr(CP_ACP, str);
1170 static void LoadSubstList(void)
1172 FontSubst *psub;
1173 HKEY hkey;
1174 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1175 LPSTR value;
1176 LPVOID data;
1178 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1179 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1180 &hkey) == ERROR_SUCCESS) {
1182 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1183 &valuelen, &datalen, NULL, NULL);
1185 valuelen++; /* returned value doesn't include room for '\0' */
1186 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1187 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1189 dlen = datalen;
1190 vlen = valuelen;
1191 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1192 &dlen) == ERROR_SUCCESS) {
1193 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1195 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1196 split_subst_info(&psub->from, value);
1197 split_subst_info(&psub->to, data);
1199 /* Win 2000 doesn't allow mapping between different charsets
1200 or mapping of DEFAULT_CHARSET */
1201 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1202 psub->to.charset == DEFAULT_CHARSET) {
1203 HeapFree(GetProcessHeap(), 0, psub->to.name);
1204 HeapFree(GetProcessHeap(), 0, psub->from.name);
1205 HeapFree(GetProcessHeap(), 0, psub);
1206 } else {
1207 add_font_subst(&font_subst_list, psub, 0);
1209 /* reset dlen and vlen */
1210 dlen = datalen;
1211 vlen = valuelen;
1213 HeapFree(GetProcessHeap(), 0, data);
1214 HeapFree(GetProcessHeap(), 0, value);
1215 RegCloseKey(hkey);
1220 static const LANGID mac_langid_table[] =
1222 MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */
1223 MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */
1224 MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */
1225 MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */
1226 MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */
1227 MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */
1228 MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */
1229 MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */
1230 MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */
1231 MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */
1232 MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */
1233 MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */
1234 MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */
1235 MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */
1236 MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */
1237 MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */
1238 MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */
1239 MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */
1240 MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */
1241 MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
1242 MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */
1243 MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */
1244 MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */
1245 MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */
1246 MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */
1247 MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */
1248 MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */
1249 MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */
1250 MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */
1251 MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */
1252 MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */
1253 MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */
1254 MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */
1255 MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
1256 MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */
1257 MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */
1258 MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */
1259 MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */
1260 MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */
1261 MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */
1262 MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */
1263 0, /* TT_MAC_LANGID_YIDDISH */
1264 MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */
1265 MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */
1266 MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */
1267 MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */
1268 MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */
1269 MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */
1270 MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */
1271 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */
1272 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
1273 MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */
1274 MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */
1275 0, /* TT_MAC_LANGID_MOLDAVIAN */
1276 MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */
1277 MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */
1278 MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */
1279 MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */
1280 MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
1281 MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */
1282 0, /* TT_MAC_LANGID_KURDISH */
1283 MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */
1284 MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */
1285 MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */
1286 MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */
1287 MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */
1288 MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */
1289 MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */
1290 MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */
1291 MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */
1292 MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */
1293 MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */
1294 MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */
1295 MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */
1296 MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */
1297 MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */
1298 MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */
1299 0, /* TT_MAC_LANGID_BURMESE */
1300 MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */
1301 MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */
1302 MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */
1303 MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */
1304 0, /* TT_MAC_LANGID_TAGALOG */
1305 MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
1306 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
1307 MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */
1308 MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */
1309 0, /* TT_MAC_LANGID_GALLA */
1310 0, /* TT_MAC_LANGID_SOMALI */
1311 MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */
1312 0, /* TT_MAC_LANGID_RUANDA */
1313 0, /* TT_MAC_LANGID_RUNDI */
1314 0, /* TT_MAC_LANGID_CHEWA */
1315 MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */
1316 MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */
1317 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
1318 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
1319 MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */
1320 MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */
1321 MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */
1322 0, /* TT_MAC_LANGID_LATIN */
1323 MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */
1324 0, /* TT_MAC_LANGID_GUARANI */
1325 0, /* TT_MAC_LANGID_AYMARA */
1326 MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */
1327 MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */
1328 0, /* TT_MAC_LANGID_DZONGKHA */
1329 0, /* TT_MAC_LANGID_JAVANESE */
1330 0, /* TT_MAC_LANGID_SUNDANESE */
1331 MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */
1332 MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */
1333 MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */
1334 MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */
1335 MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
1336 MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */
1337 MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */
1338 0, /* TT_MAC_LANGID_TONGAN */
1339 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
1340 MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */
1341 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
1344 static inline WORD get_mac_code_page( const FT_SfntName *name )
1346 if (name->encoding_id == TT_MAC_ID_SIMPLIFIED_CHINESE) return 10008; /* special case */
1347 return 10000 + name->encoding_id;
1350 static int match_name_table_language( const FT_SfntName *name, LANGID lang )
1352 LANGID name_lang;
1353 int res = 0;
1355 switch (name->platform_id)
1357 case TT_PLATFORM_MICROSOFT:
1358 res += 5; /* prefer the Microsoft name */
1359 switch (name->encoding_id)
1361 case TT_MS_ID_UNICODE_CS:
1362 case TT_MS_ID_SYMBOL_CS:
1363 name_lang = name->language_id;
1364 break;
1365 default:
1366 return 0;
1368 break;
1369 case TT_PLATFORM_MACINTOSH:
1370 if (!IsValidCodePage( get_mac_code_page( name ))) return 0;
1371 if (name->language_id >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
1372 name_lang = mac_langid_table[name->language_id];
1373 break;
1374 case TT_PLATFORM_APPLE_UNICODE:
1375 res += 2; /* prefer Unicode encodings */
1376 switch (name->encoding_id)
1378 case TT_APPLE_ID_DEFAULT:
1379 case TT_APPLE_ID_ISO_10646:
1380 case TT_APPLE_ID_UNICODE_2_0:
1381 if (name->language_id >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
1382 name_lang = mac_langid_table[name->language_id];
1383 break;
1384 default:
1385 return 0;
1387 break;
1388 default:
1389 return 0;
1391 if (name_lang == lang) res += 30;
1392 else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20;
1393 else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10;
1394 return res;
1397 static WCHAR *copy_name_table_string( const FT_SfntName *name )
1399 WCHAR *ret;
1400 WORD codepage;
1401 int i;
1403 switch (name->platform_id)
1405 case TT_PLATFORM_APPLE_UNICODE:
1406 case TT_PLATFORM_MICROSOFT:
1407 ret = HeapAlloc( GetProcessHeap(), 0, name->string_len + sizeof(WCHAR) );
1408 for (i = 0; i < name->string_len / 2; i++)
1409 ret[i] = (name->string[i * 2] << 8) | name->string[i * 2 + 1];
1410 ret[i] = 0;
1411 return ret;
1412 case TT_PLATFORM_MACINTOSH:
1413 codepage = get_mac_code_page( name );
1414 i = MultiByteToWideChar( codepage, 0, (char *)name->string, name->string_len, NULL, 0 );
1415 ret = HeapAlloc( GetProcessHeap(), 0, (i + 1) * sizeof(WCHAR) );
1416 MultiByteToWideChar( codepage, 0, (char *)name->string, name->string_len, ret, i );
1417 ret[i] = 0;
1418 return ret;
1420 return NULL;
1423 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, LANGID language_id)
1425 FT_SfntName name;
1426 FT_UInt num_names, name_index;
1427 int res, best_lang = 0, best_index = -1;
1429 if (!FT_IS_SFNT(ft_face)) return NULL;
1431 num_names = pFT_Get_Sfnt_Name_Count( ft_face );
1433 for (name_index = 0; name_index < num_names; name_index++)
1435 if (pFT_Get_Sfnt_Name( ft_face, name_index, &name )) continue;
1436 if (name.name_id != name_id) continue;
1437 res = match_name_table_language( &name, language_id );
1438 if (res > best_lang)
1440 best_lang = res;
1441 best_index = name_index;
1445 if (best_index != -1 && !pFT_Get_Sfnt_Name( ft_face, best_index, &name ))
1447 WCHAR *ret = copy_name_table_string( &name );
1448 TRACE( "name %u found platform %u lang %04x %s\n",
1449 name_id, name.platform_id, name.language_id, debugstr_w( ret ));
1450 return ret;
1452 return NULL;
1455 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1457 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1458 if (f1->scalable) return TRUE;
1459 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1460 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1463 static void release_family( Family *family )
1465 if (--family->refcount) return;
1466 assert( list_empty( &family->faces ));
1467 list_remove( &family->entry );
1468 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1469 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1470 HeapFree( GetProcessHeap(), 0, family );
1473 static void release_face( Face *face )
1475 if (--face->refcount) return;
1476 if (face->family)
1478 if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
1479 list_remove( &face->entry );
1480 release_family( face->family );
1482 HeapFree( GetProcessHeap(), 0, face->file );
1483 HeapFree( GetProcessHeap(), 0, face->StyleName );
1484 HeapFree( GetProcessHeap(), 0, face->FullName );
1485 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1486 HeapFree( GetProcessHeap(), 0, face );
1489 static inline int style_order(const Face *face)
1491 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1493 case NTM_REGULAR:
1494 return 0;
1495 case NTM_BOLD:
1496 return 1;
1497 case NTM_ITALIC:
1498 return 2;
1499 case NTM_BOLD | NTM_ITALIC:
1500 return 3;
1501 default:
1502 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1503 debugstr_w(face->family->FamilyName),
1504 debugstr_w(face->StyleName),
1505 face->ntmFlags);
1506 return 9999;
1510 static BOOL insert_face_in_family_list( Face *face, Family *family )
1512 Face *cursor;
1514 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1516 if (faces_equal( face, cursor ))
1518 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1519 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1520 cursor->font_version, face->font_version);
1522 if (face->file && face->dev == cursor->dev && face->ino == cursor->ino)
1524 cursor->refcount++;
1525 TRACE("Font %s already in list, refcount now %d\n",
1526 debugstr_w(face->file), cursor->refcount);
1527 return FALSE;
1529 if (face->font_version <= cursor->font_version)
1531 TRACE("Original font %s is newer so skipping %s\n",
1532 debugstr_w(cursor->file), debugstr_w(face->file));
1533 return FALSE;
1535 else
1537 TRACE("Replacing original %s with %s\n",
1538 debugstr_w(cursor->file), debugstr_w(face->file));
1539 list_add_before( &cursor->entry, &face->entry );
1540 face->family = family;
1541 family->refcount++;
1542 face->refcount++;
1543 release_face( cursor );
1544 return TRUE;
1547 else
1548 TRACE("Adding new %s\n", debugstr_w(face->file));
1550 if (style_order( face ) < style_order( cursor )) break;
1553 list_add_before( &cursor->entry, &face->entry );
1554 face->family = family;
1555 family->refcount++;
1556 face->refcount++;
1557 return TRUE;
1560 /****************************************************************
1561 * NB This function stores the ptrs to the strings to save copying.
1562 * Don't free them after calling.
1564 static Family *create_family( WCHAR *name, WCHAR *english_name )
1566 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1567 family->refcount = 1;
1568 family->FamilyName = name;
1569 family->EnglishName = english_name;
1570 list_init( &family->faces );
1571 family->replacement = &family->faces;
1572 list_add_tail( &font_list, &family->entry );
1574 return family;
1577 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1579 DWORD type, size = sizeof(DWORD);
1581 if (RegQueryValueExW(hkey, value, NULL, &type, (BYTE *)data, &size) ||
1582 type != REG_DWORD || size != sizeof(DWORD))
1584 *data = 0;
1585 return ERROR_BAD_CONFIGURATION;
1587 return ERROR_SUCCESS;
1590 static inline LONG reg_load_ftlong(HKEY hkey, const WCHAR *value, FT_Long *data)
1592 DWORD dw;
1593 LONG ret = reg_load_dword(hkey, value, &dw);
1594 *data = dw;
1595 return ret;
1598 static inline LONG reg_load_ftshort(HKEY hkey, const WCHAR *value, FT_Short *data)
1600 DWORD dw;
1601 LONG ret = reg_load_dword(hkey, value, &dw);
1602 *data = dw;
1603 return ret;
1606 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1608 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1611 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1613 DWORD needed, strike_index = 0;
1614 HKEY hkey_strike;
1616 /* If we have a File Name key then this is a real font, not just the parent
1617 key of a bunch of non-scalable strikes */
1618 needed = buffer_size;
1619 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1621 Face *face;
1622 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1623 face->cached_enum_data = NULL;
1624 face->family = NULL;
1626 face->refcount = 1;
1627 face->file = strdupW( buffer );
1628 face->StyleName = strdupW(face_name);
1630 needed = buffer_size;
1631 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1632 face->FullName = strdupW( buffer );
1633 else
1634 face->FullName = NULL;
1636 reg_load_ftlong(hkey_face, face_index_value, &face->face_index);
1637 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1638 reg_load_ftlong(hkey_face, face_version_value, &face->font_version);
1639 reg_load_dword(hkey_face, face_flags_value, &face->flags);
1641 needed = sizeof(face->fs);
1642 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1644 if(reg_load_ftshort(hkey_face, face_height_value, &face->size.height) != ERROR_SUCCESS)
1646 face->scalable = TRUE;
1647 memset(&face->size, 0, sizeof(face->size));
1649 else
1651 face->scalable = FALSE;
1652 reg_load_ftshort(hkey_face, face_width_value, &face->size.width);
1653 reg_load_ftlong(hkey_face, face_size_value, &face->size.size);
1654 reg_load_ftlong(hkey_face, face_x_ppem_value, &face->size.x_ppem);
1655 reg_load_ftlong(hkey_face, face_y_ppem_value, &face->size.y_ppem);
1656 reg_load_ftshort(hkey_face, face_internal_leading_value, &face->size.internal_leading);
1658 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1659 face->size.height, face->size.width, face->size.size >> 6,
1660 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1663 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1664 face->fs.fsCsb[0], face->fs.fsCsb[1],
1665 face->fs.fsUsb[0], face->fs.fsUsb[1],
1666 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1668 if (insert_face_in_family_list(face, family))
1669 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1671 release_face( face );
1674 /* load bitmap strikes */
1676 needed = buffer_size;
1677 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1679 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1681 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1682 RegCloseKey(hkey_strike);
1684 needed = buffer_size;
1688 /* move vertical fonts after their horizontal counterpart */
1689 /* assumes that font_list is already sorted by family name */
1690 static void reorder_vertical_fonts(void)
1692 Family *family, *next, *vert_family;
1693 struct list *ptr, *vptr;
1694 struct list vertical_families = LIST_INIT( vertical_families );
1696 LIST_FOR_EACH_ENTRY_SAFE( family, next, &font_list, Family, entry )
1698 if (family->FamilyName[0] != '@') continue;
1699 list_remove( &family->entry );
1700 list_add_tail( &vertical_families, &family->entry );
1703 ptr = list_head( &font_list );
1704 vptr = list_head( &vertical_families );
1705 while (ptr && vptr)
1707 family = LIST_ENTRY( ptr, Family, entry );
1708 vert_family = LIST_ENTRY( vptr, Family, entry );
1709 if (strcmpiW( family->FamilyName, vert_family->FamilyName + 1 ) > 0)
1711 list_remove( vptr );
1712 list_add_before( ptr, vptr );
1713 vptr = list_head( &vertical_families );
1715 else ptr = list_next( &font_list, ptr );
1717 list_move_tail( &font_list, &vertical_families );
1720 static void load_font_list_from_cache(HKEY hkey_font_cache)
1722 DWORD size, family_index = 0;
1723 Family *family;
1724 HKEY hkey_family;
1725 WCHAR buffer[4096];
1727 size = sizeof(buffer);
1728 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1730 WCHAR *english_family = NULL;
1731 WCHAR *family_name = strdupW( buffer );
1732 DWORD face_index = 0;
1734 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1735 TRACE("opened family key %s\n", debugstr_w(family_name));
1736 size = sizeof(buffer);
1737 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1738 english_family = strdupW( buffer );
1740 family = create_family(family_name, english_family);
1742 if(english_family)
1744 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1745 subst->from.name = strdupW(english_family);
1746 subst->from.charset = -1;
1747 subst->to.name = strdupW(family_name);
1748 subst->to.charset = -1;
1749 add_font_subst(&font_subst_list, subst, 0);
1752 size = sizeof(buffer);
1753 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1755 WCHAR *face_name = strdupW( buffer );
1756 HKEY hkey_face;
1758 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1760 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1761 RegCloseKey(hkey_face);
1763 HeapFree( GetProcessHeap(), 0, face_name );
1764 size = sizeof(buffer);
1766 RegCloseKey(hkey_family);
1767 release_family( family );
1768 size = sizeof(buffer);
1771 reorder_vertical_fonts();
1774 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1776 LONG ret;
1777 HKEY hkey_wine_fonts;
1779 /* We don't want to create the fonts key as volatile, so open this first */
1780 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1781 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1782 if(ret != ERROR_SUCCESS)
1784 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1785 return ret;
1788 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1789 KEY_ALL_ACCESS, NULL, hkey, disposition);
1790 RegCloseKey(hkey_wine_fonts);
1791 return ret;
1794 static void add_face_to_cache(Face *face)
1796 HKEY hkey_family, hkey_face;
1797 WCHAR *face_key_name;
1799 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1800 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1801 if(face->family->EnglishName)
1802 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1803 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1805 if(face->scalable)
1806 face_key_name = face->StyleName;
1807 else
1809 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1810 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1811 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1813 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1814 &hkey_face, NULL);
1815 if(!face->scalable)
1816 HeapFree(GetProcessHeap(), 0, face_key_name);
1818 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1819 (strlenW(face->file) + 1) * sizeof(WCHAR));
1820 if (face->FullName)
1821 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1822 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1824 reg_save_dword(hkey_face, face_index_value, face->face_index);
1825 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1826 reg_save_dword(hkey_face, face_version_value, face->font_version);
1827 if (face->flags) reg_save_dword(hkey_face, face_flags_value, face->flags);
1829 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1831 if(!face->scalable)
1833 reg_save_dword(hkey_face, face_height_value, face->size.height);
1834 reg_save_dword(hkey_face, face_width_value, face->size.width);
1835 reg_save_dword(hkey_face, face_size_value, face->size.size);
1836 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1837 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1838 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1840 RegCloseKey(hkey_face);
1841 RegCloseKey(hkey_family);
1844 static void remove_face_from_cache( Face *face )
1846 HKEY hkey_family;
1848 RegOpenKeyExW( hkey_font_cache, face->family->FamilyName, 0, KEY_ALL_ACCESS, &hkey_family );
1850 if (face->scalable)
1852 RegDeleteKeyW( hkey_family, face->StyleName );
1854 else
1856 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1857 WCHAR *face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1858 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1859 RegDeleteKeyW( hkey_family, face_key_name );
1860 HeapFree(GetProcessHeap(), 0, face_key_name);
1862 RegCloseKey(hkey_family);
1865 static WCHAR *prepend_at(WCHAR *family)
1867 WCHAR *str;
1869 if (!family)
1870 return NULL;
1872 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1873 str[0] = '@';
1874 strcpyW(str + 1, family);
1875 HeapFree(GetProcessHeap(), 0, family);
1876 return str;
1879 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1881 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT) );
1882 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1884 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1885 if (!*name)
1887 *name = *english;
1888 *english = NULL;
1890 else if (!strcmpiW( *name, *english ))
1892 HeapFree( GetProcessHeap(), 0, *english );
1893 *english = NULL;
1896 if (vertical)
1898 *name = prepend_at( *name );
1899 *english = prepend_at( *english );
1903 static Family *get_family( FT_Face ft_face, BOOL vertical )
1905 Family *family;
1906 WCHAR *name, *english_name;
1908 get_family_names( ft_face, &name, &english_name, vertical );
1910 family = find_family_from_name( name );
1912 if (!family)
1914 family = create_family( name, english_name );
1915 if (english_name)
1917 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1918 subst->from.name = strdupW( english_name );
1919 subst->from.charset = -1;
1920 subst->to.name = strdupW( name );
1921 subst->to.charset = -1;
1922 add_font_subst( &font_subst_list, subst, 0 );
1925 else
1927 HeapFree( GetProcessHeap(), 0, name );
1928 HeapFree( GetProcessHeap(), 0, english_name );
1929 family->refcount++;
1932 return family;
1935 static inline FT_Fixed get_font_version( FT_Face ft_face )
1937 FT_Fixed version = 0;
1938 TT_Header *header;
1940 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1941 if (header) version = header->Font_Revision;
1943 return version;
1946 static inline DWORD get_ntm_flags( FT_Face ft_face )
1948 DWORD flags = 0;
1949 FT_ULong table_size = 0;
1950 FT_WinFNT_HeaderRec winfnt_header;
1952 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1953 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1955 /* fixup the flag for our fake-bold implementation. */
1956 if (!FT_IS_SCALABLE( ft_face ) &&
1957 !pFT_Get_WinFNT_Header( ft_face, &winfnt_header ) &&
1958 winfnt_header.weight > FW_NORMAL )
1959 flags |= NTM_BOLD;
1961 if (flags == 0) flags = NTM_REGULAR;
1963 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1964 flags |= NTM_PS_OPENTYPE;
1966 return flags;
1969 static inline void get_bitmap_size( FT_Face ft_face, Bitmap_Size *face_size )
1971 My_FT_Bitmap_Size *size;
1972 FT_WinFNT_HeaderRec winfnt_header;
1974 size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1975 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1976 size->height, size->width, size->size >> 6,
1977 size->x_ppem >> 6, size->y_ppem >> 6);
1978 face_size->height = size->height;
1979 face_size->width = size->width;
1980 face_size->size = size->size;
1981 face_size->x_ppem = size->x_ppem;
1982 face_size->y_ppem = size->y_ppem;
1984 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header )) {
1985 face_size->internal_leading = winfnt_header.internal_leading;
1986 if (winfnt_header.external_leading > 0 &&
1987 (face_size->height ==
1988 winfnt_header.pixel_height + winfnt_header.external_leading))
1989 face_size->height = winfnt_header.pixel_height;
1993 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1995 TT_OS2 *os2;
1996 FT_UInt dummy;
1997 CHARSETINFO csi;
1998 FT_WinFNT_HeaderRec winfnt_header;
1999 int i;
2001 memset( fs, 0, sizeof(*fs) );
2003 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
2004 if (os2)
2006 fs->fsUsb[0] = os2->ulUnicodeRange1;
2007 fs->fsUsb[1] = os2->ulUnicodeRange2;
2008 fs->fsUsb[2] = os2->ulUnicodeRange3;
2009 fs->fsUsb[3] = os2->ulUnicodeRange4;
2011 if (os2->version == 0)
2013 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
2014 fs->fsCsb[0] = FS_LATIN1;
2015 else
2016 fs->fsCsb[0] = FS_SYMBOL;
2018 else
2020 fs->fsCsb[0] = os2->ulCodePageRange1;
2021 fs->fsCsb[1] = os2->ulCodePageRange2;
2024 else
2026 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
2028 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
2029 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
2030 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
2031 *fs = csi.fs;
2035 if (fs->fsCsb[0] == 0)
2037 /* let's see if we can find any interesting cmaps */
2038 for (i = 0; i < ft_face->num_charmaps; i++)
2040 switch (ft_face->charmaps[i]->encoding)
2042 case FT_ENCODING_UNICODE:
2043 case FT_ENCODING_APPLE_ROMAN:
2044 fs->fsCsb[0] |= FS_LATIN1;
2045 break;
2046 case FT_ENCODING_MS_SYMBOL:
2047 fs->fsCsb[0] |= FS_SYMBOL;
2048 break;
2049 default:
2050 break;
2056 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
2057 DWORD flags )
2059 struct stat st;
2060 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
2062 face->refcount = 1;
2063 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
2064 if (!face->StyleName) face->StyleName = towstr( CP_ACP, ft_face->style_name );
2066 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
2067 if (flags & ADDFONT_VERTICAL_FONT)
2068 face->FullName = prepend_at( face->FullName );
2070 face->dev = 0;
2071 face->ino = 0;
2072 if (file)
2074 face->file = towstr( CP_UNIXCP, file );
2075 face->font_data_ptr = NULL;
2076 face->font_data_size = 0;
2077 if (!stat( file, &st ))
2079 face->dev = st.st_dev;
2080 face->ino = st.st_ino;
2083 else
2085 face->file = NULL;
2086 face->font_data_ptr = font_data_ptr;
2087 face->font_data_size = font_data_size;
2090 face->face_index = face_index;
2091 get_fontsig( ft_face, &face->fs );
2092 face->ntmFlags = get_ntm_flags( ft_face );
2093 face->font_version = get_font_version( ft_face );
2095 if (FT_IS_SCALABLE( ft_face ))
2097 memset( &face->size, 0, sizeof(face->size) );
2098 face->scalable = TRUE;
2100 else
2102 get_bitmap_size( ft_face, &face->size );
2103 face->scalable = FALSE;
2106 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
2107 face->flags = flags;
2108 face->family = NULL;
2109 face->cached_enum_data = NULL;
2111 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
2112 face->fs.fsCsb[0], face->fs.fsCsb[1],
2113 face->fs.fsUsb[0], face->fs.fsUsb[1],
2114 face->fs.fsUsb[2], face->fs.fsUsb[3]);
2116 return face;
2119 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
2120 FT_Long face_index, DWORD flags )
2122 Face *face;
2123 Family *family;
2125 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags );
2126 family = get_family( ft_face, flags & ADDFONT_VERTICAL_FONT );
2127 if (strlenW(family->FamilyName) >= LF_FACESIZE)
2129 WARN("Ignoring %s because name is too long\n", debugstr_w(family->FamilyName));
2130 release_face( face );
2131 release_family( family );
2132 return;
2135 if (insert_face_in_family_list( face, family ))
2137 if (flags & ADDFONT_ADD_TO_CACHE)
2138 add_face_to_cache( face );
2140 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
2141 debugstr_w(face->StyleName));
2143 release_face( face );
2144 release_family( family );
2147 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
2148 FT_Long face_index, BOOL allow_bitmap )
2150 FT_Error err;
2151 TT_OS2 *pOS2;
2152 FT_Face ft_face;
2154 if (file)
2156 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
2157 err = pFT_New_Face(library, file, face_index, &ft_face);
2159 else
2161 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
2162 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
2165 if (err != 0)
2167 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
2168 return NULL;
2171 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
2172 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
2174 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
2175 goto fail;
2178 if (!FT_IS_SFNT( ft_face ))
2180 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
2182 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
2183 goto fail;
2186 else
2188 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
2189 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
2190 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
2192 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
2193 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
2194 goto fail;
2197 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
2198 we don't want to load these. */
2199 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
2201 FT_ULong len = 0;
2203 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
2205 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
2206 goto fail;
2211 if (!ft_face->family_name || !ft_face->style_name)
2213 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
2214 goto fail;
2217 return ft_face;
2218 fail:
2219 pFT_Done_Face( ft_face );
2220 return NULL;
2223 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
2225 FT_Face ft_face;
2226 FT_Long face_index = 0, num_faces;
2227 INT ret = 0;
2229 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
2230 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
2232 #ifdef HAVE_CARBON_CARBON_H
2233 if(file)
2235 char **mac_list = expand_mac_font(file);
2236 if(mac_list)
2238 BOOL had_one = FALSE;
2239 char **cursor;
2240 for(cursor = mac_list; *cursor; cursor++)
2242 had_one = TRUE;
2243 AddFontToList(*cursor, NULL, 0, flags);
2244 HeapFree(GetProcessHeap(), 0, *cursor);
2246 HeapFree(GetProcessHeap(), 0, mac_list);
2247 if(had_one)
2248 return 1;
2251 #endif /* HAVE_CARBON_CARBON_H */
2253 do {
2254 const DWORD FS_DBCS_MASK = FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB;
2255 FONTSIGNATURE fs;
2257 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_ALLOW_BITMAP );
2258 if (!ft_face) return 0;
2260 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
2262 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
2263 pFT_Done_Face(ft_face);
2264 return 0;
2267 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags);
2268 ++ret;
2270 get_fontsig(ft_face, &fs);
2271 if (fs.fsCsb[0] & FS_DBCS_MASK)
2273 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index,
2274 flags | ADDFONT_VERTICAL_FONT);
2275 ++ret;
2278 num_faces = ft_face->num_faces;
2279 pFT_Done_Face(ft_face);
2280 } while(num_faces > ++face_index);
2281 return ret;
2284 static int remove_font_resource( const char *file, DWORD flags )
2286 Family *family, *family_next;
2287 Face *face, *face_next;
2288 struct stat st;
2289 int count = 0;
2291 if (stat( file, &st ) == -1) return 0;
2292 LIST_FOR_EACH_ENTRY_SAFE( family, family_next, &font_list, Family, entry )
2294 family->refcount++;
2295 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, Face, entry )
2297 if (!face->file) continue;
2298 if (LOWORD(face->flags) != LOWORD(flags)) continue;
2299 if (st.st_dev == face->dev && st.st_ino == face->ino)
2301 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount );
2302 release_face( face );
2303 count++;
2306 release_family( family );
2308 return count;
2311 static void DumpFontList(void)
2313 Family *family;
2314 Face *face;
2316 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2317 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
2318 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2319 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
2320 if(!face->scalable)
2321 TRACE(" %d", face->size.height);
2322 TRACE("\n");
2327 static BOOL map_font_family(const WCHAR *orig, const WCHAR *repl)
2329 Family *family = find_family_from_any_name(repl);
2330 if (family != NULL)
2332 Family *new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2333 if (new_family != NULL)
2335 TRACE("mapping %s to %s\n", debugstr_w(repl), debugstr_w(orig));
2336 new_family->FamilyName = strdupW(orig);
2337 new_family->EnglishName = NULL;
2338 list_init(&new_family->faces);
2339 new_family->replacement = &family->faces;
2340 list_add_tail(&font_list, &new_family->entry);
2341 return TRUE;
2344 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(repl));
2345 return FALSE;
2348 /***********************************************************
2349 * The replacement list is a way to map an entire font
2350 * family onto another family. For example adding
2352 * [HKCU\Software\Wine\Fonts\Replacements]
2353 * "Wingdings"="Winedings"
2355 * would enumerate the Winedings font both as Winedings and
2356 * Wingdings. However if a real Wingdings font is present the
2357 * replacement does not take place.
2360 static void LoadReplaceList(void)
2362 HKEY hkey;
2363 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2364 LPWSTR value;
2365 LPVOID data;
2367 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2368 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
2370 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2371 &valuelen, &datalen, NULL, NULL);
2373 valuelen++; /* returned value doesn't include room for '\0' */
2374 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2375 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2377 dlen = datalen;
2378 vlen = valuelen;
2379 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data, &dlen) == ERROR_SUCCESS)
2381 /* "NewName"="Oldname" */
2382 if(!find_family_from_any_name(value))
2384 if (type == REG_MULTI_SZ)
2386 WCHAR *replace = data;
2387 while(*replace)
2389 if (map_font_family(value, replace))
2390 break;
2391 replace += strlenW(replace) + 1;
2394 else if (type == REG_SZ)
2395 map_font_family(value, data);
2397 else
2398 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2400 /* reset dlen and vlen */
2401 dlen = datalen;
2402 vlen = valuelen;
2404 HeapFree(GetProcessHeap(), 0, data);
2405 HeapFree(GetProcessHeap(), 0, value);
2406 RegCloseKey(hkey);
2410 static const WCHAR *font_links_list[] =
2412 Lucida_Sans_Unicode,
2413 Microsoft_Sans_Serif,
2414 Tahoma
2417 static const struct font_links_defaults_list
2419 /* Keyed off substitution for "MS Shell Dlg" */
2420 const WCHAR *shelldlg;
2421 /* Maximum of four substitutes, plus terminating NULL pointer */
2422 const WCHAR *substitutes[5];
2423 } font_links_defaults_list[] =
2425 /* Non East-Asian */
2426 { Tahoma, /* FIXME unverified ordering */
2427 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2429 /* Below lists are courtesy of
2430 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2432 /* Japanese */
2433 { MS_UI_Gothic,
2434 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2436 /* Chinese Simplified */
2437 { SimSun,
2438 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2440 /* Korean */
2441 { Gulim,
2442 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2444 /* Chinese Traditional */
2445 { PMingLiU,
2446 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2451 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2453 SYSTEM_LINKS *font_link;
2455 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2457 if(!strcmpiW(font_link->font_name, name))
2458 return font_link;
2461 return NULL;
2464 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2466 const WCHAR *value;
2467 int i;
2468 FontSubst *psub;
2469 Family *family;
2470 Face *face;
2471 const WCHAR *file;
2473 if (values)
2475 SYSTEM_LINKS *font_link;
2477 psub = get_font_subst(&font_subst_list, name, -1);
2478 /* Don't store fonts that are only substitutes for other fonts */
2479 if(psub)
2481 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2482 return;
2485 font_link = find_font_link(name);
2486 if (font_link == NULL)
2488 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2489 font_link->font_name = strdupW(name);
2490 list_init(&font_link->links);
2491 list_add_tail(&system_links, &font_link->entry);
2494 memset(&font_link->fs, 0, sizeof font_link->fs);
2495 for (i = 0; values[i] != NULL; i++)
2497 const struct list *face_list;
2498 CHILD_FONT *child_font;
2500 value = values[i];
2501 if (!strcmpiW(name,value))
2502 continue;
2503 psub = get_font_subst(&font_subst_list, value, -1);
2504 if(psub)
2505 value = psub->to.name;
2506 family = find_family_from_name(value);
2507 if (!family)
2508 continue;
2509 file = NULL;
2510 /* Use first extant filename for this Family */
2511 face_list = get_face_list_from_family(family);
2512 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2514 if (!face->file)
2515 continue;
2516 file = strrchrW(face->file, '/');
2517 if (!file)
2518 file = face->file;
2519 else
2520 file++;
2521 break;
2523 if (!file)
2524 continue;
2525 face = find_face_from_filename(file, value);
2526 if(!face)
2528 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2529 continue;
2532 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2533 child_font->face = face;
2534 child_font->font = NULL;
2535 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2536 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2537 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2538 child_font->face->face_index);
2539 list_add_tail(&font_link->links, &child_font->entry);
2541 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2547 /*************************************************************
2548 * init_system_links
2550 static BOOL init_system_links(void)
2552 HKEY hkey;
2553 BOOL ret = FALSE;
2554 DWORD type, max_val, max_data, val_len, data_len, index;
2555 WCHAR *value, *data;
2556 WCHAR *entry, *next;
2557 SYSTEM_LINKS *font_link, *system_font_link;
2558 CHILD_FONT *child_font;
2559 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2560 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2561 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2562 Face *face;
2563 FontSubst *psub;
2564 UINT i, j;
2566 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2568 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2569 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2570 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2571 val_len = max_val + 1;
2572 data_len = max_data;
2573 index = 0;
2574 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2576 psub = get_font_subst(&font_subst_list, value, -1);
2577 /* Don't store fonts that are only substitutes for other fonts */
2578 if(psub)
2580 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2581 goto next;
2583 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2584 font_link->font_name = strdupW(value);
2585 memset(&font_link->fs, 0, sizeof font_link->fs);
2586 list_init(&font_link->links);
2587 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2589 WCHAR *face_name;
2590 CHILD_FONT *child_font;
2592 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2594 next = entry + strlenW(entry) + 1;
2596 face_name = strchrW(entry, ',');
2597 if(face_name)
2599 *face_name++ = 0;
2600 while(isspaceW(*face_name))
2601 face_name++;
2603 psub = get_font_subst(&font_subst_list, face_name, -1);
2604 if(psub)
2605 face_name = psub->to.name;
2607 face = find_face_from_filename(entry, face_name);
2608 if(!face)
2610 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2611 continue;
2614 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2615 child_font->face = face;
2616 child_font->font = NULL;
2617 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2618 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2619 TRACE("Adding file %s index %ld\n",
2620 debugstr_w(child_font->face->file), child_font->face->face_index);
2621 list_add_tail(&font_link->links, &child_font->entry);
2623 list_add_tail(&system_links, &font_link->entry);
2624 next:
2625 val_len = max_val + 1;
2626 data_len = max_data;
2629 HeapFree(GetProcessHeap(), 0, value);
2630 HeapFree(GetProcessHeap(), 0, data);
2631 RegCloseKey(hkey);
2635 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2636 if (!psub) {
2637 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2638 goto skip_internal;
2641 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2643 const FontSubst *psub2;
2644 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2646 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2648 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2649 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2651 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2652 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2654 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2656 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2660 skip_internal:
2662 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2663 that Tahoma has */
2665 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2666 system_font_link->font_name = strdupW(System);
2667 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2668 list_init(&system_font_link->links);
2670 face = find_face_from_filename(tahoma_ttf, Tahoma);
2671 if(face)
2673 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2674 child_font->face = face;
2675 child_font->font = NULL;
2676 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2677 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2678 TRACE("Found Tahoma in %s index %ld\n",
2679 debugstr_w(child_font->face->file), child_font->face->face_index);
2680 list_add_tail(&system_font_link->links, &child_font->entry);
2682 font_link = find_font_link(Tahoma);
2683 if (font_link != NULL)
2685 CHILD_FONT *font_link_entry;
2686 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2688 CHILD_FONT *new_child;
2689 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2690 new_child->face = font_link_entry->face;
2691 new_child->font = NULL;
2692 new_child->face->refcount++;
2693 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2694 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2695 list_add_tail(&system_font_link->links, &new_child->entry);
2698 list_add_tail(&system_links, &system_font_link->entry);
2699 return ret;
2702 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2704 DIR *dir;
2705 struct dirent *dent;
2706 char path[MAX_PATH];
2708 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2710 dir = opendir(dirname);
2711 if(!dir) {
2712 WARN("Can't open directory %s\n", debugstr_a(dirname));
2713 return FALSE;
2715 while((dent = readdir(dir)) != NULL) {
2716 struct stat statbuf;
2718 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2719 continue;
2721 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2723 sprintf(path, "%s/%s", dirname, dent->d_name);
2725 if(stat(path, &statbuf) == -1)
2727 WARN("Can't stat %s\n", debugstr_a(path));
2728 continue;
2730 if(S_ISDIR(statbuf.st_mode))
2731 ReadFontDir(path, external_fonts);
2732 else
2734 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2735 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2736 AddFontToList(path, NULL, 0, addfont_flags);
2739 closedir(dir);
2740 return TRUE;
2743 #ifdef SONAME_LIBFONTCONFIG
2745 static BOOL fontconfig_enabled;
2747 static UINT parse_aa_pattern( FcPattern *pattern )
2749 FcBool antialias;
2750 int rgba;
2751 UINT aa_flags = 0;
2753 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2754 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2756 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2758 switch (rgba)
2760 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2761 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2762 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2763 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2764 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2767 return aa_flags;
2770 static void init_fontconfig(void)
2772 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2774 if (!fc_handle)
2776 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2777 return;
2780 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2781 LOAD_FUNCPTR(FcConfigSubstitute);
2782 LOAD_FUNCPTR(FcFontList);
2783 LOAD_FUNCPTR(FcFontSetDestroy);
2784 LOAD_FUNCPTR(FcInit);
2785 LOAD_FUNCPTR(FcObjectSetAdd);
2786 LOAD_FUNCPTR(FcObjectSetCreate);
2787 LOAD_FUNCPTR(FcObjectSetDestroy);
2788 LOAD_FUNCPTR(FcPatternCreate);
2789 LOAD_FUNCPTR(FcPatternDestroy);
2790 LOAD_FUNCPTR(FcPatternGetBool);
2791 LOAD_FUNCPTR(FcPatternGetInteger);
2792 LOAD_FUNCPTR(FcPatternGetString);
2793 #undef LOAD_FUNCPTR
2795 if (pFcInit())
2797 FcPattern *pattern = pFcPatternCreate();
2798 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2799 default_aa_flags = parse_aa_pattern( pattern );
2800 pFcPatternDestroy( pattern );
2801 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2802 fontconfig_enabled = TRUE;
2806 static void load_fontconfig_fonts(void)
2808 FcPattern *pat;
2809 FcObjectSet *os;
2810 FcFontSet *fontset;
2811 int i, len;
2812 char *file;
2813 const char *ext;
2815 if (!fontconfig_enabled) return;
2817 pat = pFcPatternCreate();
2818 os = pFcObjectSetCreate();
2819 pFcObjectSetAdd(os, FC_FILE);
2820 pFcObjectSetAdd(os, FC_SCALABLE);
2821 pFcObjectSetAdd(os, FC_ANTIALIAS);
2822 pFcObjectSetAdd(os, FC_RGBA);
2823 fontset = pFcFontList(NULL, pat, os);
2824 if(!fontset) return;
2825 for(i = 0; i < fontset->nfont; i++) {
2826 FcBool scalable;
2827 DWORD aa_flags;
2829 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2830 continue;
2832 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2834 /* We're just interested in OT/TT fonts for now, so this hack just
2835 picks up the scalable fonts without extensions .pf[ab] to save time
2836 loading every other font */
2838 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2840 TRACE("not scalable\n");
2841 continue;
2844 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2845 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2847 len = strlen( file );
2848 if(len < 4) continue;
2849 ext = &file[ len - 3 ];
2850 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2851 AddFontToList(file, NULL, 0,
2852 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2854 pFcFontSetDestroy(fontset);
2855 pFcObjectSetDestroy(os);
2856 pFcPatternDestroy(pat);
2859 #elif defined(HAVE_CARBON_CARBON_H)
2861 static void load_mac_font_callback(const void *value, void *context)
2863 CFStringRef pathStr = value;
2864 CFIndex len;
2865 char* path;
2867 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2868 path = HeapAlloc(GetProcessHeap(), 0, len);
2869 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2871 TRACE("font file %s\n", path);
2872 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2874 HeapFree(GetProcessHeap(), 0, path);
2877 static void load_mac_fonts(void)
2879 CFStringRef removeDupesKey;
2880 CFBooleanRef removeDupesValue;
2881 CFDictionaryRef options;
2882 CTFontCollectionRef col;
2883 CFArrayRef descs;
2884 CFMutableSetRef paths;
2885 CFIndex i;
2887 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2888 removeDupesValue = kCFBooleanTrue;
2889 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2890 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2891 col = CTFontCollectionCreateFromAvailableFonts(options);
2892 if (options) CFRelease(options);
2893 if (!col)
2895 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2896 return;
2899 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2900 CFRelease(col);
2901 if (!descs)
2903 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2904 return;
2907 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2908 if (!paths)
2910 WARN("CFSetCreateMutable failed\n");
2911 CFRelease(descs);
2912 return;
2915 for (i = 0; i < CFArrayGetCount(descs); i++)
2917 CTFontDescriptorRef desc;
2918 CTFontRef font;
2919 ATSFontRef atsFont;
2920 OSStatus status;
2921 FSRef fsref;
2922 CFURLRef url;
2923 CFStringRef ext;
2924 CFStringRef path;
2926 desc = CFArrayGetValueAtIndex(descs, i);
2928 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2929 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2930 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2931 if (!font) continue;
2933 atsFont = CTFontGetPlatformFont(font, NULL);
2934 if (!atsFont)
2936 CFRelease(font);
2937 continue;
2940 status = ATSFontGetFileReference(atsFont, &fsref);
2941 CFRelease(font);
2942 if (status != noErr) continue;
2944 url = CFURLCreateFromFSRef(NULL, &fsref);
2945 if (!url) continue;
2947 ext = CFURLCopyPathExtension(url);
2948 if (ext)
2950 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2951 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2952 CFRelease(ext);
2953 if (skip)
2955 CFRelease(url);
2956 continue;
2960 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2961 CFRelease(url);
2962 if (!path) continue;
2964 CFSetAddValue(paths, path);
2965 CFRelease(path);
2968 CFRelease(descs);
2970 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2971 CFRelease(paths);
2974 #endif
2976 static char *get_font_dir(void)
2978 const char *build_dir, *data_dir;
2979 char *name = NULL;
2981 if ((data_dir = wine_get_data_dir()))
2983 if (!(name = HeapAlloc( GetProcessHeap(), 0, strlen(data_dir) + 1 + sizeof(WINE_FONT_DIR) )))
2984 return NULL;
2985 strcpy( name, data_dir );
2986 strcat( name, "/" );
2987 strcat( name, WINE_FONT_DIR );
2989 else if ((build_dir = wine_get_build_dir()))
2991 if (!(name = HeapAlloc( GetProcessHeap(), 0, strlen(build_dir) + sizeof("/fonts") )))
2992 return NULL;
2993 strcpy( name, build_dir );
2994 strcat( name, "/fonts" );
2996 return name;
2999 static char *get_data_dir_path( LPCWSTR file )
3001 char *unix_name = NULL;
3002 char *font_dir = get_font_dir();
3004 if (font_dir)
3006 INT len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
3008 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(font_dir) + len + 1 );
3009 strcpy(unix_name, font_dir);
3010 strcat(unix_name, "/");
3012 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
3013 HeapFree( GetProcessHeap(), 0, font_dir );
3015 return unix_name;
3018 static BOOL load_font_from_data_dir(LPCWSTR file)
3020 BOOL ret = FALSE;
3021 char *unix_name = get_data_dir_path( file );
3023 if (unix_name)
3025 EnterCriticalSection( &freetype_cs );
3026 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3027 LeaveCriticalSection( &freetype_cs );
3028 HeapFree(GetProcessHeap(), 0, unix_name);
3030 return ret;
3033 static char *get_winfonts_dir_path(LPCWSTR file)
3035 static const WCHAR slashW[] = {'\\','\0'};
3036 WCHAR windowsdir[MAX_PATH];
3038 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3039 strcatW(windowsdir, fontsW);
3040 strcatW(windowsdir, slashW);
3041 strcatW(windowsdir, file);
3042 return wine_get_unix_file_name( windowsdir );
3045 static void load_system_fonts(void)
3047 HKEY hkey;
3048 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
3049 const WCHAR * const *value;
3050 DWORD dlen, type;
3051 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3052 char *unixname;
3054 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
3055 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3056 strcatW(windowsdir, fontsW);
3057 for(value = SystemFontValues; *value; value++) {
3058 dlen = sizeof(data);
3059 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
3060 type == REG_SZ) {
3061 BOOL added = FALSE;
3063 sprintfW(pathW, fmtW, windowsdir, data);
3064 if((unixname = wine_get_unix_file_name(pathW))) {
3065 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3066 HeapFree(GetProcessHeap(), 0, unixname);
3068 if (!added)
3069 load_font_from_data_dir(data);
3072 RegCloseKey(hkey);
3076 /*************************************************************
3078 * This adds registry entries for any externally loaded fonts
3079 * (fonts from fontconfig or FontDirs). It also deletes entries
3080 * of no longer existing fonts.
3083 static void update_reg_entries(void)
3085 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
3086 LPWSTR valueW;
3087 DWORD len;
3088 Family *family;
3089 Face *face;
3090 WCHAR *file, *path;
3091 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
3093 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
3094 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
3095 ERR("Can't create Windows font reg key\n");
3096 goto end;
3099 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
3100 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
3101 ERR("Can't create Windows font reg key\n");
3102 goto end;
3105 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
3106 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
3107 ERR("Can't create external font reg key\n");
3108 goto end;
3111 /* enumerate the fonts and add external ones to the two keys */
3113 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
3114 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
3115 char *buffer;
3116 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
3118 if(face->FullName)
3120 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
3121 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3122 strcpyW(valueW, face->FullName);
3124 else
3126 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
3127 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3128 strcpyW(valueW, family->FamilyName);
3131 buffer = strWtoA( CP_UNIXCP, face->file );
3132 path = wine_get_dos_file_name( buffer );
3133 HeapFree( GetProcessHeap(), 0, buffer );
3135 if (path)
3136 file = path;
3137 else if ((file = strrchrW(face->file, '/')))
3138 file++;
3139 else
3140 file = face->file;
3142 len = strlenW(file) + 1;
3143 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3144 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3145 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3147 HeapFree(GetProcessHeap(), 0, path);
3148 HeapFree(GetProcessHeap(), 0, valueW);
3151 end:
3152 if(external_key) RegCloseKey(external_key);
3153 if(win9x_key) RegCloseKey(win9x_key);
3154 if(winnt_key) RegCloseKey(winnt_key);
3157 static void delete_external_font_keys(void)
3159 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
3160 DWORD dlen, vlen, datalen, valuelen, i, type;
3161 LPWSTR valueW;
3162 LPVOID data;
3164 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
3165 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
3166 ERR("Can't create Windows font reg key\n");
3167 goto end;
3170 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
3171 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
3172 ERR("Can't create Windows font reg key\n");
3173 goto end;
3176 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
3177 ERR("Can't create external font reg key\n");
3178 goto end;
3181 /* Delete all external fonts added last time */
3183 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3184 &valuelen, &datalen, NULL, NULL);
3185 valuelen++; /* returned value doesn't include room for '\0' */
3186 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3187 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3189 dlen = datalen * sizeof(WCHAR);
3190 vlen = valuelen;
3191 i = 0;
3192 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
3193 &dlen) == ERROR_SUCCESS) {
3195 RegDeleteValueW(winnt_key, valueW);
3196 RegDeleteValueW(win9x_key, valueW);
3197 /* reset dlen and vlen */
3198 dlen = datalen;
3199 vlen = valuelen;
3201 HeapFree(GetProcessHeap(), 0, data);
3202 HeapFree(GetProcessHeap(), 0, valueW);
3204 /* Delete the old external fonts key */
3205 RegCloseKey(external_key);
3206 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
3208 end:
3209 if(win9x_key) RegCloseKey(win9x_key);
3210 if(winnt_key) RegCloseKey(winnt_key);
3213 /*************************************************************
3214 * WineEngAddFontResourceEx
3217 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3219 INT ret = 0;
3221 GDI_CheckNotLock();
3223 if (ft_handle) /* do it only if we have freetype up and running */
3225 char *unixname;
3227 EnterCriticalSection( &freetype_cs );
3229 if((unixname = wine_get_unix_file_name(file)))
3231 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3233 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3234 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
3235 HeapFree(GetProcessHeap(), 0, unixname);
3237 if (!ret && !strchrW(file, '\\')) {
3238 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
3239 if ((unixname = get_winfonts_dir_path( file )))
3241 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3242 HeapFree(GetProcessHeap(), 0, unixname);
3244 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
3245 if (!ret && (unixname = get_data_dir_path( file )))
3247 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3248 HeapFree(GetProcessHeap(), 0, unixname);
3252 LeaveCriticalSection( &freetype_cs );
3254 return ret;
3257 /*************************************************************
3258 * WineEngAddFontMemResourceEx
3261 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3263 GDI_CheckNotLock();
3265 if (ft_handle) /* do it only if we have freetype up and running */
3267 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
3269 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
3270 memcpy(pFontCopy, pbFont, cbFont);
3272 EnterCriticalSection( &freetype_cs );
3273 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3274 LeaveCriticalSection( &freetype_cs );
3276 if (*pcFonts == 0)
3278 TRACE("AddFontToList failed\n");
3279 HeapFree(GetProcessHeap(), 0, pFontCopy);
3280 return 0;
3282 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
3283 * For now return something unique but quite random
3285 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
3286 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
3289 *pcFonts = 0;
3290 return 0;
3293 /*************************************************************
3294 * WineEngRemoveFontResourceEx
3297 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3299 INT ret = 0;
3301 GDI_CheckNotLock();
3303 if (ft_handle) /* do it only if we have freetype up and running */
3305 char *unixname;
3307 EnterCriticalSection( &freetype_cs );
3309 if ((unixname = wine_get_unix_file_name(file)))
3311 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3313 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3314 ret = remove_font_resource( unixname, addfont_flags );
3315 HeapFree(GetProcessHeap(), 0, unixname);
3317 if (!ret && !strchrW(file, '\\'))
3319 if ((unixname = get_winfonts_dir_path( file )))
3321 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3322 HeapFree(GetProcessHeap(), 0, unixname);
3324 if (!ret && (unixname = get_data_dir_path( file )))
3326 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3327 HeapFree(GetProcessHeap(), 0, unixname);
3331 LeaveCriticalSection( &freetype_cs );
3333 return ret;
3336 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
3338 WCHAR *fullname;
3339 char *unix_name;
3340 int file_len;
3342 if (!font_file) return NULL;
3344 file_len = strlenW( font_file );
3346 if (font_path && font_path[0])
3348 int path_len = strlenW( font_path );
3349 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
3350 if (!fullname) return NULL;
3351 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
3352 fullname[path_len] = '\\';
3353 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
3355 else
3357 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
3358 if (!len) return NULL;
3359 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3360 if (!fullname) return NULL;
3361 GetFullPathNameW( font_file, len, fullname, NULL );
3364 unix_name = wine_get_unix_file_name( fullname );
3365 HeapFree( GetProcessHeap(), 0, fullname );
3366 return unix_name;
3369 #include <pshpack1.h>
3370 struct fontdir
3372 WORD num_of_resources;
3373 WORD res_id;
3374 WORD dfVersion;
3375 DWORD dfSize;
3376 CHAR dfCopyright[60];
3377 WORD dfType;
3378 WORD dfPoints;
3379 WORD dfVertRes;
3380 WORD dfHorizRes;
3381 WORD dfAscent;
3382 WORD dfInternalLeading;
3383 WORD dfExternalLeading;
3384 BYTE dfItalic;
3385 BYTE dfUnderline;
3386 BYTE dfStrikeOut;
3387 WORD dfWeight;
3388 BYTE dfCharSet;
3389 WORD dfPixWidth;
3390 WORD dfPixHeight;
3391 BYTE dfPitchAndFamily;
3392 WORD dfAvgWidth;
3393 WORD dfMaxWidth;
3394 BYTE dfFirstChar;
3395 BYTE dfLastChar;
3396 BYTE dfDefaultChar;
3397 BYTE dfBreakChar;
3398 WORD dfWidthBytes;
3399 DWORD dfDevice;
3400 DWORD dfFace;
3401 DWORD dfReserved;
3402 CHAR szFaceName[LF_FACESIZE];
3405 #include <poppack.h>
3407 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
3408 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
3410 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
3412 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3413 Face *face;
3414 WCHAR *name, *english_name;
3415 ENUMLOGFONTEXW elf;
3416 NEWTEXTMETRICEXW ntm;
3417 DWORD type;
3419 if (!ft_face) return FALSE;
3420 face = create_face( ft_face, 0, unix_name, NULL, 0, 0 );
3421 get_family_names( ft_face, &name, &english_name, FALSE );
3422 pFT_Done_Face( ft_face );
3424 GetEnumStructs( face, name, &elf, &ntm, &type );
3425 release_face( face );
3426 HeapFree( GetProcessHeap(), 0, name );
3427 HeapFree( GetProcessHeap(), 0, english_name );
3429 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3431 memset( fd, 0, sizeof(*fd) );
3433 fd->num_of_resources = 1;
3434 fd->res_id = 0;
3435 fd->dfVersion = 0x200;
3436 fd->dfSize = sizeof(*fd);
3437 strcpy( fd->dfCopyright, "Wine fontdir" );
3438 fd->dfType = 0x4003; /* 0x0080 set if private */
3439 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3440 fd->dfVertRes = 72;
3441 fd->dfHorizRes = 72;
3442 fd->dfAscent = ntm.ntmTm.tmAscent;
3443 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3444 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3445 fd->dfItalic = ntm.ntmTm.tmItalic;
3446 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3447 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3448 fd->dfWeight = ntm.ntmTm.tmWeight;
3449 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3450 fd->dfPixWidth = 0;
3451 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3452 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3453 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3454 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3455 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3456 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3457 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3458 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3459 fd->dfWidthBytes = 0;
3460 fd->dfDevice = 0;
3461 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3462 fd->dfReserved = 0;
3463 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3465 return TRUE;
3468 #define NE_FFLAGS_LIBMODULE 0x8000
3469 #define NE_OSFLAGS_WINDOWS 0x02
3471 static const char dos_string[0x40] = "This is a TrueType resource file";
3472 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3474 #include <pshpack2.h>
3476 struct ne_typeinfo
3478 WORD type_id;
3479 WORD count;
3480 DWORD res;
3483 struct ne_nameinfo
3485 WORD off;
3486 WORD len;
3487 WORD flags;
3488 WORD id;
3489 DWORD res;
3492 struct rsrc_tab
3494 WORD align;
3495 struct ne_typeinfo fontdir_type;
3496 struct ne_nameinfo fontdir_name;
3497 struct ne_typeinfo scalable_type;
3498 struct ne_nameinfo scalable_name;
3499 WORD end_of_rsrc;
3500 BYTE fontdir_res_name[8];
3503 #include <poppack.h>
3505 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3507 BOOL ret = FALSE;
3508 HANDLE file;
3509 DWORD size, written;
3510 BYTE *ptr, *start;
3511 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3512 char *font_fileA, *last_part, *ext;
3513 IMAGE_DOS_HEADER dos;
3514 IMAGE_OS2_HEADER ne =
3516 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3517 0, 0, 0, 0, 0, 0,
3518 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3519 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3521 struct rsrc_tab rsrc_tab =
3524 { 0x8007, 1, 0 },
3525 { 0, 0, 0x0c50, 0x2c, 0 },
3526 { 0x80cc, 1, 0 },
3527 { 0, 0, 0x0c50, 0x8001, 0 },
3529 { 7,'F','O','N','T','D','I','R'}
3532 memset( &dos, 0, sizeof(dos) );
3533 dos.e_magic = IMAGE_DOS_SIGNATURE;
3534 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3536 /* import name is last part\0, resident name is last part without extension
3537 non-resident name is "FONTRES:" + lfFaceName */
3539 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3540 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3541 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3543 last_part = strrchr( font_fileA, '\\' );
3544 if (last_part) last_part++;
3545 else last_part = font_fileA;
3546 import_name_len = strlen( last_part ) + 1;
3548 ext = strchr( last_part, '.' );
3549 if (ext) res_name_len = ext - last_part;
3550 else res_name_len = import_name_len - 1;
3552 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3554 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3555 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3556 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3557 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3558 ne.ne_cbenttab = 2;
3559 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3561 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3562 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3563 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3564 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3566 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3567 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3569 if (!ptr)
3571 HeapFree( GetProcessHeap(), 0, font_fileA );
3572 return FALSE;
3575 memcpy( ptr, &dos, sizeof(dos) );
3576 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3577 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3579 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3580 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3582 ptr = start + dos.e_lfanew + ne.ne_restab;
3583 *ptr++ = res_name_len;
3584 memcpy( ptr, last_part, res_name_len );
3586 ptr = start + dos.e_lfanew + ne.ne_imptab;
3587 *ptr++ = import_name_len;
3588 memcpy( ptr, last_part, import_name_len );
3590 ptr = start + ne.ne_nrestab;
3591 *ptr++ = non_res_name_len;
3592 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3593 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3595 ptr = start + (rsrc_tab.scalable_name.off << 4);
3596 memcpy( ptr, font_fileA, font_file_len );
3598 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3599 memcpy( ptr, fontdir, fontdir->dfSize );
3601 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3602 if (file != INVALID_HANDLE_VALUE)
3604 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3605 ret = TRUE;
3606 CloseHandle( file );
3609 HeapFree( GetProcessHeap(), 0, start );
3610 HeapFree( GetProcessHeap(), 0, font_fileA );
3612 return ret;
3615 /*************************************************************
3616 * WineEngCreateScalableFontResource
3619 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3620 LPCWSTR font_file, LPCWSTR font_path )
3622 char *unix_name = get_ttf_file_name( font_file, font_path );
3623 struct fontdir fontdir;
3624 BOOL ret = FALSE;
3626 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3627 SetLastError( ERROR_INVALID_PARAMETER );
3628 else
3630 if (hidden) fontdir.dfType |= 0x80;
3631 ret = create_fot( resource, font_file, &fontdir );
3634 HeapFree( GetProcessHeap(), 0, unix_name );
3635 return ret;
3638 static const struct nls_update_font_list
3640 UINT ansi_cp, oem_cp;
3641 const char *oem, *fixed, *system;
3642 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3643 /* these are for font substitutes */
3644 const char *shelldlg, *tmsrmn;
3645 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3646 *helv_0, *tmsrmn_0;
3647 const struct subst
3649 const char *from, *to;
3650 } arial_0, courier_new_0, times_new_roman_0;
3651 } nls_update_font_list[] =
3653 /* Latin 1 (United States) */
3654 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3655 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3656 "Tahoma","Times New Roman",
3657 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3658 { 0 }, { 0 }, { 0 }
3660 /* Latin 1 (Multilingual) */
3661 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3662 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3663 "Tahoma","Times New Roman", /* FIXME unverified */
3664 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3665 { 0 }, { 0 }, { 0 }
3667 /* Eastern Europe */
3668 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3669 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3670 "Tahoma","Times New Roman", /* FIXME unverified */
3671 "Fixedsys,238", "System,238",
3672 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3673 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3674 { "Arial CE,0", "Arial,238" },
3675 { "Courier New CE,0", "Courier New,238" },
3676 { "Times New Roman CE,0", "Times New Roman,238" }
3678 /* Cyrillic */
3679 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3680 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3681 "Tahoma","Times New Roman", /* FIXME unverified */
3682 "Fixedsys,204", "System,204",
3683 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3684 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3685 { "Arial Cyr,0", "Arial,204" },
3686 { "Courier New Cyr,0", "Courier New,204" },
3687 { "Times New Roman Cyr,0", "Times New Roman,204" }
3689 /* Greek */
3690 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3691 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3692 "Tahoma","Times New Roman", /* FIXME unverified */
3693 "Fixedsys,161", "System,161",
3694 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3695 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3696 { "Arial Greek,0", "Arial,161" },
3697 { "Courier New Greek,0", "Courier New,161" },
3698 { "Times New Roman Greek,0", "Times New Roman,161" }
3700 /* Turkish */
3701 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3702 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3703 "Tahoma","Times New Roman", /* FIXME unverified */
3704 "Fixedsys,162", "System,162",
3705 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3706 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3707 { "Arial Tur,0", "Arial,162" },
3708 { "Courier New Tur,0", "Courier New,162" },
3709 { "Times New Roman Tur,0", "Times New Roman,162" }
3711 /* Hebrew */
3712 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3713 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3714 "Tahoma","Times New Roman", /* FIXME unverified */
3715 "Fixedsys,177", "System,177",
3716 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3717 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3718 { 0 }, { 0 }, { 0 }
3720 /* Arabic */
3721 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3722 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3723 "Microsoft Sans Serif","Times New Roman",
3724 "Fixedsys,178", "System,178",
3725 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3726 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3727 { 0 }, { 0 }, { 0 }
3729 /* Baltic */
3730 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3731 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3732 "Tahoma","Times New Roman", /* FIXME unverified */
3733 "Fixedsys,186", "System,186",
3734 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3735 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3736 { "Arial Baltic,0", "Arial,186" },
3737 { "Courier New Baltic,0", "Courier New,186" },
3738 { "Times New Roman Baltic,0", "Times New Roman,186" }
3740 /* Vietnamese */
3741 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3742 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3743 "Tahoma","Times New Roman", /* FIXME unverified */
3744 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3745 { 0 }, { 0 }, { 0 }
3747 /* Thai */
3748 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3749 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3750 "Tahoma","Times New Roman", /* FIXME unverified */
3751 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3752 { 0 }, { 0 }, { 0 }
3754 /* Japanese */
3755 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3756 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3757 "MS UI Gothic","MS Serif",
3758 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3759 { 0 }, { 0 }, { 0 }
3761 /* Chinese Simplified */
3762 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3763 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3764 "SimSun", "NSimSun",
3765 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3766 { 0 }, { 0 }, { 0 }
3768 /* Korean */
3769 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3770 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3771 "Gulim", "Batang",
3772 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3773 { 0 }, { 0 }, { 0 }
3775 /* Chinese Traditional */
3776 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3777 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3778 "PMingLiU", "MingLiU",
3779 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3780 { 0 }, { 0 }, { 0 }
3784 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3786 return ( ansi_cp == 932 /* CP932 for Japanese */
3787 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3788 || ansi_cp == 949 /* CP949 for Korean */
3789 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3792 static inline HKEY create_fonts_NT_registry_key(void)
3794 HKEY hkey = 0;
3796 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3797 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3798 return hkey;
3801 static inline HKEY create_fonts_9x_registry_key(void)
3803 HKEY hkey = 0;
3805 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3806 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3807 return hkey;
3810 static inline HKEY create_config_fonts_registry_key(void)
3812 HKEY hkey = 0;
3814 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3815 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3816 return hkey;
3819 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3821 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3823 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3824 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3825 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3826 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3829 static void set_value_key(HKEY hkey, const char *name, const char *value)
3831 if (value)
3832 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3833 else if (name)
3834 RegDeleteValueA(hkey, name);
3837 static void update_font_association_info(UINT current_ansi_codepage)
3839 static const char *font_assoc_reg_key = "System\\CurrentControlSet\\Control\\FontAssoc";
3840 static const char *assoc_charset_subkey = "Associated Charset";
3842 if (is_dbcs_ansi_cp(current_ansi_codepage))
3844 HKEY hkey;
3845 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, font_assoc_reg_key, &hkey) == ERROR_SUCCESS)
3847 HKEY hsubkey;
3848 if (RegCreateKeyA(hkey, assoc_charset_subkey, &hsubkey) == ERROR_SUCCESS)
3850 switch (current_ansi_codepage)
3852 case 932:
3853 set_value_key(hsubkey, "ANSI(00)", "NO");
3854 set_value_key(hsubkey, "OEM(FF)", "NO");
3855 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3856 break;
3857 case 936:
3858 case 949:
3859 case 950:
3860 set_value_key(hsubkey, "ANSI(00)", "YES");
3861 set_value_key(hsubkey, "OEM(FF)", "YES");
3862 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3863 break;
3865 RegCloseKey(hsubkey);
3868 /* TODO: Associated DefaultFonts */
3870 RegCloseKey(hkey);
3873 else
3874 RegDeleteTreeA(HKEY_LOCAL_MACHINE, font_assoc_reg_key);
3877 static void set_multi_value_key(HKEY hkey, const WCHAR *name, const WCHAR *value, DWORD len)
3879 if (value)
3880 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (const BYTE *)value, len);
3881 else if (name)
3882 RegDeleteValueW(hkey, name);
3885 static void update_font_system_link_info(UINT current_ansi_codepage)
3887 static const WCHAR system_link_simplified_chinese[] =
3888 {'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3889 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3890 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3891 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3892 '\0'};
3893 static const WCHAR system_link_traditional_chinese[] =
3894 {'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3895 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3896 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3897 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3898 '\0'};
3899 static const WCHAR system_link_japanese[] =
3900 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3901 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3902 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3903 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3904 '\0'};
3905 static const WCHAR system_link_korean[] =
3906 {'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3907 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3908 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3909 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3910 '\0'};
3911 static const WCHAR system_link_non_cjk[] =
3912 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3913 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3914 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3915 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3916 '\0'};
3917 HKEY hkey;
3919 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
3921 const WCHAR *link;
3922 DWORD len;
3924 switch (current_ansi_codepage)
3926 case 932:
3927 link = system_link_japanese;
3928 len = sizeof(system_link_japanese);
3929 break;
3930 case 936:
3931 link = system_link_simplified_chinese;
3932 len = sizeof(system_link_simplified_chinese);
3933 break;
3934 case 949:
3935 link = system_link_korean;
3936 len = sizeof(system_link_korean);
3937 break;
3938 case 950:
3939 link = system_link_traditional_chinese;
3940 len = sizeof(system_link_traditional_chinese);
3941 break;
3942 default:
3943 link = system_link_non_cjk;
3944 len = sizeof(system_link_non_cjk);
3946 set_multi_value_key(hkey, Lucida_Sans_Unicode, link, len);
3947 set_multi_value_key(hkey, Microsoft_Sans_Serif, link, len);
3948 set_multi_value_key(hkey, Tahoma, link, len);
3949 RegCloseKey(hkey);
3953 static void update_font_info(void)
3955 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3956 char buf[40], cpbuf[40];
3957 DWORD len, type;
3958 HKEY hkey = 0;
3959 UINT i, ansi_cp = 0, oem_cp = 0;
3960 DWORD screen_dpi = 96, font_dpi = 0;
3961 BOOL done = FALSE;
3963 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3964 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3965 &hkey) == ERROR_SUCCESS)
3967 reg_load_dword(hkey, logpixels, &screen_dpi);
3968 RegCloseKey(hkey);
3971 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3972 return;
3974 reg_load_dword(hkey, logpixels, &font_dpi);
3976 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3977 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3978 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3979 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3980 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3982 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3983 if (is_dbcs_ansi_cp(ansi_cp))
3984 use_default_fallback = TRUE;
3986 buf[0] = 0;
3987 len = sizeof(buf);
3988 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3990 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3992 RegCloseKey(hkey);
3993 return;
3995 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3996 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3998 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3999 ansi_cp, oem_cp, screen_dpi);
4001 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
4002 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
4003 RegCloseKey(hkey);
4005 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
4007 HKEY hkey;
4009 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
4010 nls_update_font_list[i].oem_cp == oem_cp)
4012 hkey = create_config_fonts_registry_key();
4013 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
4014 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
4015 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
4016 RegCloseKey(hkey);
4018 hkey = create_fonts_NT_registry_key();
4019 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
4020 RegCloseKey(hkey);
4022 hkey = create_fonts_9x_registry_key();
4023 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
4024 RegCloseKey(hkey);
4026 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
4028 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
4029 strlen(nls_update_font_list[i].shelldlg)+1);
4030 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
4031 strlen(nls_update_font_list[i].tmsrmn)+1);
4033 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
4034 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
4035 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
4036 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
4037 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
4038 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
4039 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
4040 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
4042 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
4043 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
4044 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
4046 RegCloseKey(hkey);
4048 done = TRUE;
4050 else
4052 /* Delete the FontSubstitutes from other locales */
4053 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
4055 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
4056 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
4057 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
4058 RegCloseKey(hkey);
4062 if (!done)
4063 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
4065 /* update locale dependent font association info and font system link info in registry.
4066 update only when codepages changed, not logpixels. */
4067 if (strcmp(buf, cpbuf) != 0)
4069 update_font_association_info(ansi_cp);
4070 update_font_system_link_info(ansi_cp);
4074 static BOOL init_freetype(void)
4076 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
4077 if(!ft_handle) {
4078 WINE_MESSAGE(
4079 "Wine cannot find the FreeType font library. To enable Wine to\n"
4080 "use TrueType fonts please install a version of FreeType greater than\n"
4081 "or equal to 2.0.5.\n"
4082 "http://www.freetype.org\n");
4083 return FALSE;
4086 #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;}
4088 LOAD_FUNCPTR(FT_Done_Face)
4089 LOAD_FUNCPTR(FT_Get_Char_Index)
4090 LOAD_FUNCPTR(FT_Get_First_Char)
4091 LOAD_FUNCPTR(FT_Get_Next_Char)
4092 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
4093 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
4094 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
4095 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
4096 LOAD_FUNCPTR(FT_Init_FreeType)
4097 LOAD_FUNCPTR(FT_Library_Version)
4098 LOAD_FUNCPTR(FT_Load_Glyph)
4099 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
4100 LOAD_FUNCPTR(FT_Matrix_Multiply)
4101 #ifndef FT_MULFIX_INLINED
4102 LOAD_FUNCPTR(FT_MulFix)
4103 #endif
4104 LOAD_FUNCPTR(FT_New_Face)
4105 LOAD_FUNCPTR(FT_New_Memory_Face)
4106 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
4107 LOAD_FUNCPTR(FT_Outline_Get_CBox)
4108 LOAD_FUNCPTR(FT_Outline_Transform)
4109 LOAD_FUNCPTR(FT_Outline_Translate)
4110 LOAD_FUNCPTR(FT_Render_Glyph)
4111 LOAD_FUNCPTR(FT_Select_Charmap)
4112 LOAD_FUNCPTR(FT_Set_Charmap)
4113 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
4114 LOAD_FUNCPTR(FT_Vector_Length)
4115 LOAD_FUNCPTR(FT_Vector_Transform)
4116 LOAD_FUNCPTR(FT_Vector_Unit)
4117 #undef LOAD_FUNCPTR
4118 /* Don't warn if these ones are missing */
4119 pFT_Outline_Embolden = wine_dlsym(ft_handle, "FT_Outline_Embolden", NULL, 0);
4120 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
4121 #ifdef FT_LCD_FILTER_H
4122 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
4123 #endif
4125 if(pFT_Init_FreeType(&library) != 0) {
4126 ERR("Can't init FreeType library\n");
4127 wine_dlclose(ft_handle, NULL, 0);
4128 ft_handle = NULL;
4129 return FALSE;
4131 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
4133 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
4134 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
4135 ((FT_Version.minor << 8) & 0x00ff00) |
4136 ((FT_Version.patch ) & 0x0000ff);
4138 font_driver = &freetype_funcs;
4139 return TRUE;
4141 sym_not_found:
4142 WINE_MESSAGE(
4143 "Wine cannot find certain functions that it needs inside the FreeType\n"
4144 "font library. To enable Wine to use TrueType fonts please upgrade\n"
4145 "FreeType to at least version 2.1.4.\n"
4146 "http://www.freetype.org\n");
4147 wine_dlclose(ft_handle, NULL, 0);
4148 ft_handle = NULL;
4149 return FALSE;
4152 static void init_font_list(void)
4154 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
4155 static const WCHAR pathW[] = {'P','a','t','h',0};
4156 HKEY hkey;
4157 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
4158 WCHAR windowsdir[MAX_PATH];
4159 char *unixname;
4161 delete_external_font_keys();
4163 /* load the system bitmap fonts */
4164 load_system_fonts();
4166 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
4167 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
4168 strcatW(windowsdir, fontsW);
4169 if((unixname = wine_get_unix_file_name(windowsdir)))
4171 ReadFontDir(unixname, FALSE);
4172 HeapFree(GetProcessHeap(), 0, unixname);
4175 /* load the wine fonts */
4176 if ((unixname = get_font_dir()))
4178 ReadFontDir(unixname, TRUE);
4179 HeapFree(GetProcessHeap(), 0, unixname);
4182 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
4183 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
4184 full path as the entry. Also look for any .fon fonts, since ReadFontDir
4185 will skip these. */
4186 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
4187 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
4188 &hkey) == ERROR_SUCCESS)
4190 LPWSTR data, valueW;
4191 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
4192 &valuelen, &datalen, NULL, NULL);
4194 valuelen++; /* returned value doesn't include room for '\0' */
4195 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
4196 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
4197 if (valueW && data)
4199 dlen = datalen * sizeof(WCHAR);
4200 vlen = valuelen;
4201 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
4202 &dlen) == ERROR_SUCCESS)
4204 if(data[0] && (data[1] == ':'))
4206 if((unixname = wine_get_unix_file_name(data)))
4208 AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
4209 HeapFree(GetProcessHeap(), 0, unixname);
4212 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
4214 WCHAR pathW[MAX_PATH];
4215 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
4216 BOOL added = FALSE;
4218 sprintfW(pathW, fmtW, windowsdir, data);
4219 if((unixname = wine_get_unix_file_name(pathW)))
4221 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
4222 HeapFree(GetProcessHeap(), 0, unixname);
4224 if (!added)
4225 load_font_from_data_dir(data);
4227 /* reset dlen and vlen */
4228 dlen = datalen;
4229 vlen = valuelen;
4232 HeapFree(GetProcessHeap(), 0, data);
4233 HeapFree(GetProcessHeap(), 0, valueW);
4234 RegCloseKey(hkey);
4237 #ifdef SONAME_LIBFONTCONFIG
4238 load_fontconfig_fonts();
4239 #elif defined(HAVE_CARBON_CARBON_H)
4240 load_mac_fonts();
4241 #elif defined(__ANDROID__)
4242 ReadFontDir("/system/fonts", TRUE);
4243 #endif
4245 /* then look in any directories that we've specified in the config file */
4246 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
4247 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
4249 DWORD len;
4250 LPWSTR valueW;
4251 LPSTR valueA, ptr;
4253 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
4255 len += sizeof(WCHAR);
4256 valueW = HeapAlloc( GetProcessHeap(), 0, len );
4257 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
4259 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
4260 valueA = HeapAlloc( GetProcessHeap(), 0, len );
4261 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
4262 TRACE( "got font path %s\n", debugstr_a(valueA) );
4263 ptr = valueA;
4264 while (ptr)
4266 const char* home;
4267 LPSTR next = strchr( ptr, ':' );
4268 if (next) *next++ = 0;
4269 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
4270 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
4272 strcpy( unixname, home );
4273 strcat( unixname, ptr + 1 );
4274 ReadFontDir( unixname, TRUE );
4275 HeapFree( GetProcessHeap(), 0, unixname );
4277 else
4278 ReadFontDir( ptr, TRUE );
4279 ptr = next;
4281 HeapFree( GetProcessHeap(), 0, valueA );
4283 HeapFree( GetProcessHeap(), 0, valueW );
4285 RegCloseKey(hkey);
4289 static BOOL move_to_front(const WCHAR *name)
4291 Family *family, *cursor2;
4292 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
4294 if(!strcmpiW(family->FamilyName, name))
4296 list_remove(&family->entry);
4297 list_add_head(&font_list, &family->entry);
4298 return TRUE;
4301 return FALSE;
4304 static BOOL set_default(const WCHAR **name_list)
4306 while (*name_list)
4308 if (move_to_front(*name_list)) return TRUE;
4309 name_list++;
4312 return FALSE;
4315 static void reorder_font_list(void)
4317 set_default( default_serif_list );
4318 set_default( default_fixed_list );
4319 set_default( default_sans_list );
4322 /*************************************************************
4323 * WineEngInit
4325 * Initialize FreeType library and create a list of available faces
4327 BOOL WineEngInit(void)
4329 HKEY hkey;
4330 DWORD disposition;
4331 HANDLE font_mutex;
4333 /* update locale dependent font info in registry */
4334 update_font_info();
4336 if(!init_freetype()) return FALSE;
4338 #ifdef SONAME_LIBFONTCONFIG
4339 init_fontconfig();
4340 #endif
4342 if (!RegOpenKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, KEY_READ, &hkey))
4344 static const WCHAR antialias_fake_bold_or_italic[] = { 'A','n','t','i','a','l','i','a','s','F','a','k','e',
4345 'B','o','l','d','O','r','I','t','a','l','i','c',0 };
4346 static const WCHAR true_options[] = { 'y','Y','t','T','1',0 };
4347 DWORD type, size;
4348 WCHAR buffer[20];
4350 size = sizeof(buffer);
4351 if (!RegQueryValueExW(hkey, antialias_fake_bold_or_italic, NULL, &type, (BYTE*)buffer, &size) &&
4352 type == REG_SZ && size >= 1)
4354 antialias_fakes = (strchrW(true_options, buffer[0]) != NULL);
4356 RegCloseKey(hkey);
4359 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
4361 ERR("Failed to create font mutex\n");
4362 return FALSE;
4364 WaitForSingleObject(font_mutex, INFINITE);
4366 create_font_cache_key(&hkey_font_cache, &disposition);
4368 if(disposition == REG_CREATED_NEW_KEY)
4369 init_font_list();
4370 else
4371 load_font_list_from_cache(hkey_font_cache);
4373 reorder_font_list();
4375 DumpFontList();
4376 LoadSubstList();
4377 DumpSubstList();
4378 LoadReplaceList();
4380 if(disposition == REG_CREATED_NEW_KEY)
4381 update_reg_entries();
4383 init_system_links();
4385 ReleaseMutex(font_mutex);
4386 return TRUE;
4389 /* Some fonts have large usWinDescent values, as a result of storing signed short
4390 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
4391 some font generation tools. */
4392 static inline USHORT get_fixed_windescent(USHORT windescent)
4394 return abs((SHORT)windescent);
4397 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
4399 TT_OS2 *pOS2;
4400 TT_HoriHeader *pHori;
4402 LONG ppem;
4403 const LONG MAX_PPEM = (1 << 16) - 1;
4405 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4406 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4408 if(height == 0) height = 16;
4410 /* Calc. height of EM square:
4412 * For +ve lfHeight we have
4413 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
4414 * Re-arranging gives:
4415 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4417 * For -ve lfHeight we have
4418 * |lfHeight| = ppem
4419 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4420 * with il = winAscent + winDescent - units_per_em]
4424 if(height > 0) {
4425 USHORT windescent = get_fixed_windescent(pOS2->usWinDescent);
4426 if(pOS2->usWinAscent + windescent == 0)
4427 ppem = MulDiv(ft_face->units_per_EM, height,
4428 pHori->Ascender - pHori->Descender);
4429 else
4430 ppem = MulDiv(ft_face->units_per_EM, height,
4431 pOS2->usWinAscent + windescent);
4432 if(ppem > MAX_PPEM) {
4433 WARN("Ignoring too large height %d, ppem %d\n", height, ppem);
4434 ppem = 1;
4437 else if(height >= -MAX_PPEM)
4438 ppem = -height;
4439 else {
4440 WARN("Ignoring too large height %d\n", height);
4441 ppem = 1;
4444 return ppem;
4447 static struct font_mapping *map_font_file( const char *name )
4449 struct font_mapping *mapping;
4450 struct stat st;
4451 int fd;
4453 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
4454 if (fstat( fd, &st ) == -1) goto error;
4456 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
4458 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
4460 mapping->refcount++;
4461 close( fd );
4462 return mapping;
4465 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
4466 goto error;
4468 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
4469 close( fd );
4471 if (mapping->data == MAP_FAILED)
4473 HeapFree( GetProcessHeap(), 0, mapping );
4474 return NULL;
4476 mapping->refcount = 1;
4477 mapping->dev = st.st_dev;
4478 mapping->ino = st.st_ino;
4479 mapping->size = st.st_size;
4480 list_add_tail( &mappings_list, &mapping->entry );
4481 return mapping;
4483 error:
4484 close( fd );
4485 return NULL;
4488 static void unmap_font_file( struct font_mapping *mapping )
4490 if (!--mapping->refcount)
4492 list_remove( &mapping->entry );
4493 munmap( mapping->data, mapping->size );
4494 HeapFree( GetProcessHeap(), 0, mapping );
4498 static LONG load_VDMX(GdiFont*, LONG);
4500 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
4502 FT_Error err;
4503 FT_Face ft_face;
4504 void *data_ptr;
4505 DWORD data_size;
4507 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
4509 if (face->file)
4511 char *filename = strWtoA( CP_UNIXCP, face->file );
4512 font->mapping = map_font_file( filename );
4513 HeapFree( GetProcessHeap(), 0, filename );
4514 if (!font->mapping)
4516 WARN("failed to map %s\n", debugstr_w(face->file));
4517 return 0;
4519 data_ptr = font->mapping->data;
4520 data_size = font->mapping->size;
4522 else
4524 data_ptr = face->font_data_ptr;
4525 data_size = face->font_data_size;
4528 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
4529 if(err) {
4530 ERR("FT_New_Face rets %d\n", err);
4531 return 0;
4534 /* set it here, as load_VDMX needs it */
4535 font->ft_face = ft_face;
4537 if(FT_IS_SCALABLE(ft_face)) {
4538 /* load the VDMX table if we have one */
4539 font->ppem = load_VDMX(font, height);
4540 if(font->ppem == 0)
4541 font->ppem = calc_ppem_for_height(ft_face, height);
4542 TRACE("height %d => ppem %d\n", height, font->ppem);
4544 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
4545 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
4546 } else {
4547 font->ppem = height;
4548 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
4549 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
4551 return ft_face;
4555 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
4557 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4558 a single face with the requested charset. The idea is to check if
4559 the selected font supports the current ANSI codepage, if it does
4560 return the corresponding charset, else return the first charset */
4562 CHARSETINFO csi;
4563 int acp = GetACP(), i;
4564 DWORD fs0;
4566 *cp = acp;
4567 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
4569 const SYSTEM_LINKS *font_link;
4571 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4572 return csi.ciCharset;
4574 font_link = find_font_link(family_name);
4575 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4576 return csi.ciCharset;
4579 for(i = 0; i < 32; i++) {
4580 fs0 = 1L << i;
4581 if(face->fs.fsCsb[0] & fs0) {
4582 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4583 *cp = csi.ciACP;
4584 return csi.ciCharset;
4586 else
4587 FIXME("TCI failing on %x\n", fs0);
4591 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4592 face->fs.fsCsb[0], debugstr_w(face->file));
4593 *cp = acp;
4594 return DEFAULT_CHARSET;
4597 static GdiFont *alloc_font(void)
4599 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4600 ret->refcount = 1;
4601 ret->gmsize = 1;
4602 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4603 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4604 ret->potm = NULL;
4605 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4606 ret->total_kern_pairs = (DWORD)-1;
4607 ret->kern_pairs = NULL;
4608 ret->instance_id = alloc_font_handle(ret);
4609 list_init(&ret->child_fonts);
4610 return ret;
4613 static void free_font(GdiFont *font)
4615 CHILD_FONT *child, *child_next;
4616 DWORD i;
4618 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
4620 list_remove(&child->entry);
4621 if(child->font)
4622 free_font(child->font);
4623 release_face( child->face );
4624 HeapFree(GetProcessHeap(), 0, child);
4627 HeapFree(GetProcessHeap(), 0, font->fileinfo);
4628 free_font_handle(font->instance_id);
4629 if (font->ft_face) pFT_Done_Face(font->ft_face);
4630 if (font->mapping) unmap_font_file( font->mapping );
4631 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4632 HeapFree(GetProcessHeap(), 0, font->potm);
4633 HeapFree(GetProcessHeap(), 0, font->name);
4634 for (i = 0; i < font->gmsize; i++)
4635 HeapFree(GetProcessHeap(),0,font->gm[i]);
4636 HeapFree(GetProcessHeap(), 0, font->gm);
4637 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4638 HeapFree(GetProcessHeap(), 0, font);
4642 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4644 FT_Face ft_face = font->ft_face;
4645 FT_ULong len;
4646 FT_Error err;
4648 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4650 if(!buf)
4651 len = 0;
4652 else
4653 len = cbData;
4655 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4657 /* make sure value of len is the value freetype says it needs */
4658 if (buf && len)
4660 FT_ULong needed = 0;
4661 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4662 if( !err && needed < len) len = needed;
4664 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4665 if (err)
4667 TRACE("Can't find table %c%c%c%c\n",
4668 /* bytes were reversed */
4669 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4670 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4671 return GDI_ERROR;
4673 return len;
4676 /*************************************************************
4677 * load_VDMX
4679 * load the vdmx entry for the specified height
4682 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4683 ( ( (FT_ULong)_x4 << 24 ) | \
4684 ( (FT_ULong)_x3 << 16 ) | \
4685 ( (FT_ULong)_x2 << 8 ) | \
4686 (FT_ULong)_x1 )
4688 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4690 typedef struct {
4691 WORD version;
4692 WORD numRecs;
4693 WORD numRatios;
4694 } VDMX_Header;
4696 typedef struct {
4697 BYTE bCharSet;
4698 BYTE xRatio;
4699 BYTE yStartRatio;
4700 BYTE yEndRatio;
4701 } Ratios;
4703 typedef struct {
4704 WORD recs;
4705 BYTE startsz;
4706 BYTE endsz;
4707 } VDMX_group;
4709 typedef struct {
4710 WORD yPelHeight;
4711 WORD yMax;
4712 WORD yMin;
4713 } VDMX_vTable;
4715 static LONG load_VDMX(GdiFont *font, LONG height)
4717 VDMX_Header hdr;
4718 VDMX_group group;
4719 BYTE devXRatio, devYRatio;
4720 USHORT numRecs, numRatios;
4721 DWORD result, offset = -1;
4722 LONG ppem = 0;
4723 int i;
4725 result = get_font_data(font, MS_VDMX_TAG, 0, &hdr, sizeof(hdr));
4727 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4728 return ppem;
4730 /* FIXME: need the real device aspect ratio */
4731 devXRatio = 1;
4732 devYRatio = 1;
4734 numRecs = GET_BE_WORD(hdr.numRecs);
4735 numRatios = GET_BE_WORD(hdr.numRatios);
4737 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr.version), numRecs, numRatios);
4738 for(i = 0; i < numRatios; i++) {
4739 Ratios ratio;
4741 offset = sizeof(hdr) + (i * sizeof(Ratios));
4742 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4743 offset = -1;
4745 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4747 if (!ratio.bCharSet) continue;
4749 if((ratio.xRatio == 0 &&
4750 ratio.yStartRatio == 0 &&
4751 ratio.yEndRatio == 0) ||
4752 (devXRatio == ratio.xRatio &&
4753 devYRatio >= ratio.yStartRatio &&
4754 devYRatio <= ratio.yEndRatio))
4756 WORD group_offset;
4758 offset = sizeof(hdr) + numRatios * sizeof(ratio) + i * sizeof(group_offset);
4759 get_font_data(font, MS_VDMX_TAG, offset, &group_offset, sizeof(group_offset));
4760 offset = GET_BE_WORD(group_offset);
4761 break;
4765 if(offset == -1) return 0;
4767 if(get_font_data(font, MS_VDMX_TAG, offset, &group, sizeof(group)) != GDI_ERROR) {
4768 USHORT recs;
4769 BYTE startsz, endsz;
4770 WORD *vTable;
4772 recs = GET_BE_WORD(group.recs);
4773 startsz = group.startsz;
4774 endsz = group.endsz;
4776 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4778 vTable = HeapAlloc(GetProcessHeap(), 0, recs * sizeof(VDMX_vTable));
4779 result = get_font_data(font, MS_VDMX_TAG, offset + sizeof(group), vTable, recs * sizeof(VDMX_vTable));
4780 if(result == GDI_ERROR) {
4781 FIXME("Failed to retrieve vTable\n");
4782 goto end;
4785 if(height > 0) {
4786 for(i = 0; i < recs; i++) {
4787 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4788 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4789 ppem = GET_BE_WORD(vTable[i * 3]);
4791 if(yMax + -yMin == height) {
4792 font->yMax = yMax;
4793 font->yMin = yMin;
4794 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4795 break;
4797 if(yMax + -yMin > height) {
4798 if(--i < 0) {
4799 ppem = 0;
4800 goto end; /* failed */
4802 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4803 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4804 ppem = GET_BE_WORD(vTable[i * 3]);
4805 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4806 break;
4809 if(!font->yMax) {
4810 ppem = 0;
4811 TRACE("ppem not found for height %d\n", height);
4813 } else {
4814 ppem = -height;
4815 if(ppem < startsz || ppem > endsz)
4817 ppem = 0;
4818 goto end;
4821 for(i = 0; i < recs; i++) {
4822 USHORT yPelHeight;
4823 yPelHeight = GET_BE_WORD(vTable[i * 3]);
4825 if(yPelHeight > ppem)
4827 ppem = 0;
4828 break; /* failed */
4831 if(yPelHeight == ppem) {
4832 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4833 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4834 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
4835 break;
4839 end:
4840 HeapFree(GetProcessHeap(), 0, vTable);
4843 return ppem;
4846 static void dump_gdi_font_list(void)
4848 GdiFont *font;
4850 TRACE("---------- Font Cache ----------\n");
4851 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct tagGdiFont, entry )
4852 TRACE("font=%p ref=%u %s %d\n", font, font->refcount,
4853 debugstr_w(font->font_desc.lf.lfFaceName), font->font_desc.lf.lfHeight);
4856 static void grab_font( GdiFont *font )
4858 if (!font->refcount++)
4860 list_remove( &font->unused_entry );
4861 unused_font_count--;
4865 static void release_font( GdiFont *font )
4867 if (!font) return;
4868 if (!--font->refcount)
4870 TRACE( "font %p\n", font );
4872 /* add it to the unused list */
4873 list_add_head( &unused_gdi_font_list, &font->unused_entry );
4874 if (unused_font_count > UNUSED_CACHE_SIZE)
4876 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct tagGdiFont, unused_entry );
4877 TRACE( "freeing %p\n", font );
4878 list_remove( &font->entry );
4879 list_remove( &font->unused_entry );
4880 free_font( font );
4882 else unused_font_count++;
4884 if (TRACE_ON(font)) dump_gdi_font_list();
4888 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4890 if(font->font_desc.hash != fd->hash) return TRUE;
4891 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4892 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4893 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4894 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4897 static void calc_hash(FONT_DESC *pfd)
4899 DWORD hash = 0, *ptr, two_chars;
4900 WORD *pwc;
4901 unsigned int i;
4903 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4904 hash ^= *ptr;
4905 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4906 hash ^= *ptr;
4907 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4908 two_chars = *ptr;
4909 pwc = (WCHAR *)&two_chars;
4910 if(!*pwc) break;
4911 *pwc = toupperW(*pwc);
4912 pwc++;
4913 *pwc = toupperW(*pwc);
4914 hash ^= two_chars;
4915 if(!*pwc) break;
4917 hash ^= !pfd->can_use_bitmap;
4918 pfd->hash = hash;
4921 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4923 GdiFont *ret;
4924 FONT_DESC fd;
4926 fd.lf = *plf;
4927 fd.matrix = *pmat;
4928 fd.can_use_bitmap = can_use_bitmap;
4929 calc_hash(&fd);
4931 /* try the in-use list */
4932 LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
4934 if(fontcmp(ret, &fd)) continue;
4935 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4936 list_remove( &ret->entry );
4937 list_add_head( &gdi_font_list, &ret->entry );
4938 grab_font( ret );
4939 return ret;
4941 return NULL;
4944 static void add_to_cache(GdiFont *font)
4946 static DWORD cache_num = 1;
4948 font->cache_num = cache_num++;
4949 list_add_head(&gdi_font_list, &font->entry);
4950 TRACE( "font %p\n", font );
4953 /*************************************************************
4954 * create_child_font_list
4956 static BOOL create_child_font_list(GdiFont *font)
4958 BOOL ret = FALSE;
4959 SYSTEM_LINKS *font_link;
4960 CHILD_FONT *font_link_entry, *new_child;
4961 FontSubst *psub;
4962 WCHAR* font_name;
4964 psub = get_font_subst(&font_subst_list, font->name, -1);
4965 font_name = psub ? psub->to.name : font->name;
4966 font_link = find_font_link(font_name);
4967 if (font_link != NULL)
4969 TRACE("found entry in system 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;
4982 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4983 * Sans Serif. This is how asian windows get default fallbacks for fonts
4985 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4986 font->charset != OEM_CHARSET &&
4987 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4989 font_link = find_font_link(szDefaultFallbackLink);
4990 if (font_link != NULL)
4992 TRACE("found entry in default fallback list\n");
4993 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4995 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4996 new_child->face = font_link_entry->face;
4997 new_child->font = NULL;
4998 new_child->face->refcount++;
4999 list_add_tail(&font->child_fonts, &new_child->entry);
5000 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
5002 ret = TRUE;
5006 return ret;
5009 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
5011 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
5013 if (pFT_Set_Charmap)
5015 FT_Int i;
5016 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
5018 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
5020 for (i = 0; i < ft_face->num_charmaps; i++)
5022 if (ft_face->charmaps[i]->encoding == encoding)
5024 TRACE("found cmap with platform_id %u, encoding_id %u\n",
5025 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
5027 switch (ft_face->charmaps[i]->platform_id)
5029 default:
5030 cmap_def = ft_face->charmaps[i];
5031 break;
5032 case 0: /* Apple Unicode */
5033 cmap0 = ft_face->charmaps[i];
5034 break;
5035 case 1: /* Macintosh */
5036 cmap1 = ft_face->charmaps[i];
5037 break;
5038 case 2: /* ISO */
5039 cmap2 = ft_face->charmaps[i];
5040 break;
5041 case 3: /* Microsoft */
5042 cmap3 = ft_face->charmaps[i];
5043 break;
5047 if (cmap3) /* prefer Microsoft cmap table */
5048 ft_err = pFT_Set_Charmap(ft_face, cmap3);
5049 else if (cmap1)
5050 ft_err = pFT_Set_Charmap(ft_face, cmap1);
5051 else if (cmap2)
5052 ft_err = pFT_Set_Charmap(ft_face, cmap2);
5053 else if (cmap0)
5054 ft_err = pFT_Set_Charmap(ft_face, cmap0);
5055 else if (cmap_def)
5056 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
5058 return ft_err == FT_Err_Ok;
5061 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
5065 /*************************************************************
5066 * freetype_CreateDC
5068 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
5069 LPCWSTR output, const DEVMODEW *devmode )
5071 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
5073 if (!physdev) return FALSE;
5074 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
5075 return TRUE;
5079 /*************************************************************
5080 * freetype_DeleteDC
5082 static BOOL freetype_DeleteDC( PHYSDEV dev )
5084 struct freetype_physdev *physdev = get_freetype_dev( dev );
5085 release_font( physdev->font );
5086 HeapFree( GetProcessHeap(), 0, physdev );
5087 return TRUE;
5090 static FT_Encoding pick_charmap( FT_Face face, int charset )
5092 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
5093 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
5094 const FT_Encoding *encs = regular_order;
5096 if (charset == SYMBOL_CHARSET) encs = symbol_order;
5098 while (*encs != 0)
5100 if (select_charmap( face, *encs )) break;
5101 encs++;
5103 return *encs;
5106 #define GASP_GRIDFIT 0x01
5107 #define GASP_DOGRAY 0x02
5108 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
5110 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
5112 DWORD size;
5113 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
5114 WORD *alloced = NULL, *ptr = buf;
5115 WORD num_recs, version;
5116 BOOL ret = FALSE;
5118 *flags = 0;
5119 size = get_font_data( font, GASP_TAG, 0, NULL, 0 );
5120 if (size == GDI_ERROR) return FALSE;
5121 if (size < 4 * sizeof(WORD)) return FALSE;
5122 if (size > sizeof(buf))
5124 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
5125 if (!ptr) return FALSE;
5128 get_font_data( font, GASP_TAG, 0, ptr, size );
5130 version = GET_BE_WORD( *ptr++ );
5131 num_recs = GET_BE_WORD( *ptr++ );
5133 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
5135 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
5136 goto done;
5139 while (num_recs--)
5141 *flags = GET_BE_WORD( *(ptr + 1) );
5142 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
5143 ptr += 2;
5145 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
5146 ret = TRUE;
5148 done:
5149 HeapFree( GetProcessHeap(), 0, alloced );
5150 return ret;
5153 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5155 const GSUB_ScriptList *script;
5156 const GSUB_Script *deflt = NULL;
5157 int i;
5158 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5160 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5161 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5163 const GSUB_Script *scr;
5164 int offset;
5166 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5167 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5169 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5170 return scr;
5171 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5172 deflt = scr;
5174 return deflt;
5177 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5179 int i;
5180 int offset;
5181 const GSUB_LangSys *Lang;
5183 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5185 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5187 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5188 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5190 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5191 return Lang;
5193 offset = GET_BE_WORD(script->DefaultLangSys);
5194 if (offset)
5196 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5197 return Lang;
5199 return NULL;
5202 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5204 int i;
5205 const GSUB_FeatureList *feature;
5206 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5208 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5209 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5211 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5212 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5214 const GSUB_Feature *feat;
5215 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5216 return feat;
5219 return NULL;
5222 static const char* get_opentype_script(const GdiFont *font)
5225 * I am not sure if this is the correct way to generate our script tag
5228 switch (font->charset)
5230 case ANSI_CHARSET: return "latn";
5231 case BALTIC_CHARSET: return "latn"; /* ?? */
5232 case CHINESEBIG5_CHARSET: return "hani";
5233 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5234 case GB2312_CHARSET: return "hani";
5235 case GREEK_CHARSET: return "grek";
5236 case HANGUL_CHARSET: return "hang";
5237 case RUSSIAN_CHARSET: return "cyrl";
5238 case SHIFTJIS_CHARSET: return "kana";
5239 case TURKISH_CHARSET: return "latn"; /* ?? */
5240 case VIETNAMESE_CHARSET: return "latn";
5241 case JOHAB_CHARSET: return "latn"; /* ?? */
5242 case ARABIC_CHARSET: return "arab";
5243 case HEBREW_CHARSET: return "hebr";
5244 case THAI_CHARSET: return "thai";
5245 default: return "latn";
5249 static const VOID * get_GSUB_vert_feature(const GdiFont *font)
5251 const GSUB_Header *header;
5252 const GSUB_Script *script;
5253 const GSUB_LangSys *language;
5254 const GSUB_Feature *feature;
5256 if (!font->GSUB_Table)
5257 return NULL;
5259 header = font->GSUB_Table;
5261 script = GSUB_get_script_table(header, get_opentype_script(font));
5262 if (!script)
5264 TRACE("Script not found\n");
5265 return NULL;
5267 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5268 if (!language)
5270 TRACE("Language not found\n");
5271 return NULL;
5273 feature = GSUB_get_feature(header, language, "vrt2");
5274 if (!feature)
5275 feature = GSUB_get_feature(header, language, "vert");
5276 if (!feature)
5278 TRACE("vrt2/vert feature not found\n");
5279 return NULL;
5281 return feature;
5284 static void fill_fileinfo_from_face( GdiFont *font, Face *face )
5286 WIN32_FILE_ATTRIBUTE_DATA info;
5287 int len;
5289 if (!face->file)
5291 font->fileinfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*font->fileinfo));
5292 return;
5295 len = strlenW(face->file);
5296 font->fileinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*font->fileinfo) + len * sizeof(WCHAR));
5297 if (GetFileAttributesExW(face->file, GetFileExInfoStandard, &info))
5299 font->fileinfo->writetime = info.ftLastWriteTime;
5300 font->fileinfo->size.QuadPart = (LONGLONG)info.nFileSizeHigh << 32 | info.nFileSizeLow;
5301 strcpyW(font->fileinfo->path, face->file);
5303 else
5304 memset(font->fileinfo, 0, sizeof(*font->fileinfo) + len * sizeof(WCHAR));
5307 /*************************************************************
5308 * freetype_SelectFont
5310 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
5312 struct freetype_physdev *physdev = get_freetype_dev( dev );
5313 GdiFont *ret;
5314 Face *face, *best, *best_bitmap;
5315 Family *family, *last_resort_family;
5316 const struct list *face_list;
5317 INT height, width = 0;
5318 unsigned int score = 0, new_score;
5319 signed int diff = 0, newdiff;
5320 BOOL bd, it, can_use_bitmap, want_vertical;
5321 LOGFONTW lf;
5322 CHARSETINFO csi;
5323 FMAT2 dcmat;
5324 FontSubst *psub = NULL;
5325 DC *dc = get_dc_ptr( dev->hdc );
5326 const SYSTEM_LINKS *font_link;
5328 if (!hfont) /* notification that the font has been changed by another driver */
5330 release_font( physdev->font );
5331 physdev->font = NULL;
5332 release_dc_ptr( dc );
5333 return 0;
5336 GetObjectW( hfont, sizeof(lf), &lf );
5337 lf.lfWidth = abs(lf.lfWidth);
5339 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
5341 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
5342 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
5343 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
5344 lf.lfEscapement);
5346 if(dc->GraphicsMode == GM_ADVANCED)
5348 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
5349 /* Try to avoid not necessary glyph transformations */
5350 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
5352 lf.lfHeight *= fabs(dcmat.eM11);
5353 lf.lfWidth *= fabs(dcmat.eM11);
5354 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
5357 else
5359 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
5360 font scaling abilities. */
5361 dcmat.eM11 = dcmat.eM22 = 1.0;
5362 dcmat.eM21 = dcmat.eM12 = 0;
5363 lf.lfOrientation = lf.lfEscapement;
5364 if (dc->vport2WorldValid)
5366 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
5367 lf.lfOrientation = -lf.lfOrientation;
5368 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
5369 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
5373 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
5374 dcmat.eM21, dcmat.eM22);
5376 GDI_CheckNotLock();
5377 EnterCriticalSection( &freetype_cs );
5379 /* check the cache first */
5380 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5381 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
5382 goto done;
5385 TRACE("not in cache\n");
5386 ret = alloc_font();
5388 ret->font_desc.matrix = dcmat;
5389 ret->font_desc.lf = lf;
5390 ret->font_desc.can_use_bitmap = can_use_bitmap;
5391 calc_hash(&ret->font_desc);
5393 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
5394 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
5395 original value lfCharSet. Note this is a special case for
5396 Symbol and doesn't happen at least for "Wingdings*" */
5398 if(!strcmpiW(lf.lfFaceName, SymbolW))
5399 lf.lfCharSet = SYMBOL_CHARSET;
5401 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
5402 switch(lf.lfCharSet) {
5403 case DEFAULT_CHARSET:
5404 csi.fs.fsCsb[0] = 0;
5405 break;
5406 default:
5407 FIXME("Untranslated charset %d\n", lf.lfCharSet);
5408 csi.fs.fsCsb[0] = 0;
5409 break;
5413 family = NULL;
5414 if(lf.lfFaceName[0] != '\0') {
5415 CHILD_FONT *font_link_entry;
5416 LPWSTR FaceName = lf.lfFaceName;
5418 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
5420 if(psub) {
5421 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
5422 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
5423 if (psub->to.charset != -1)
5424 lf.lfCharSet = psub->to.charset;
5427 /* We want a match on name and charset or just name if
5428 charset was DEFAULT_CHARSET. If the latter then
5429 we fixup the returned charset later in get_nearest_charset
5430 where we'll either use the charset of the current ansi codepage
5431 or if that's unavailable the first charset that the font supports.
5433 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5434 if (!strcmpiW(family->FamilyName, FaceName) ||
5435 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
5437 font_link = find_font_link(family->FamilyName);
5438 face_list = get_face_list_from_family(family);
5439 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5440 if (!(face->scalable || can_use_bitmap))
5441 continue;
5442 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5443 goto found;
5444 if (font_link != NULL &&
5445 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5446 goto found;
5447 if (!csi.fs.fsCsb[0])
5448 goto found;
5453 /* Search by full face name. */
5454 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5455 face_list = get_face_list_from_family(family);
5456 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5457 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
5458 (face->scalable || can_use_bitmap))
5460 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5461 goto found_face;
5462 font_link = find_font_link(family->FamilyName);
5463 if (font_link != NULL &&
5464 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5465 goto found_face;
5471 * Try check the SystemLink list first for a replacement font.
5472 * We may find good replacements there.
5474 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
5476 if(!strcmpiW(font_link->font_name, FaceName) ||
5477 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
5479 TRACE("found entry in system list\n");
5480 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5482 const SYSTEM_LINKS *links;
5484 face = font_link_entry->face;
5485 if (!(face->scalable || can_use_bitmap))
5486 continue;
5487 family = face->family;
5488 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5489 goto found;
5490 links = find_font_link(family->FamilyName);
5491 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
5492 goto found;
5498 psub = NULL; /* substitution is no more relevant */
5500 /* If requested charset was DEFAULT_CHARSET then try using charset
5501 corresponding to the current ansi codepage */
5502 if (!csi.fs.fsCsb[0])
5504 INT acp = GetACP();
5505 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
5506 FIXME("TCI failed on codepage %d\n", acp);
5507 csi.fs.fsCsb[0] = 0;
5508 } else
5509 lf.lfCharSet = csi.ciCharset;
5512 want_vertical = (lf.lfFaceName[0] == '@');
5514 /* Face families are in the top 4 bits of lfPitchAndFamily,
5515 so mask with 0xF0 before testing */
5517 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
5518 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
5519 strcpyW(lf.lfFaceName, defFixed);
5520 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
5521 strcpyW(lf.lfFaceName, defSerif);
5522 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
5523 strcpyW(lf.lfFaceName, defSans);
5524 else
5525 strcpyW(lf.lfFaceName, defSans);
5526 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5527 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
5528 font_link = find_font_link(family->FamilyName);
5529 face_list = get_face_list_from_family(family);
5530 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5531 if (!(face->scalable || can_use_bitmap))
5532 continue;
5533 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5534 goto found;
5535 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5536 goto found;
5541 last_resort_family = NULL;
5542 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5543 font_link = find_font_link(family->FamilyName);
5544 face_list = get_face_list_from_family(family);
5545 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5546 if(!(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical &&
5547 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5548 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
5549 if(face->scalable)
5550 goto found;
5551 if(can_use_bitmap && !last_resort_family)
5552 last_resort_family = family;
5557 if(last_resort_family) {
5558 family = last_resort_family;
5559 csi.fs.fsCsb[0] = 0;
5560 goto found;
5563 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5564 face_list = get_face_list_from_family(family);
5565 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5566 if(face->scalable && !(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical) {
5567 csi.fs.fsCsb[0] = 0;
5568 WARN("just using first face for now\n");
5569 goto found;
5571 if(can_use_bitmap && !last_resort_family)
5572 last_resort_family = family;
5575 if(!last_resort_family) {
5576 FIXME("can't find a single appropriate font - bailing\n");
5577 free_font(ret);
5578 ret = NULL;
5579 goto done;
5582 WARN("could only find a bitmap font - this will probably look awful!\n");
5583 family = last_resort_family;
5584 csi.fs.fsCsb[0] = 0;
5586 found:
5587 it = lf.lfItalic ? 1 : 0;
5588 bd = lf.lfWeight > 550 ? 1 : 0;
5590 height = lf.lfHeight;
5592 face = best = best_bitmap = NULL;
5593 font_link = find_font_link(family->FamilyName);
5594 face_list = get_face_list_from_family(family);
5595 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5597 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5598 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
5599 !csi.fs.fsCsb[0])
5601 BOOL italic, bold;
5603 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
5604 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
5605 new_score = (italic ^ it) + (bold ^ bd);
5606 if(!best || new_score <= score)
5608 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5609 italic, bold, it, bd);
5610 score = new_score;
5611 best = face;
5612 if(best->scalable && score == 0) break;
5613 if(!best->scalable)
5615 if(height > 0)
5616 newdiff = height - (signed int)(best->size.height);
5617 else
5618 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
5619 if(!best_bitmap || new_score < score ||
5620 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
5622 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
5623 diff = newdiff;
5624 best_bitmap = best;
5625 if(score == 0 && diff == 0) break;
5631 if(best)
5632 face = best->scalable ? best : best_bitmap;
5633 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
5634 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
5636 found_face:
5637 height = lf.lfHeight;
5639 ret->fs = face->fs;
5641 if(csi.fs.fsCsb[0]) {
5642 ret->charset = lf.lfCharSet;
5643 ret->codepage = csi.ciACP;
5645 else
5646 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
5648 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
5649 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
5651 ret->aveWidth = height ? lf.lfWidth : 0;
5653 if(!face->scalable) {
5654 /* Windows uses integer scaling factors for bitmap fonts */
5655 INT scale, scaled_height;
5656 GdiFont *cachedfont;
5658 /* FIXME: rotation of bitmap fonts is ignored */
5659 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
5660 if (ret->aveWidth)
5661 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
5662 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
5663 dcmat.eM11 = dcmat.eM22 = 1.0;
5664 /* As we changed the matrix, we need to search the cache for the font again,
5665 * otherwise we might explode the cache. */
5666 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5667 TRACE("Found cached font after non-scalable matrix rescale!\n");
5668 free_font( ret );
5669 ret = cachedfont;
5670 goto done;
5672 calc_hash(&ret->font_desc);
5674 if (height != 0) height = diff;
5675 height += face->size.height;
5677 scale = (height + face->size.height - 1) / face->size.height;
5678 scaled_height = scale * face->size.height;
5679 /* Only jump to the next height if the difference <= 25% original height */
5680 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
5681 /* The jump between unscaled and doubled is delayed by 1 */
5682 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
5683 ret->scale_y = scale;
5685 width = face->size.x_ppem >> 6;
5686 height = face->size.y_ppem >> 6;
5688 else
5689 ret->scale_y = 1.0;
5690 TRACE("font scale y: %f\n", ret->scale_y);
5692 ret->ft_face = OpenFontFace(ret, face, width, height);
5694 if (!ret->ft_face)
5696 free_font( ret );
5697 ret = NULL;
5698 goto done;
5701 fill_fileinfo_from_face( ret, face );
5702 ret->ntmFlags = face->ntmFlags;
5704 pick_charmap( ret->ft_face, ret->charset );
5706 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
5707 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
5708 ret->underline = lf.lfUnderline ? 0xff : 0;
5709 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
5710 create_child_font_list(ret);
5712 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
5714 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
5715 if (length != GDI_ERROR)
5717 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
5718 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
5719 TRACE("Loaded GSUB table of %i bytes\n",length);
5720 ret->vert_feature = get_GSUB_vert_feature(ret);
5721 if (!ret->vert_feature)
5723 TRACE("Vertical feature not found\n");
5724 HeapFree(GetProcessHeap(), 0, ret->GSUB_Table);
5725 ret->GSUB_Table = NULL;
5729 ret->aa_flags = HIWORD( face->flags );
5731 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
5733 add_to_cache(ret);
5734 done:
5735 if (ret)
5737 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
5739 switch (lf.lfQuality)
5741 case NONANTIALIASED_QUALITY:
5742 case ANTIALIASED_QUALITY:
5743 next->funcs->pSelectFont( dev, hfont, aa_flags );
5744 break;
5745 case CLEARTYPE_QUALITY:
5746 case CLEARTYPE_NATURAL_QUALITY:
5747 default:
5748 if (!*aa_flags) *aa_flags = ret->aa_flags;
5749 next->funcs->pSelectFont( dev, hfont, aa_flags );
5751 /* fixup the antialiasing flags for that font */
5752 switch (*aa_flags)
5754 case WINE_GGO_HRGB_BITMAP:
5755 case WINE_GGO_HBGR_BITMAP:
5756 case WINE_GGO_VRGB_BITMAP:
5757 case WINE_GGO_VBGR_BITMAP:
5758 if (is_subpixel_rendering_enabled()) break;
5759 *aa_flags = GGO_GRAY4_BITMAP;
5760 /* fall through */
5761 case GGO_GRAY2_BITMAP:
5762 case GGO_GRAY4_BITMAP:
5763 case GGO_GRAY8_BITMAP:
5764 case WINE_GGO_GRAY16_BITMAP:
5765 if ((!antialias_fakes || (!ret->fake_bold && !ret->fake_italic)) && is_hinting_enabled())
5767 WORD gasp_flags;
5768 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
5770 TRACE( "font %s %d aa disabled by GASP\n",
5771 debugstr_w(lf.lfFaceName), lf.lfHeight );
5772 *aa_flags = GGO_BITMAP;
5777 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5778 release_font( physdev->font );
5779 physdev->font = ret;
5781 LeaveCriticalSection( &freetype_cs );
5782 release_dc_ptr( dc );
5783 return ret ? hfont : 0;
5786 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5788 HRSRC rsrc;
5789 HGLOBAL hMem;
5790 WCHAR *p;
5791 int i;
5793 id += IDS_FIRST_SCRIPT;
5794 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5795 if (!rsrc) return 0;
5796 hMem = LoadResource( gdi32_module, rsrc );
5797 if (!hMem) return 0;
5799 p = LockResource( hMem );
5800 id &= 0x000f;
5801 while (id--) p += *p + 1;
5803 i = min(LF_FACESIZE - 1, *p);
5804 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5805 buffer[i] = 0;
5806 return i;
5809 static inline BOOL is_complex_script_ansi_cp(UINT ansi_cp)
5811 return (ansi_cp == 874 /* Thai */
5812 || ansi_cp == 1255 /* Hebrew */
5813 || ansi_cp == 1256 /* Arabic */
5817 /***************************************************
5818 * create_enum_charset_list
5820 * This function creates charset enumeration list because in DEFAULT_CHARSET
5821 * case, the ANSI codepage's charset takes precedence over other charsets.
5822 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
5823 * This function works as a filter other than DEFAULT_CHARSET case.
5825 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5827 CHARSETINFO csi;
5828 DWORD n = 0;
5830 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5831 csi.fs.fsCsb[0] != 0) {
5832 list->element[n].mask = csi.fs.fsCsb[0];
5833 list->element[n].charset = csi.ciCharset;
5834 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5835 n++;
5837 else { /* charset is DEFAULT_CHARSET or invalid. */
5838 INT acp, i;
5839 DWORD mask = 0;
5841 /* Set the current codepage's charset as the first element. */
5842 acp = GetACP();
5843 if (!is_complex_script_ansi_cp(acp) &&
5844 TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5845 csi.fs.fsCsb[0] != 0) {
5846 list->element[n].mask = csi.fs.fsCsb[0];
5847 list->element[n].charset = csi.ciCharset;
5848 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5849 mask |= csi.fs.fsCsb[0];
5850 n++;
5853 /* Fill out left elements. */
5854 for (i = 0; i < 32; i++) {
5855 FONTSIGNATURE fs;
5856 fs.fsCsb[0] = 1L << i;
5857 fs.fsCsb[1] = 0;
5858 if (fs.fsCsb[0] & mask)
5859 continue; /* skip, already added. */
5860 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5861 continue; /* skip, this is an invalid fsCsb bit. */
5863 list->element[n].mask = fs.fsCsb[0];
5864 list->element[n].charset = csi.ciCharset;
5865 load_script_name( i, list->element[n].name );
5866 mask |= fs.fsCsb[0];
5867 n++;
5870 /* add catch all mask for remaining bits */
5871 if (~mask)
5873 list->element[n].mask = ~mask;
5874 list->element[n].charset = DEFAULT_CHARSET;
5875 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5876 n++;
5879 list->total = n;
5881 return n;
5884 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
5885 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5887 GdiFont *font;
5888 LONG width, height;
5890 if (face->cached_enum_data)
5892 TRACE("Cached\n");
5893 *pelf = face->cached_enum_data->elf;
5894 *pntm = face->cached_enum_data->ntm;
5895 *ptype = face->cached_enum_data->type;
5896 return;
5899 font = alloc_font();
5901 if(face->scalable) {
5902 height = 100;
5903 width = 0;
5904 } else {
5905 height = face->size.y_ppem >> 6;
5906 width = face->size.x_ppem >> 6;
5908 font->scale_y = 1.0;
5910 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5912 free_font(font);
5913 return;
5916 font->name = strdupW( family_name );
5917 font->ntmFlags = face->ntmFlags;
5919 if (get_outline_text_metrics(font))
5921 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5923 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5924 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5925 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5927 lstrcpynW(pelf->elfLogFont.lfFaceName,
5928 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5929 LF_FACESIZE);
5930 lstrcpynW(pelf->elfFullName,
5931 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5932 LF_FULLFACESIZE);
5933 lstrcpynW(pelf->elfStyle,
5934 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5935 LF_FACESIZE);
5937 else
5939 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5941 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5942 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5943 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5945 lstrcpynW(pelf->elfLogFont.lfFaceName, family_name, LF_FACESIZE);
5946 if (face->FullName)
5947 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5948 else
5949 lstrcpynW(pelf->elfFullName, family_name, LF_FULLFACESIZE);
5950 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5953 pntm->ntmTm.ntmFlags = face->ntmFlags;
5954 pntm->ntmFontSig = face->fs;
5956 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5958 pelf->elfLogFont.lfEscapement = 0;
5959 pelf->elfLogFont.lfOrientation = 0;
5960 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5961 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5962 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5963 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5964 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5965 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5966 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5967 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5968 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5969 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5970 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5972 *ptype = 0;
5973 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5974 *ptype |= TRUETYPE_FONTTYPE;
5975 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5976 *ptype |= DEVICE_FONTTYPE;
5977 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5978 *ptype |= RASTER_FONTTYPE;
5980 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5981 if (face->cached_enum_data)
5983 face->cached_enum_data->elf = *pelf;
5984 face->cached_enum_data->ntm = *pntm;
5985 face->cached_enum_data->type = *ptype;
5988 free_font(font);
5991 static BOOL family_matches(Family *family, const WCHAR *face_name)
5993 Face *face;
5994 const struct list *face_list;
5996 if (!strcmpiW(face_name, family->FamilyName)) return TRUE;
5998 face_list = get_face_list_from_family(family);
5999 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
6000 if (face->FullName && !strcmpiW(face_name, face->FullName)) return TRUE;
6002 return FALSE;
6005 static BOOL face_matches(const WCHAR *family_name, Face *face, const WCHAR *face_name)
6007 if (!strcmpiW(face_name, family_name)) return TRUE;
6009 return (face->FullName && !strcmpiW(face_name, face->FullName));
6012 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
6013 FONTENUMPROCW proc, LPARAM lparam, const WCHAR *subst)
6015 ENUMLOGFONTEXW elf;
6016 NEWTEXTMETRICEXW ntm;
6017 DWORD type = 0;
6018 DWORD i;
6020 GetEnumStructs(face, face->family->FamilyName, &elf, &ntm, &type);
6021 for(i = 0; i < list->total; i++) {
6022 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
6023 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
6024 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
6025 i = list->total; /* break out of loop after enumeration */
6027 else
6029 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
6030 /* use the DEFAULT_CHARSET case only if no other charset is present */
6031 if (list->element[i].charset == DEFAULT_CHARSET &&
6032 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
6033 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
6034 strcpyW(elf.elfScript, list->element[i].name);
6035 if (!elf.elfScript[0])
6036 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
6038 /* Font Replacement */
6039 if (family != face->family)
6041 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
6042 if (face->FullName)
6043 strcpyW(elf.elfFullName, face->FullName);
6044 else
6045 strcpyW(elf.elfFullName, family->FamilyName);
6047 if (subst)
6048 strcpyW(elf.elfLogFont.lfFaceName, subst);
6049 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
6050 debugstr_w(elf.elfLogFont.lfFaceName),
6051 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
6052 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
6053 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
6054 ntm.ntmTm.ntmFlags);
6055 /* release section before callback (FIXME) */
6056 LeaveCriticalSection( &freetype_cs );
6057 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
6058 EnterCriticalSection( &freetype_cs );
6060 return TRUE;
6063 /*************************************************************
6064 * freetype_EnumFonts
6066 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
6068 Family *family;
6069 Face *face;
6070 const struct list *face_list;
6071 LOGFONTW lf;
6072 struct enum_charset_list enum_charsets;
6074 if (!plf)
6076 lf.lfCharSet = DEFAULT_CHARSET;
6077 lf.lfPitchAndFamily = 0;
6078 lf.lfFaceName[0] = 0;
6079 plf = &lf;
6082 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
6084 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
6086 GDI_CheckNotLock();
6087 EnterCriticalSection( &freetype_cs );
6088 if(plf->lfFaceName[0]) {
6089 WCHAR *face_name = plf->lfFaceName;
6090 FontSubst *psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
6092 if(psub) {
6093 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
6094 debugstr_w(psub->to.name));
6095 face_name = psub->to.name;
6098 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
6099 if (!family_matches(family, face_name)) continue;
6100 face_list = get_face_list_from_family(family);
6101 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
6102 if (!face_matches(family->FamilyName, face, face_name)) continue;
6103 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam, psub ? psub->from.name : NULL)) return FALSE;
6106 } else {
6107 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
6108 face_list = get_face_list_from_family(family);
6109 face = LIST_ENTRY(list_head(face_list), Face, entry);
6110 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam, NULL)) return FALSE;
6113 LeaveCriticalSection( &freetype_cs );
6114 return TRUE;
6117 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
6119 pt->x.value = vec->x >> 6;
6120 pt->x.fract = (vec->x & 0x3f) << 10;
6121 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
6122 pt->y.value = vec->y >> 6;
6123 pt->y.fract = (vec->y & 0x3f) << 10;
6124 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
6127 /***************************************************
6128 * According to the MSDN documentation on WideCharToMultiByte,
6129 * certain codepages cannot set the default_used parameter.
6130 * This returns TRUE if the codepage can set that parameter, false else
6131 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
6133 static BOOL codepage_sets_default_used(UINT codepage)
6135 switch (codepage)
6137 case CP_UTF7:
6138 case CP_UTF8:
6139 case CP_SYMBOL:
6140 return FALSE;
6141 default:
6142 return TRUE;
6147 * GSUB Table handling functions
6150 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
6152 const GSUB_CoverageFormat1* cf1;
6154 cf1 = table;
6156 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
6158 int count = GET_BE_WORD(cf1->GlyphCount);
6159 int i;
6160 TRACE("Coverage Format 1, %i glyphs\n",count);
6161 for (i = 0; i < count; i++)
6162 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
6163 return i;
6164 return -1;
6166 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
6168 const GSUB_CoverageFormat2* cf2;
6169 int i;
6170 int count;
6171 cf2 = (const GSUB_CoverageFormat2*)cf1;
6173 count = GET_BE_WORD(cf2->RangeCount);
6174 TRACE("Coverage Format 2, %i ranges\n",count);
6175 for (i = 0; i < count; i++)
6177 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
6178 return -1;
6179 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
6180 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
6182 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
6183 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
6186 return -1;
6188 else
6189 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
6191 return -1;
6194 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
6196 int i;
6197 int offset;
6198 const GSUB_LookupList *lookup;
6199 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
6201 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
6202 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
6204 const GSUB_LookupTable *look;
6205 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
6206 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
6207 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
6208 if (GET_BE_WORD(look->LookupType) != 1)
6209 FIXME("We only handle SubType 1\n");
6210 else
6212 int j;
6214 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
6216 const GSUB_SingleSubstFormat1 *ssf1;
6217 offset = GET_BE_WORD(look->SubTable[j]);
6218 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
6219 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
6221 int offset = GET_BE_WORD(ssf1->Coverage);
6222 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
6223 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
6225 TRACE(" Glyph 0x%x ->",glyph);
6226 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
6227 TRACE(" 0x%x\n",glyph);
6230 else
6232 const GSUB_SingleSubstFormat2 *ssf2;
6233 INT index;
6234 INT offset;
6236 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
6237 offset = GET_BE_WORD(ssf1->Coverage);
6238 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
6239 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
6240 TRACE(" Coverage index %i\n",index);
6241 if (index != -1)
6243 TRACE(" Glyph is 0x%x ->",glyph);
6244 glyph = GET_BE_WORD(ssf2->Substitute[index]);
6245 TRACE("0x%x\n",glyph);
6251 return glyph;
6255 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
6257 const GSUB_Header *header;
6258 const GSUB_Feature *feature;
6260 if (!font->GSUB_Table)
6261 return glyph;
6263 header = font->GSUB_Table;
6264 feature = font->vert_feature;
6266 return GSUB_apply_feature(header, feature, glyph);
6269 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
6271 FT_UInt glyphId;
6273 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
6274 WCHAR wc = (WCHAR)glyph;
6275 BOOL default_used;
6276 BOOL *default_used_pointer;
6277 FT_UInt ret;
6278 char buf;
6279 default_used_pointer = NULL;
6280 default_used = FALSE;
6281 if (codepage_sets_default_used(font->codepage))
6282 default_used_pointer = &default_used;
6283 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
6285 if (font->codepage == CP_SYMBOL && wc < 0x100)
6286 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
6287 else
6288 ret = 0;
6290 else
6291 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
6292 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6293 return ret;
6296 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
6298 if (glyph < 0x100) glyph += 0xf000;
6299 /* there is a number of old pre-Unicode "broken" TTFs, which
6300 do have symbols at U+00XX instead of U+f0XX */
6301 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
6302 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
6304 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
6306 return glyphId;
6309 /* helper for freetype_GetGlyphIndices */
6310 static FT_UInt get_gdi_glyph_index(const GdiFont *font, UINT glyph)
6312 WCHAR wc = (WCHAR)glyph;
6313 BOOL default_used = FALSE;
6314 BOOL *default_used_pointer = NULL;
6315 FT_UInt ret;
6316 char buf;
6318 if(font->ft_face->charmap->encoding != FT_ENCODING_NONE)
6319 return get_glyph_index(font, glyph);
6321 if (codepage_sets_default_used(font->codepage))
6322 default_used_pointer = &default_used;
6323 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer)
6324 || default_used)
6326 if (font->codepage == CP_SYMBOL && wc < 0x100)
6327 ret = (unsigned char)wc;
6328 else
6329 ret = 0;
6331 else
6332 ret = (unsigned char)buf;
6333 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6334 return ret;
6337 static FT_UInt get_default_char_index(GdiFont *font)
6339 FT_UInt default_char;
6341 if (FT_IS_SFNT(font->ft_face))
6343 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
6344 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
6346 else
6348 TEXTMETRICW textm;
6349 get_text_metrics(font, &textm);
6350 default_char = textm.tmDefaultChar;
6353 return default_char;
6356 /*************************************************************
6357 * freetype_GetGlyphIndices
6359 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
6361 struct freetype_physdev *physdev = get_freetype_dev( dev );
6362 int i;
6363 WORD default_char;
6364 BOOL got_default = FALSE;
6366 if (!physdev->font)
6368 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
6369 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
6372 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
6374 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
6375 got_default = TRUE;
6378 GDI_CheckNotLock();
6379 EnterCriticalSection( &freetype_cs );
6381 for(i = 0; i < count; i++)
6383 pgi[i] = get_gdi_glyph_index(physdev->font, lpstr[i]);
6384 if (pgi[i] == 0)
6386 if (!got_default)
6388 default_char = get_default_char_index(physdev->font);
6389 got_default = TRUE;
6391 pgi[i] = default_char;
6393 else
6394 pgi[i] = get_GSUB_vert_glyph(physdev->font, pgi[i]);
6396 LeaveCriticalSection( &freetype_cs );
6397 return count;
6400 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
6402 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
6403 return !memcmp(matrix, &identity, sizeof(FMAT2));
6406 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
6408 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
6409 return !memcmp(matrix, &identity, sizeof(MAT2));
6412 static inline FT_Vector normalize_vector(FT_Vector *vec)
6414 FT_Vector out;
6415 FT_Fixed len;
6416 len = pFT_Vector_Length(vec);
6417 if (len) {
6418 out.x = (vec->x << 6) / len;
6419 out.y = (vec->y << 6) / len;
6421 else
6422 out.x = out.y = 0;
6423 return out;
6426 static BOOL get_bold_glyph_outline(FT_GlyphSlot glyph, LONG ppem, FT_Glyph_Metrics *metrics)
6428 FT_Error err;
6429 FT_Pos strength;
6430 FT_BBox bbox;
6432 if(glyph->format != FT_GLYPH_FORMAT_OUTLINE)
6433 return FALSE;
6434 if(!pFT_Outline_Embolden)
6435 return FALSE;
6437 strength = MulDiv(ppem, 1 << 6, 24);
6438 err = pFT_Outline_Embolden(&glyph->outline, strength);
6439 if(err) {
6440 TRACE("FT_Ouline_Embolden returns %d\n", err);
6441 return FALSE;
6444 pFT_Outline_Get_CBox(&glyph->outline, &bbox);
6445 metrics->width = bbox.xMax - bbox.xMin;
6446 metrics->height = bbox.yMax - bbox.yMin;
6447 metrics->horiBearingX = bbox.xMin;
6448 metrics->horiBearingY = bbox.yMax;
6449 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
6450 metrics->vertBearingY = (metrics->vertAdvance - metrics->height) / 2;
6451 return TRUE;
6454 static inline BYTE get_max_level( UINT format )
6456 switch( format )
6458 case GGO_GRAY2_BITMAP: return 4;
6459 case GGO_GRAY4_BITMAP: return 16;
6460 case GGO_GRAY8_BITMAP: return 64;
6462 return 255;
6465 extern const unsigned short vertical_orientation_table[] DECLSPEC_HIDDEN;
6467 static BOOL check_unicode_tategaki(WCHAR uchar)
6469 unsigned short orientation = vertical_orientation_table[vertical_orientation_table[vertical_orientation_table[uchar >> 8]+((uchar >> 4) & 0x0f)]+ (uchar & 0xf)];
6471 /* We only reach this code if typographical substitution did not occur */
6472 /* Type: U or Type: Tu */
6473 return (orientation == 1 || orientation == 3);
6476 static FT_Vector get_advance_metric(GdiFont *incoming_font, GdiFont *font,
6477 const FT_Glyph_Metrics *metrics,
6478 const FT_Matrix *transMat, BOOL vertical_metrics)
6480 FT_Vector adv;
6481 FT_Fixed base_advance, em_scale = 0;
6482 BOOL fixed_pitch_full = FALSE;
6484 if (vertical_metrics)
6485 base_advance = metrics->vertAdvance;
6486 else
6487 base_advance = metrics->horiAdvance;
6489 adv.x = base_advance;
6490 adv.y = 0;
6492 /* In fixed-pitch font, we adjust the fullwidth character advance so that
6493 they have double halfwidth character width. E.g. if the font is 19 ppem,
6494 we return 20 (not 19) for fullwidth characters as we return 10 for
6495 halfwidth characters. */
6496 if(FT_IS_SCALABLE(incoming_font->ft_face) &&
6497 (incoming_font->potm || get_outline_text_metrics(incoming_font)) &&
6498 !(incoming_font->potm->otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
6499 UINT avg_advance;
6500 em_scale = MulDiv(incoming_font->ppem, 1 << 16,
6501 incoming_font->ft_face->units_per_EM);
6502 avg_advance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
6503 fixed_pitch_full = (avg_advance > 0 &&
6504 (base_advance + 63) >> 6 ==
6505 pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale));
6506 if (fixed_pitch_full && !transMat)
6507 adv.x = (avg_advance * 2) << 6;
6510 if (transMat) {
6511 pFT_Vector_Transform(&adv, transMat);
6512 if (fixed_pitch_full && adv.y == 0) {
6513 FT_Vector vec;
6514 vec.x = incoming_font->ntmAvgWidth;
6515 vec.y = 0;
6516 pFT_Vector_Transform(&vec, transMat);
6517 adv.x = (pFT_MulFix(vec.x, em_scale) * 2) << 6;
6521 if (font->fake_bold) {
6522 if (!transMat)
6523 adv.x += 1 << 6;
6524 else {
6525 FT_Vector fake_bold_adv, vec = { 1 << 6, 0 };
6526 pFT_Vector_Transform(&vec, transMat);
6527 fake_bold_adv = normalize_vector(&vec);
6528 adv.x += fake_bold_adv.x;
6529 adv.y += fake_bold_adv.y;
6533 adv.x = (adv.x + 63) & -64;
6534 adv.y = -((adv.y + 63) & -64);
6535 return adv;
6538 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
6540 TTPOLYGONHEADER *pph;
6541 TTPOLYCURVE *ppc;
6542 unsigned int needed = 0, point = 0, contour, first_pt;
6543 unsigned int pph_start, cpfx;
6544 DWORD type;
6546 for (contour = 0; contour < outline->n_contours; contour++)
6548 /* Ignore contours containing one point */
6549 if (point == outline->contours[contour])
6551 point++;
6552 continue;
6555 pph_start = needed;
6556 pph = (TTPOLYGONHEADER *)(buf + needed);
6557 first_pt = point;
6558 if (buf)
6560 pph->dwType = TT_POLYGON_TYPE;
6561 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6563 needed += sizeof(*pph);
6564 point++;
6565 while (point <= outline->contours[contour])
6567 ppc = (TTPOLYCURVE *)(buf + needed);
6568 type = outline->tags[point] & FT_Curve_Tag_On ?
6569 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6570 cpfx = 0;
6573 if (buf)
6574 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6575 cpfx++;
6576 point++;
6577 } while (point <= outline->contours[contour] &&
6578 (outline->tags[point] & FT_Curve_Tag_On) ==
6579 (outline->tags[point-1] & FT_Curve_Tag_On));
6580 /* At the end of a contour Windows adds the start point, but
6581 only for Beziers */
6582 if (point > outline->contours[contour] &&
6583 !(outline->tags[point-1] & FT_Curve_Tag_On))
6585 if (buf)
6586 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6587 cpfx++;
6589 else if (point <= outline->contours[contour] &&
6590 outline->tags[point] & FT_Curve_Tag_On)
6592 /* add closing pt for bezier */
6593 if (buf)
6594 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6595 cpfx++;
6596 point++;
6598 if (buf)
6600 ppc->wType = type;
6601 ppc->cpfx = cpfx;
6603 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6605 if (buf)
6606 pph->cb = needed - pph_start;
6608 return needed;
6611 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
6613 /* Convert the quadratic Beziers to cubic Beziers.
6614 The parametric eqn for a cubic Bezier is, from PLRM:
6615 r(t) = at^3 + bt^2 + ct + r0
6616 with the control points:
6617 r1 = r0 + c/3
6618 r2 = r1 + (c + b)/3
6619 r3 = r0 + c + b + a
6621 A quadratic Bezier has the form:
6622 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6624 So equating powers of t leads to:
6625 r1 = 2/3 p1 + 1/3 p0
6626 r2 = 2/3 p1 + 1/3 p2
6627 and of course r0 = p0, r3 = p2
6629 int contour, point = 0, first_pt;
6630 TTPOLYGONHEADER *pph;
6631 TTPOLYCURVE *ppc;
6632 DWORD pph_start, cpfx, type;
6633 FT_Vector cubic_control[4];
6634 unsigned int needed = 0;
6636 for (contour = 0; contour < outline->n_contours; contour++)
6638 pph_start = needed;
6639 pph = (TTPOLYGONHEADER *)(buf + needed);
6640 first_pt = point;
6641 if (buf)
6643 pph->dwType = TT_POLYGON_TYPE;
6644 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6646 needed += sizeof(*pph);
6647 point++;
6648 while (point <= outline->contours[contour])
6650 ppc = (TTPOLYCURVE *)(buf + needed);
6651 type = outline->tags[point] & FT_Curve_Tag_On ?
6652 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6653 cpfx = 0;
6656 if (type == TT_PRIM_LINE)
6658 if (buf)
6659 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6660 cpfx++;
6661 point++;
6663 else
6665 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6666 so cpfx = 3n */
6668 /* FIXME: Possible optimization in endpoint calculation
6669 if there are two consecutive curves */
6670 cubic_control[0] = outline->points[point-1];
6671 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
6673 cubic_control[0].x += outline->points[point].x + 1;
6674 cubic_control[0].y += outline->points[point].y + 1;
6675 cubic_control[0].x >>= 1;
6676 cubic_control[0].y >>= 1;
6678 if (point+1 > outline->contours[contour])
6679 cubic_control[3] = outline->points[first_pt];
6680 else
6682 cubic_control[3] = outline->points[point+1];
6683 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
6685 cubic_control[3].x += outline->points[point].x + 1;
6686 cubic_control[3].y += outline->points[point].y + 1;
6687 cubic_control[3].x >>= 1;
6688 cubic_control[3].y >>= 1;
6691 /* r1 = 1/3 p0 + 2/3 p1
6692 r2 = 1/3 p2 + 2/3 p1 */
6693 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6694 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6695 cubic_control[2] = cubic_control[1];
6696 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6697 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6698 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6699 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6700 if (buf)
6702 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6703 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6704 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6706 cpfx += 3;
6707 point++;
6709 } while (point <= outline->contours[contour] &&
6710 (outline->tags[point] & FT_Curve_Tag_On) ==
6711 (outline->tags[point-1] & FT_Curve_Tag_On));
6712 /* At the end of a contour Windows adds the start point,
6713 but only for Beziers and we've already done that.
6715 if (point <= outline->contours[contour] &&
6716 outline->tags[point] & FT_Curve_Tag_On)
6718 /* This is the closing pt of a bezier, but we've already
6719 added it, so just inc point and carry on */
6720 point++;
6722 if (buf)
6724 ppc->wType = type;
6725 ppc->cpfx = cpfx;
6727 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6729 if (buf)
6730 pph->cb = needed - pph_start;
6732 return needed;
6735 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6737 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
6738 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
6739 const MAT2* lpmat)
6741 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
6742 GLYPHMETRICS gm;
6743 FT_Face ft_face = incoming_font->ft_face;
6744 GdiFont *font = incoming_font;
6745 FT_Glyph_Metrics metrics;
6746 FT_UInt glyph_index;
6747 DWORD width, height, pitch, needed = 0;
6748 FT_Bitmap ft_bitmap;
6749 FT_Error err;
6750 INT left, right, top = 0, bottom = 0;
6751 FT_Vector adv;
6752 INT origin_x = 0, origin_y = 0;
6753 FT_Angle angle = 0;
6754 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
6755 double widthRatio = 1.0;
6756 FT_Matrix transMat = identityMat;
6757 FT_Matrix transMatUnrotated;
6758 FT_Matrix transMatTategaki;
6759 BOOL needsTransform = FALSE;
6760 BOOL tategaki = (font->name[0] == '@');
6761 BOOL vertical_metrics;
6762 UINT original_index;
6764 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
6765 buflen, buf, lpmat);
6767 TRACE("font transform %f %f %f %f\n",
6768 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
6769 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
6771 if(format & GGO_GLYPH_INDEX) {
6772 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
6773 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
6774 as glyph index. "Treasure Adventure Game" depends on this. */
6775 glyph_index = pFT_Get_Char_Index(font->ft_face, glyph);
6776 TRACE("translate glyph index %04x -> %04x\n", glyph, glyph_index);
6777 } else
6778 glyph_index = glyph;
6779 original_index = glyph_index;
6780 format &= ~GGO_GLYPH_INDEX;
6781 /* TODO: Window also turns off tategaki for glyphs passed in by index
6782 if their unicode code points fall outside of the range that is
6783 rotated. */
6784 } else {
6785 BOOL vert;
6786 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index, &vert);
6787 ft_face = font->ft_face;
6788 original_index = glyph_index;
6789 if (!vert && tategaki)
6790 tategaki = check_unicode_tategaki(glyph);
6793 if(format & GGO_UNHINTED) {
6794 load_flags |= FT_LOAD_NO_HINTING;
6795 format &= ~GGO_UNHINTED;
6798 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
6799 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
6800 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
6801 font->gmsize * sizeof(GM*));
6802 } else {
6803 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
6804 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
6806 *lpgm = FONT_GM(font,original_index)->gm;
6807 *abc = FONT_GM(font,original_index)->abc;
6808 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6809 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6810 lpgm->gmCellIncX, lpgm->gmCellIncY);
6811 return 1; /* FIXME */
6815 if (!font->gm[original_index / GM_BLOCK_SIZE])
6816 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
6818 /* Scaling factor */
6819 if (font->aveWidth)
6821 TEXTMETRICW tm;
6823 get_text_metrics(font, &tm);
6825 widthRatio = (double)font->aveWidth;
6826 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6828 else
6829 widthRatio = font->scale_y;
6831 /* Scaling transform */
6832 if (widthRatio != 1.0 || font->scale_y != 1.0)
6834 FT_Matrix scaleMat;
6835 scaleMat.xx = FT_FixedFromFloat(widthRatio);
6836 scaleMat.xy = 0;
6837 scaleMat.yx = 0;
6838 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
6840 pFT_Matrix_Multiply(&scaleMat, &transMat);
6841 needsTransform = TRUE;
6844 /* Slant transform */
6845 if (font->fake_italic) {
6846 FT_Matrix slantMat;
6848 slantMat.xx = (1 << 16);
6849 slantMat.xy = ((1 << 16) >> 2);
6850 slantMat.yx = 0;
6851 slantMat.yy = (1 << 16);
6852 pFT_Matrix_Multiply(&slantMat, &transMat);
6853 needsTransform = TRUE;
6856 /* Rotation transform */
6857 transMatUnrotated = transMat;
6858 transMatTategaki = transMat;
6859 if(font->orientation || tategaki) {
6860 FT_Matrix rotationMat;
6861 FT_Matrix taterotationMat;
6862 FT_Vector vecAngle;
6864 double orient = font->orientation / 10.0;
6865 double tate_orient = 0.f;
6867 if (tategaki)
6868 tate_orient = ((font->orientation+900)%3600)/10.0;
6869 else
6870 tate_orient = font->orientation/10.0;
6872 if (orient)
6874 angle = FT_FixedFromFloat(orient);
6875 pFT_Vector_Unit(&vecAngle, angle);
6876 rotationMat.xx = vecAngle.x;
6877 rotationMat.xy = -vecAngle.y;
6878 rotationMat.yx = -rotationMat.xy;
6879 rotationMat.yy = rotationMat.xx;
6881 pFT_Matrix_Multiply(&rotationMat, &transMat);
6884 if (tate_orient)
6886 angle = FT_FixedFromFloat(tate_orient);
6887 pFT_Vector_Unit(&vecAngle, angle);
6888 taterotationMat.xx = vecAngle.x;
6889 taterotationMat.xy = -vecAngle.y;
6890 taterotationMat.yx = -taterotationMat.xy;
6891 taterotationMat.yy = taterotationMat.xx;
6892 pFT_Matrix_Multiply(&taterotationMat, &transMatTategaki);
6895 needsTransform = TRUE;
6898 /* World transform */
6899 if (!is_identity_FMAT2(&font->font_desc.matrix))
6901 FT_Matrix worldMat;
6902 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
6903 worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21);
6904 worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12);
6905 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
6906 pFT_Matrix_Multiply(&worldMat, &transMat);
6907 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
6908 pFT_Matrix_Multiply(&worldMat, &transMatTategaki);
6909 needsTransform = TRUE;
6912 /* Extra transformation specified by caller */
6913 if (!is_identity_MAT2(lpmat))
6915 FT_Matrix extraMat;
6916 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
6917 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
6918 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
6919 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
6920 pFT_Matrix_Multiply(&extraMat, &transMat);
6921 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
6922 pFT_Matrix_Multiply(&extraMat, &transMatTategaki);
6923 needsTransform = TRUE;
6926 vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face));
6927 /* there is a freetype bug where vertical metrics are only
6928 properly scaled and correct in 2.4.0 or greater */
6929 if ((vertical_metrics) && (FT_Version.major < 2 || (FT_Version.major == 2 && FT_Version.minor < 4)))
6930 vertical_metrics = FALSE;
6932 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
6933 if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
6935 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
6937 if(err) {
6938 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
6939 return GDI_ERROR;
6942 metrics = ft_face->glyph->metrics;
6943 if(font->fake_bold) {
6944 if (!get_bold_glyph_outline(ft_face->glyph, font->ppem, &metrics) && metrics.width)
6945 metrics.width += 1 << 6;
6948 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6949 * by the text metrics. The proper behavior is to clip the glyph metrics to
6950 * fit within the maximums specified in the text metrics. */
6951 if(incoming_font->potm || get_outline_text_metrics(incoming_font) ||
6952 get_bitmap_text_metrics(incoming_font)) {
6953 TEXTMETRICW *ptm = &incoming_font->potm->otmTextMetrics;
6954 top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
6955 bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
6956 metrics.horiBearingY = top;
6957 metrics.height = top - bottom;
6959 /* TODO: Are we supposed to clip the width as well...? */
6960 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6963 if(!needsTransform) {
6964 left = (INT)(metrics.horiBearingX) & -64;
6965 right = (INT)((metrics.horiBearingX + metrics.width) + 63) & -64;
6966 top = (metrics.horiBearingY + 63) & -64;
6967 bottom = (metrics.horiBearingY - metrics.height) & -64;
6968 adv = get_advance_metric(incoming_font, font, &metrics, NULL, vertical_metrics);
6969 gm.gmCellIncX = adv.x >> 6;
6970 gm.gmCellIncY = 0;
6971 origin_x = left;
6972 origin_y = top;
6973 abc->abcA = origin_x >> 6;
6974 abc->abcB = metrics.width >> 6;
6975 } else {
6976 INT xc, yc;
6977 FT_Vector vec;
6978 FT_Pos lsb;
6980 left = right = 0;
6982 for(xc = 0; xc < 2; xc++) {
6983 for(yc = 0; yc < 2; yc++) {
6984 vec.x = metrics.horiBearingX + xc * metrics.width;
6985 vec.y = metrics.horiBearingY - yc * metrics.height;
6986 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
6987 pFT_Vector_Transform(&vec, &transMatTategaki);
6988 if(xc == 0 && yc == 0) {
6989 left = right = vec.x;
6990 top = bottom = vec.y;
6991 } else {
6992 if(vec.x < left) left = vec.x;
6993 else if(vec.x > right) right = vec.x;
6994 if(vec.y < bottom) bottom = vec.y;
6995 else if(vec.y > top) top = vec.y;
6999 left = left & -64;
7000 right = (right + 63) & -64;
7001 bottom = bottom & -64;
7002 top = (top + 63) & -64;
7004 if (tategaki && (font->potm || get_outline_text_metrics(font)))
7006 if (vertical_metrics)
7007 lsb = metrics.horiBearingY + metrics.vertBearingY;
7008 else
7009 lsb = metrics.vertAdvance + (font->potm->otmDescent << 6);
7010 vec.x = lsb;
7011 vec.y = font->potm->otmDescent << 6;
7012 TRACE ("Vec %ld,%ld\n", vec.x>>6, vec.y>>6);
7013 pFT_Vector_Transform(&vec, &transMat);
7014 origin_x = (vec.x + left) & -64;
7015 origin_y = (vec.y + top + 63) & -64;
7017 else
7019 origin_x = left;
7020 origin_y = top;
7021 lsb = metrics.horiBearingX;
7024 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
7025 adv = get_advance_metric(incoming_font, font, &metrics, &transMat, vertical_metrics);
7026 gm.gmCellIncX = adv.x >> 6;
7027 gm.gmCellIncY = adv.y >> 6;
7029 adv = get_advance_metric(incoming_font, font, &metrics, &transMatUnrotated, vertical_metrics);
7031 vec.x = lsb;
7032 vec.y = 0;
7033 pFT_Vector_Transform(&vec, &transMatUnrotated);
7034 abc->abcA = vec.x >> 6;
7036 vec.x = metrics.width;
7037 vec.y = 0;
7038 pFT_Vector_Transform(&vec, &transMatUnrotated);
7039 if (vec.x >= 0)
7040 abc->abcB = vec.x >> 6;
7041 else
7042 abc->abcB = -vec.x >> 6;
7045 width = (right - left) >> 6;
7046 height = (top - bottom) >> 6;
7047 gm.gmBlackBoxX = width ? width : 1;
7048 gm.gmBlackBoxY = height ? height : 1;
7049 gm.gmptGlyphOrigin.x = origin_x >> 6;
7050 gm.gmptGlyphOrigin.y = origin_y >> 6;
7051 if (!abc->abcB) abc->abcB = 1;
7052 abc->abcC = (adv.x >> 6) - abc->abcA - abc->abcB;
7054 TRACE("%u,%u,%s,%d,%d\n", gm.gmBlackBoxX, gm.gmBlackBoxY,
7055 wine_dbgstr_point(&gm.gmptGlyphOrigin),
7056 gm.gmCellIncX, gm.gmCellIncY);
7058 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
7059 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
7061 FONT_GM(font,original_index)->gm = gm;
7062 FONT_GM(font,original_index)->abc = *abc;
7063 FONT_GM(font,original_index)->init = TRUE;
7066 if(format == GGO_METRICS)
7068 *lpgm = gm;
7069 return 1; /* FIXME */
7072 if(ft_face->glyph->format != ft_glyph_format_outline &&
7073 (format == GGO_NATIVE || format == GGO_BEZIER))
7075 TRACE("loaded a bitmap\n");
7076 return GDI_ERROR;
7079 switch(format) {
7080 case GGO_BITMAP:
7081 pitch = ((width + 31) >> 5) << 2;
7082 needed = pitch * height;
7084 if(!buf || !buflen) break;
7085 if (!needed) return GDI_ERROR; /* empty glyph */
7086 if (needed > buflen)
7087 return GDI_ERROR;
7089 switch(ft_face->glyph->format) {
7090 case ft_glyph_format_bitmap:
7092 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
7093 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
7094 INT h = min( height, ft_face->glyph->bitmap.rows );
7095 while(h--) {
7096 if (!font->fake_bold)
7097 memcpy(dst, src, w);
7098 else {
7099 INT x;
7100 dst[0] = 0;
7101 for (x = 0; x < w; x++) {
7102 dst[x ] = (dst[x] & 0x80) | (src[x] >> 1) | src[x];
7103 if (x+1 < pitch)
7104 dst[x+1] = (src[x] & 0x01) << 7;
7107 src += ft_face->glyph->bitmap.pitch;
7108 dst += pitch;
7110 break;
7113 case ft_glyph_format_outline:
7114 ft_bitmap.width = width;
7115 ft_bitmap.rows = height;
7116 ft_bitmap.pitch = pitch;
7117 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
7118 ft_bitmap.buffer = buf;
7120 if(needsTransform)
7121 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
7123 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
7125 /* Note: FreeType will only set 'black' bits for us. */
7126 memset(buf, 0, needed);
7127 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
7128 break;
7130 default:
7131 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
7132 return GDI_ERROR;
7134 break;
7136 case GGO_GRAY2_BITMAP:
7137 case GGO_GRAY4_BITMAP:
7138 case GGO_GRAY8_BITMAP:
7139 case WINE_GGO_GRAY16_BITMAP:
7141 unsigned int max_level, row, col;
7142 BYTE *start, *ptr;
7144 pitch = (width + 3) / 4 * 4;
7145 needed = pitch * height;
7147 if(!buf || !buflen) break;
7148 if (!needed) return GDI_ERROR; /* empty glyph */
7149 if (needed > buflen)
7150 return GDI_ERROR;
7152 max_level = get_max_level( format );
7154 switch(ft_face->glyph->format) {
7155 case ft_glyph_format_bitmap:
7157 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
7158 INT h = min( height, ft_face->glyph->bitmap.rows );
7159 INT x;
7160 memset( buf, 0, needed );
7161 while(h--) {
7162 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++) {
7163 if (src[x / 8] & masks[x % 8]) {
7164 dst[x] = max_level;
7165 if (font->fake_bold && x+1 < pitch) dst[x+1] = max_level;
7168 src += ft_face->glyph->bitmap.pitch;
7169 dst += pitch;
7171 break;
7173 case ft_glyph_format_outline:
7175 ft_bitmap.width = width;
7176 ft_bitmap.rows = height;
7177 ft_bitmap.pitch = pitch;
7178 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
7179 ft_bitmap.buffer = buf;
7181 if(needsTransform)
7182 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
7184 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
7186 memset(ft_bitmap.buffer, 0, buflen);
7188 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
7190 if (max_level != 255)
7192 for (row = 0, start = buf; row < height; row++)
7194 for (col = 0, ptr = start; col < width; col++, ptr++)
7195 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
7196 start += pitch;
7199 break;
7202 default:
7203 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
7204 return GDI_ERROR;
7206 break;
7209 case WINE_GGO_HRGB_BITMAP:
7210 case WINE_GGO_HBGR_BITMAP:
7211 case WINE_GGO_VRGB_BITMAP:
7212 case WINE_GGO_VBGR_BITMAP:
7213 #ifdef FT_LCD_FILTER_H
7215 switch (ft_face->glyph->format)
7217 case FT_GLYPH_FORMAT_BITMAP:
7219 BYTE *src, *dst;
7220 INT src_pitch, x;
7222 pitch = width * 4;
7223 needed = pitch * height;
7225 if (!buf || !buflen) break;
7226 if (!needed) return GDI_ERROR; /* empty glyph */
7227 if (needed > buflen)
7228 return GDI_ERROR;
7230 memset(buf, 0, buflen);
7231 dst = buf;
7232 src = ft_face->glyph->bitmap.buffer;
7233 src_pitch = ft_face->glyph->bitmap.pitch;
7235 height = min( height, ft_face->glyph->bitmap.rows );
7236 while ( height-- )
7238 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
7240 if ( src[x / 8] & masks[x % 8] )
7242 ((unsigned int *)dst)[x] = ~0u;
7243 if (font->fake_bold && x+1 < width) ((unsigned int *)dst)[x+1] = ~0u;
7246 src += src_pitch;
7247 dst += pitch;
7250 break;
7253 case FT_GLYPH_FORMAT_OUTLINE:
7255 unsigned int *dst;
7256 BYTE *src;
7257 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
7258 INT x_shift, y_shift;
7259 BOOL rgb;
7260 FT_Render_Mode render_mode =
7261 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
7262 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
7264 if (!width || !height)
7266 if (!buf || !buflen) break;
7267 return GDI_ERROR;
7270 if ( render_mode == FT_RENDER_MODE_LCD)
7272 gm.gmBlackBoxX += 2;
7273 gm.gmptGlyphOrigin.x -= 1;
7274 left -= (1 << 6);
7276 else
7278 gm.gmBlackBoxY += 2;
7279 gm.gmptGlyphOrigin.y += 1;
7280 top += (1 << 6);
7283 width = gm.gmBlackBoxX;
7284 height = gm.gmBlackBoxY;
7285 pitch = width * 4;
7286 needed = pitch * height;
7288 if (!buf || !buflen) break;
7289 if (needed > buflen)
7290 return GDI_ERROR;
7292 memset(buf, 0, buflen);
7293 dst = buf;
7294 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
7296 if ( needsTransform )
7297 pFT_Outline_Transform (&ft_face->glyph->outline, &transMatTategaki);
7299 if ( pFT_Library_SetLcdFilter )
7300 pFT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT );
7301 pFT_Render_Glyph (ft_face->glyph, render_mode);
7303 src = ft_face->glyph->bitmap.buffer;
7304 src_pitch = ft_face->glyph->bitmap.pitch;
7305 src_width = ft_face->glyph->bitmap.width;
7306 src_height = ft_face->glyph->bitmap.rows;
7308 if ( render_mode == FT_RENDER_MODE_LCD)
7310 rgb_interval = 1;
7311 hmul = 3;
7312 vmul = 1;
7314 else
7316 rgb_interval = src_pitch;
7317 hmul = 1;
7318 vmul = 3;
7321 x_shift = ft_face->glyph->bitmap_left - (left >> 6);
7322 if ( x_shift < 0 )
7324 src += hmul * -x_shift;
7325 src_width -= hmul * -x_shift;
7327 else if ( x_shift > 0 )
7329 dst += x_shift;
7330 width -= x_shift;
7333 y_shift = (top >> 6) - ft_face->glyph->bitmap_top;
7334 if ( y_shift < 0 )
7336 src += src_pitch * vmul * -y_shift;
7337 src_height -= vmul * -y_shift;
7339 else if ( y_shift > 0 )
7341 dst += y_shift * ( pitch / sizeof(*dst) );
7342 height -= y_shift;
7345 width = min( width, src_width / hmul );
7346 height = min( height, src_height / vmul );
7348 while ( height-- )
7350 for ( x = 0; x < width; x++ )
7352 if ( rgb )
7354 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
7355 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
7356 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
7357 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
7359 else
7361 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
7362 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
7363 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
7364 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
7367 src += src_pitch * vmul;
7368 dst += pitch / sizeof(*dst);
7371 break;
7374 default:
7375 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
7376 return GDI_ERROR;
7379 break;
7381 #else
7382 return GDI_ERROR;
7383 #endif
7385 case GGO_NATIVE:
7387 FT_Outline *outline = &ft_face->glyph->outline;
7389 if(buflen == 0) buf = NULL;
7391 if (needsTransform && buf)
7392 pFT_Outline_Transform(outline, &transMatTategaki);
7394 needed = get_native_glyph_outline(outline, buflen, NULL);
7396 if (!buf || !buflen)
7397 break;
7398 if (needed > buflen)
7399 return GDI_ERROR;
7401 get_native_glyph_outline(outline, buflen, buf);
7402 break;
7404 case GGO_BEZIER:
7406 FT_Outline *outline = &ft_face->glyph->outline;
7407 if(buflen == 0) buf = NULL;
7409 if (needsTransform && buf)
7410 pFT_Outline_Transform(outline, &transMat);
7412 needed = get_bezier_glyph_outline(outline, buflen, NULL);
7414 if (!buf || !buflen)
7415 break;
7416 if (needed > buflen)
7417 return GDI_ERROR;
7419 get_bezier_glyph_outline(outline, buflen, buf);
7420 break;
7423 default:
7424 FIXME("Unsupported format %d\n", format);
7425 return GDI_ERROR;
7427 *lpgm = gm;
7428 return needed;
7431 static BOOL get_bitmap_text_metrics(GdiFont *font)
7433 FT_Face ft_face = font->ft_face;
7434 FT_WinFNT_HeaderRec winfnt_header;
7435 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
7436 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
7437 font->potm->otmSize = size;
7439 #define TM font->potm->otmTextMetrics
7440 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
7442 TM.tmHeight = winfnt_header.pixel_height;
7443 TM.tmAscent = winfnt_header.ascent;
7444 TM.tmDescent = TM.tmHeight - TM.tmAscent;
7445 TM.tmInternalLeading = winfnt_header.internal_leading;
7446 TM.tmExternalLeading = winfnt_header.external_leading;
7447 TM.tmAveCharWidth = winfnt_header.avg_width;
7448 TM.tmMaxCharWidth = winfnt_header.max_width;
7449 TM.tmWeight = winfnt_header.weight;
7450 TM.tmOverhang = 0;
7451 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
7452 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
7453 TM.tmFirstChar = winfnt_header.first_char;
7454 TM.tmLastChar = winfnt_header.last_char;
7455 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
7456 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
7457 TM.tmItalic = winfnt_header.italic;
7458 TM.tmUnderlined = font->underline;
7459 TM.tmStruckOut = font->strikeout;
7460 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
7461 TM.tmCharSet = winfnt_header.charset;
7463 else
7465 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
7466 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
7467 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7468 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
7469 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
7470 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
7471 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
7472 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
7473 TM.tmOverhang = 0;
7474 TM.tmDigitizedAspectX = 96; /* FIXME */
7475 TM.tmDigitizedAspectY = 96; /* FIXME */
7476 TM.tmFirstChar = 1;
7477 TM.tmLastChar = 255;
7478 TM.tmDefaultChar = 32;
7479 TM.tmBreakChar = 32;
7480 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
7481 TM.tmUnderlined = font->underline;
7482 TM.tmStruckOut = font->strikeout;
7483 /* NB inverted meaning of TMPF_FIXED_PITCH */
7484 TM.tmPitchAndFamily = FT_IS_FIXED_WIDTH(ft_face) ? 0 : TMPF_FIXED_PITCH;
7485 TM.tmCharSet = font->charset;
7487 #undef TM
7489 return TRUE;
7493 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
7495 double scale_x, scale_y;
7497 if (font->aveWidth)
7499 scale_x = (double)font->aveWidth;
7500 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7502 else
7503 scale_x = font->scale_y;
7505 scale_x *= fabs(font->font_desc.matrix.eM11);
7506 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7508 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7509 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7511 SCALE_Y(ptm->tmHeight);
7512 SCALE_Y(ptm->tmAscent);
7513 SCALE_Y(ptm->tmDescent);
7514 SCALE_Y(ptm->tmInternalLeading);
7515 SCALE_Y(ptm->tmExternalLeading);
7516 SCALE_Y(ptm->tmOverhang);
7518 SCALE_X(ptm->tmAveCharWidth);
7519 SCALE_X(ptm->tmMaxCharWidth);
7521 #undef SCALE_X
7522 #undef SCALE_Y
7525 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
7527 double scale_x, scale_y;
7529 if (font->aveWidth)
7531 scale_x = (double)font->aveWidth;
7532 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7534 else
7535 scale_x = font->scale_y;
7537 scale_x *= fabs(font->font_desc.matrix.eM11);
7538 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7540 scale_font_metrics(font, &potm->otmTextMetrics);
7542 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7543 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7545 SCALE_Y(potm->otmAscent);
7546 SCALE_Y(potm->otmDescent);
7547 SCALE_Y(potm->otmLineGap);
7548 SCALE_Y(potm->otmsCapEmHeight);
7549 SCALE_Y(potm->otmsXHeight);
7550 SCALE_Y(potm->otmrcFontBox.top);
7551 SCALE_Y(potm->otmrcFontBox.bottom);
7552 SCALE_X(potm->otmrcFontBox.left);
7553 SCALE_X(potm->otmrcFontBox.right);
7554 SCALE_Y(potm->otmMacAscent);
7555 SCALE_Y(potm->otmMacDescent);
7556 SCALE_Y(potm->otmMacLineGap);
7557 SCALE_X(potm->otmptSubscriptSize.x);
7558 SCALE_Y(potm->otmptSubscriptSize.y);
7559 SCALE_X(potm->otmptSubscriptOffset.x);
7560 SCALE_Y(potm->otmptSubscriptOffset.y);
7561 SCALE_X(potm->otmptSuperscriptSize.x);
7562 SCALE_Y(potm->otmptSuperscriptSize.y);
7563 SCALE_X(potm->otmptSuperscriptOffset.x);
7564 SCALE_Y(potm->otmptSuperscriptOffset.y);
7565 SCALE_Y(potm->otmsStrikeoutSize);
7566 SCALE_Y(potm->otmsStrikeoutPosition);
7567 SCALE_Y(potm->otmsUnderscoreSize);
7568 SCALE_Y(potm->otmsUnderscorePosition);
7570 #undef SCALE_X
7571 #undef SCALE_Y
7574 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
7576 if(!font->potm)
7578 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
7580 /* Make sure that the font has sane width/height ratio */
7581 if (font->aveWidth)
7583 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
7585 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
7586 font->aveWidth = 0;
7590 *ptm = font->potm->otmTextMetrics;
7591 scale_font_metrics(font, ptm);
7592 return TRUE;
7595 static BOOL face_has_symbol_charmap(FT_Face ft_face)
7597 int i;
7599 for(i = 0; i < ft_face->num_charmaps; i++)
7601 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
7602 return TRUE;
7604 return FALSE;
7607 static BOOL get_outline_text_metrics(GdiFont *font)
7609 BOOL ret = FALSE;
7610 FT_Face ft_face = font->ft_face;
7611 UINT needed, lenfam, lensty, lenface, lenfull;
7612 TT_OS2 *pOS2;
7613 TT_HoriHeader *pHori;
7614 TT_Postscript *pPost;
7615 FT_Fixed em_scale;
7616 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
7617 char *cp;
7618 INT ascent, descent;
7619 USHORT windescent;
7621 TRACE("font=%p\n", font);
7623 if(!FT_IS_SCALABLE(ft_face))
7624 return FALSE;
7626 needed = sizeof(*font->potm);
7628 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
7629 family_nameW = strdupW(font->name);
7631 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
7632 if (!style_nameW)
7634 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
7635 style_nameW = towstr( CP_ACP, ft_face->style_name );
7637 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
7639 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
7640 if (!face_nameW)
7642 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
7643 face_nameW = strdupW(font->name);
7645 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
7646 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
7648 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
7649 if (!full_nameW)
7651 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
7652 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
7653 full_nameW = strdupW(fake_nameW);
7655 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
7657 /* These names should be read from the TT name table */
7659 /* length of otmpFamilyName */
7660 needed += lenfam;
7662 /* length of otmpFaceName */
7663 needed += lenface;
7665 /* length of otmpStyleName */
7666 needed += lensty;
7668 /* length of otmpFullName */
7669 needed += lenfull;
7672 em_scale = (FT_Fixed)MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
7674 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
7675 if(!pOS2) {
7676 FIXME("Can't find OS/2 table - not TT font?\n");
7677 goto end;
7680 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
7681 if(!pHori) {
7682 FIXME("Can't find HHEA table - not TT font?\n");
7683 goto end;
7686 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
7688 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",
7689 pOS2->usWinAscent, pOS2->usWinDescent,
7690 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
7691 pOS2->xAvgCharWidth,
7692 ft_face->ascender, ft_face->descender, ft_face->height,
7693 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
7694 ft_face->bbox.yMax, ft_face->bbox.yMin);
7696 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
7697 font->potm->otmSize = needed;
7699 #define TM font->potm->otmTextMetrics
7701 windescent = get_fixed_windescent(pOS2->usWinDescent);
7702 if(pOS2->usWinAscent + windescent == 0) {
7703 ascent = pHori->Ascender;
7704 descent = -pHori->Descender;
7705 } else {
7706 ascent = pOS2->usWinAscent;
7707 descent = windescent;
7710 font->ntmCellHeight = ascent + descent;
7711 font->ntmAvgWidth = pOS2->xAvgCharWidth;
7713 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7714 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7716 if(font->yMax) {
7717 TM.tmAscent = font->yMax;
7718 TM.tmDescent = -font->yMin;
7719 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
7720 } else {
7721 TM.tmAscent = SCALE_Y(ascent);
7722 TM.tmDescent = SCALE_Y(descent);
7723 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
7726 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7728 /* MSDN says:
7729 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7731 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
7732 ((ascent + descent) -
7733 (pHori->Ascender - pHori->Descender))));
7735 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
7736 if (TM.tmAveCharWidth == 0) {
7737 TM.tmAveCharWidth = 1;
7739 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
7740 TM.tmWeight = FW_REGULAR;
7741 if (font->fake_bold) {
7742 TM.tmAveCharWidth++;
7743 TM.tmMaxCharWidth++;
7744 TM.tmWeight = FW_BOLD;
7746 else
7748 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
7750 if (pOS2->usWeightClass > FW_MEDIUM)
7751 TM.tmWeight = pOS2->usWeightClass;
7753 else if (pOS2->usWeightClass <= FW_MEDIUM)
7754 TM.tmWeight = pOS2->usWeightClass;
7756 TM.tmOverhang = 0;
7757 TM.tmDigitizedAspectX = 96; /* FIXME */
7758 TM.tmDigitizedAspectY = 96; /* FIXME */
7759 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7760 * symbol range to 0 - f0ff
7763 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
7765 TM.tmFirstChar = 0;
7766 switch(GetACP())
7768 case 1255: /* Hebrew */
7769 TM.tmLastChar = 0xf896;
7770 break;
7771 case 1257: /* Baltic */
7772 TM.tmLastChar = 0xf8fd;
7773 break;
7774 default:
7775 TM.tmLastChar = 0xf0ff;
7777 TM.tmBreakChar = 0x20;
7778 TM.tmDefaultChar = 0x1f;
7780 else
7782 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
7783 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
7785 if(pOS2->usFirstCharIndex <= 1)
7786 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
7787 else if (pOS2->usFirstCharIndex > 0xff)
7788 TM.tmBreakChar = 0x20;
7789 else
7790 TM.tmBreakChar = pOS2->usFirstCharIndex;
7791 TM.tmDefaultChar = TM.tmBreakChar - 1;
7793 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
7794 TM.tmUnderlined = font->underline;
7795 TM.tmStruckOut = font->strikeout;
7797 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7798 if(!FT_IS_FIXED_WIDTH(ft_face) &&
7799 (pOS2->version == 0xFFFFU ||
7800 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
7801 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
7802 else
7803 TM.tmPitchAndFamily = 0;
7805 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
7807 case PAN_FAMILY_SCRIPT:
7808 TM.tmPitchAndFamily |= FF_SCRIPT;
7809 break;
7811 case PAN_FAMILY_DECORATIVE:
7812 TM.tmPitchAndFamily |= FF_DECORATIVE;
7813 break;
7815 case PAN_ANY:
7816 case PAN_NO_FIT:
7817 case PAN_FAMILY_TEXT_DISPLAY:
7818 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
7819 /* which is clearly not what the panose spec says. */
7820 default:
7821 if(TM.tmPitchAndFamily == 0 || /* fixed */
7822 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
7823 TM.tmPitchAndFamily = FF_MODERN;
7824 else
7826 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
7828 case PAN_ANY:
7829 case PAN_NO_FIT:
7830 default:
7831 TM.tmPitchAndFamily |= FF_DONTCARE;
7832 break;
7834 case PAN_SERIF_COVE:
7835 case PAN_SERIF_OBTUSE_COVE:
7836 case PAN_SERIF_SQUARE_COVE:
7837 case PAN_SERIF_OBTUSE_SQUARE_COVE:
7838 case PAN_SERIF_SQUARE:
7839 case PAN_SERIF_THIN:
7840 case PAN_SERIF_BONE:
7841 case PAN_SERIF_EXAGGERATED:
7842 case PAN_SERIF_TRIANGLE:
7843 TM.tmPitchAndFamily |= FF_ROMAN;
7844 break;
7846 case PAN_SERIF_NORMAL_SANS:
7847 case PAN_SERIF_OBTUSE_SANS:
7848 case PAN_SERIF_PERP_SANS:
7849 case PAN_SERIF_FLARED:
7850 case PAN_SERIF_ROUNDED:
7851 TM.tmPitchAndFamily |= FF_SWISS;
7852 break;
7855 break;
7858 if(FT_IS_SCALABLE(ft_face))
7859 TM.tmPitchAndFamily |= TMPF_VECTOR;
7861 if(FT_IS_SFNT(ft_face))
7863 if (font->ntmFlags & NTM_PS_OPENTYPE)
7864 TM.tmPitchAndFamily |= TMPF_DEVICE;
7865 else
7866 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
7869 TM.tmCharSet = font->charset;
7871 font->potm->otmFiller = 0;
7872 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
7873 font->potm->otmfsSelection = pOS2->fsSelection;
7874 if (font->fake_italic)
7875 font->potm->otmfsSelection |= 1;
7876 if (font->fake_bold)
7877 font->potm->otmfsSelection |= 1 << 5;
7878 font->potm->otmfsType = pOS2->fsType;
7879 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
7880 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
7881 font->potm->otmItalicAngle = 0; /* POST table */
7882 font->potm->otmEMSquare = ft_face->units_per_EM;
7883 font->potm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
7884 font->potm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
7885 font->potm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
7886 font->potm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
7887 font->potm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
7888 font->potm->otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
7889 font->potm->otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
7890 font->potm->otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
7891 font->potm->otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
7892 font->potm->otmMacAscent = TM.tmAscent;
7893 font->potm->otmMacDescent = -TM.tmDescent;
7894 font->potm->otmMacLineGap = font->potm->otmLineGap;
7895 font->potm->otmusMinimumPPEM = 0; /* TT Header */
7896 font->potm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
7897 font->potm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
7898 font->potm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
7899 font->potm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
7900 font->potm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
7901 font->potm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
7902 font->potm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
7903 font->potm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
7904 font->potm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
7905 font->potm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
7906 if(!pPost) {
7907 font->potm->otmsUnderscoreSize = 0;
7908 font->potm->otmsUnderscorePosition = 0;
7909 } else {
7910 font->potm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
7911 font->potm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
7913 #undef SCALE_X
7914 #undef SCALE_Y
7915 #undef TM
7917 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7918 cp = (char*)font->potm + sizeof(*font->potm);
7919 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
7920 strcpyW((WCHAR*)cp, family_nameW);
7921 cp += lenfam;
7922 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
7923 strcpyW((WCHAR*)cp, style_nameW);
7924 cp += lensty;
7925 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7926 strcpyW((WCHAR*)cp, face_nameW);
7927 cp += lenface;
7928 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
7929 strcpyW((WCHAR*)cp, full_nameW);
7930 ret = TRUE;
7932 end:
7933 HeapFree(GetProcessHeap(), 0, style_nameW);
7934 HeapFree(GetProcessHeap(), 0, family_nameW);
7935 HeapFree(GetProcessHeap(), 0, face_nameW);
7936 HeapFree(GetProcessHeap(), 0, full_nameW);
7937 return ret;
7940 /*************************************************************
7941 * freetype_GetGlyphOutline
7943 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
7944 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7946 struct freetype_physdev *physdev = get_freetype_dev( dev );
7947 DWORD ret;
7948 ABC abc;
7950 if (!physdev->font)
7952 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
7953 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
7956 GDI_CheckNotLock();
7957 EnterCriticalSection( &freetype_cs );
7958 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
7959 LeaveCriticalSection( &freetype_cs );
7960 return ret;
7963 /*************************************************************
7964 * freetype_GetTextMetrics
7966 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
7968 struct freetype_physdev *physdev = get_freetype_dev( dev );
7969 BOOL ret;
7971 if (!physdev->font)
7973 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
7974 return dev->funcs->pGetTextMetrics( dev, metrics );
7977 GDI_CheckNotLock();
7978 EnterCriticalSection( &freetype_cs );
7979 ret = get_text_metrics( physdev->font, metrics );
7980 LeaveCriticalSection( &freetype_cs );
7981 return ret;
7984 /*************************************************************
7985 * freetype_GetOutlineTextMetrics
7987 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
7989 struct freetype_physdev *physdev = get_freetype_dev( dev );
7990 UINT ret = 0;
7992 if (!physdev->font)
7994 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
7995 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
7998 TRACE("font=%p\n", physdev->font);
8000 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
8002 GDI_CheckNotLock();
8003 EnterCriticalSection( &freetype_cs );
8005 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
8007 if(potm && cbSize >= physdev->font->potm->otmSize)
8009 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
8010 scale_outline_font_metrics(physdev->font, potm);
8012 ret = physdev->font->potm->otmSize;
8014 LeaveCriticalSection( &freetype_cs );
8015 return ret;
8018 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
8020 child->font = alloc_font();
8021 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
8022 if(!child->font->ft_face)
8024 free_font(child->font);
8025 child->font = NULL;
8026 return FALSE;
8029 child->font->font_desc = font->font_desc;
8030 child->font->ntmFlags = child->face->ntmFlags;
8031 child->font->orientation = font->orientation;
8032 child->font->scale_y = font->scale_y;
8033 child->font->name = strdupW(child->face->family->FamilyName);
8034 child->font->base_font = font;
8035 TRACE("created child font %p for base %p\n", child->font, font);
8036 return TRUE;
8039 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL* vert)
8041 FT_UInt g,o;
8042 CHILD_FONT *child_font;
8044 if(font->base_font)
8045 font = font->base_font;
8047 *linked_font = font;
8049 if((*glyph = get_glyph_index(font, c)))
8051 o = *glyph;
8052 *glyph = get_GSUB_vert_glyph(font, *glyph);
8053 *vert = (o != *glyph);
8054 return TRUE;
8057 if (c < 32) goto done; /* don't check linked fonts for control characters */
8059 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
8061 if(!child_font->font)
8062 if(!load_child_font(font, child_font))
8063 continue;
8065 if(!child_font->font->ft_face)
8066 continue;
8067 g = get_glyph_index(child_font->font, c);
8068 o = g;
8069 g = get_GSUB_vert_glyph(child_font->font, g);
8070 if(g)
8072 *glyph = g;
8073 *linked_font = child_font->font;
8074 *vert = (o != g);
8075 return TRUE;
8079 done:
8080 *vert = FALSE;
8081 return FALSE;
8084 /*************************************************************
8085 * freetype_GetCharWidth
8087 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
8089 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8090 UINT c;
8091 GLYPHMETRICS gm;
8092 ABC abc;
8093 struct freetype_physdev *physdev = get_freetype_dev( dev );
8095 if (!physdev->font)
8097 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
8098 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
8101 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
8103 GDI_CheckNotLock();
8104 EnterCriticalSection( &freetype_cs );
8105 for(c = firstChar; c <= lastChar; c++) {
8106 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
8107 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
8109 LeaveCriticalSection( &freetype_cs );
8110 return TRUE;
8113 /*************************************************************
8114 * freetype_GetCharABCWidths
8116 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
8118 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8119 UINT c;
8120 GLYPHMETRICS gm;
8121 struct freetype_physdev *physdev = get_freetype_dev( dev );
8123 if (!physdev->font)
8125 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
8126 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
8129 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
8131 GDI_CheckNotLock();
8132 EnterCriticalSection( &freetype_cs );
8134 for(c = firstChar; c <= lastChar; c++, buffer++)
8135 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
8137 LeaveCriticalSection( &freetype_cs );
8138 return TRUE;
8141 /*************************************************************
8142 * freetype_GetCharABCWidthsI
8144 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
8146 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8147 UINT c;
8148 GLYPHMETRICS gm;
8149 struct freetype_physdev *physdev = get_freetype_dev( dev );
8151 if (!physdev->font)
8153 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
8154 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
8157 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
8158 return FALSE;
8160 GDI_CheckNotLock();
8161 EnterCriticalSection( &freetype_cs );
8163 for(c = 0; c < count; c++, buffer++)
8164 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
8165 &gm, buffer, 0, NULL, &identity );
8167 LeaveCriticalSection( &freetype_cs );
8168 return TRUE;
8171 /*************************************************************
8172 * freetype_GetTextExtentExPoint
8174 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
8176 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8177 INT idx, pos;
8178 ABC abc;
8179 GLYPHMETRICS gm;
8180 struct freetype_physdev *physdev = get_freetype_dev( dev );
8182 if (!physdev->font)
8184 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
8185 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
8188 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
8190 GDI_CheckNotLock();
8191 EnterCriticalSection( &freetype_cs );
8193 for (idx = pos = 0; idx < count; idx++)
8195 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
8196 pos += abc.abcA + abc.abcB + abc.abcC;
8197 dxs[idx] = pos;
8200 LeaveCriticalSection( &freetype_cs );
8201 return TRUE;
8204 /*************************************************************
8205 * freetype_GetTextExtentExPointI
8207 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
8209 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8210 INT idx, pos;
8211 ABC abc;
8212 GLYPHMETRICS gm;
8213 struct freetype_physdev *physdev = get_freetype_dev( dev );
8215 if (!physdev->font)
8217 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
8218 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
8221 TRACE("%p, %p, %d\n", physdev->font, indices, count);
8223 GDI_CheckNotLock();
8224 EnterCriticalSection( &freetype_cs );
8226 for (idx = pos = 0; idx < count; idx++)
8228 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
8229 &gm, &abc, 0, NULL, &identity );
8230 pos += abc.abcA + abc.abcB + abc.abcC;
8231 dxs[idx] = pos;
8234 LeaveCriticalSection( &freetype_cs );
8235 return TRUE;
8238 /*************************************************************
8239 * freetype_GetFontData
8241 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
8243 struct freetype_physdev *physdev = get_freetype_dev( dev );
8245 if (!physdev->font)
8247 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
8248 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
8251 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
8252 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
8253 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
8255 return get_font_data( physdev->font, table, offset, buf, cbData );
8258 /*************************************************************
8259 * freetype_GetTextFace
8261 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
8263 INT n;
8264 struct freetype_physdev *physdev = get_freetype_dev( dev );
8266 if (!physdev->font)
8268 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
8269 return dev->funcs->pGetTextFace( dev, count, str );
8272 n = strlenW(physdev->font->name) + 1;
8273 if (str)
8275 lstrcpynW(str, physdev->font->name, count);
8276 n = min(count, n);
8278 return n;
8281 /*************************************************************
8282 * freetype_GetTextCharsetInfo
8284 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
8286 struct freetype_physdev *physdev = get_freetype_dev( dev );
8288 if (!physdev->font)
8290 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
8291 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
8293 if (fs) *fs = physdev->font->fs;
8294 return physdev->font->charset;
8297 /* Retrieve a list of supported Unicode ranges for a given font.
8298 * Can be called with NULL gs to calculate the buffer size. Returns
8299 * the number of ranges found.
8301 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
8303 DWORD num_ranges = 0;
8305 if (face->charmap->encoding == FT_ENCODING_UNICODE)
8307 FT_UInt glyph_code;
8308 FT_ULong char_code, char_code_prev;
8310 glyph_code = 0;
8311 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
8313 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
8314 face->num_glyphs, glyph_code, char_code);
8316 if (!glyph_code) return 0;
8318 if (gs)
8320 gs->ranges[0].wcLow = (USHORT)char_code;
8321 gs->ranges[0].cGlyphs = 0;
8322 gs->cGlyphsSupported = 0;
8325 num_ranges = 1;
8326 while (glyph_code)
8328 if (char_code < char_code_prev)
8330 ERR("expected increasing char code from FT_Get_Next_Char\n");
8331 return 0;
8333 if (char_code - char_code_prev > 1)
8335 num_ranges++;
8336 if (gs)
8338 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
8339 gs->ranges[num_ranges - 1].cGlyphs = 1;
8340 gs->cGlyphsSupported++;
8343 else if (gs)
8345 gs->ranges[num_ranges - 1].cGlyphs++;
8346 gs->cGlyphsSupported++;
8348 char_code_prev = char_code;
8349 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
8352 else
8353 FIXME("encoding %u not supported\n", face->charmap->encoding);
8355 return num_ranges;
8358 /*************************************************************
8359 * freetype_GetFontUnicodeRanges
8361 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
8363 struct freetype_physdev *physdev = get_freetype_dev( dev );
8364 DWORD size, num_ranges;
8366 if (!physdev->font)
8368 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
8369 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
8372 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
8373 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
8374 if (glyphset)
8376 glyphset->cbThis = size;
8377 glyphset->cRanges = num_ranges;
8378 glyphset->flAccel = 0;
8380 return size;
8383 /*************************************************************
8384 * freetype_FontIsLinked
8386 static BOOL freetype_FontIsLinked( PHYSDEV dev )
8388 struct freetype_physdev *physdev = get_freetype_dev( dev );
8389 BOOL ret;
8391 if (!physdev->font)
8393 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
8394 return dev->funcs->pFontIsLinked( dev );
8397 GDI_CheckNotLock();
8398 EnterCriticalSection( &freetype_cs );
8399 ret = !list_empty(&physdev->font->child_fonts);
8400 LeaveCriticalSection( &freetype_cs );
8401 return ret;
8404 /*************************************************************************
8405 * GetRasterizerCaps (GDI32.@)
8407 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8409 lprs->nSize = sizeof(RASTERIZER_STATUS);
8410 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
8411 lprs->nLanguageID = 0;
8412 return TRUE;
8415 /*************************************************************
8416 * freetype_GetFontRealizationInfo
8418 static BOOL freetype_GetFontRealizationInfo( PHYSDEV dev, void *ptr )
8420 struct freetype_physdev *physdev = get_freetype_dev( dev );
8421 struct font_realization_info *info = ptr;
8423 if (!physdev->font)
8425 dev = GET_NEXT_PHYSDEV( dev, pGetFontRealizationInfo );
8426 return dev->funcs->pGetFontRealizationInfo( dev, ptr );
8429 TRACE("(%p, %p)\n", physdev->font, info);
8431 info->flags = 1;
8432 if(FT_IS_SCALABLE(physdev->font->ft_face))
8433 info->flags |= 2;
8435 info->cache_num = physdev->font->cache_num;
8436 info->instance_id = physdev->font->instance_id;
8437 if (info->size == sizeof(*info))
8439 info->unk = 0;
8440 info->face_index = physdev->font->ft_face->face_index;
8441 info->simulations = 0;
8442 if (physdev->font->fake_bold)
8443 info->simulations |= 0x1;
8444 if (physdev->font->fake_italic)
8445 info->simulations |= 0x2;
8448 return TRUE;
8451 /*************************************************************************
8452 * GetFontFileInfo (GDI32.@)
8454 BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_fileinfo *info, DWORD size, DWORD *needed )
8456 struct font_handle_entry *entry = handle_entry( instance_id );
8457 const GdiFont *font;
8459 if (!entry)
8461 SetLastError(ERROR_INVALID_PARAMETER);
8462 return FALSE;
8465 font = entry->obj;
8466 *needed = sizeof(*info) + strlenW(font->fileinfo->path) * sizeof(WCHAR);
8467 if (*needed > size)
8469 SetLastError(ERROR_INSUFFICIENT_BUFFER);
8470 return FALSE;
8473 /* path is included too */
8474 memcpy(info, font->fileinfo, *needed);
8475 return TRUE;
8478 /*************************************************************************
8479 * Kerning support for TrueType fonts
8481 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
8483 struct TT_kern_table
8485 USHORT version;
8486 USHORT nTables;
8489 struct TT_kern_subtable
8491 USHORT version;
8492 USHORT length;
8493 union
8495 USHORT word;
8496 struct
8498 USHORT horizontal : 1;
8499 USHORT minimum : 1;
8500 USHORT cross_stream: 1;
8501 USHORT override : 1;
8502 USHORT reserved1 : 4;
8503 USHORT format : 8;
8504 } bits;
8505 } coverage;
8508 struct TT_format0_kern_subtable
8510 USHORT nPairs;
8511 USHORT searchRange;
8512 USHORT entrySelector;
8513 USHORT rangeShift;
8516 struct TT_kern_pair
8518 USHORT left;
8519 USHORT right;
8520 short value;
8523 static DWORD parse_format0_kern_subtable(GdiFont *font,
8524 const struct TT_format0_kern_subtable *tt_f0_ks,
8525 const USHORT *glyph_to_char,
8526 KERNINGPAIR *kern_pair, DWORD cPairs)
8528 USHORT i, nPairs;
8529 const struct TT_kern_pair *tt_kern_pair;
8531 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
8533 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
8535 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8536 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
8537 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
8539 if (!kern_pair || !cPairs)
8540 return nPairs;
8542 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
8544 nPairs = min(nPairs, cPairs);
8546 for (i = 0; i < nPairs; i++)
8548 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
8549 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
8550 /* this algorithm appears to better match what Windows does */
8551 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
8552 if (kern_pair->iKernAmount < 0)
8554 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
8555 kern_pair->iKernAmount -= font->ppem;
8557 else if (kern_pair->iKernAmount > 0)
8559 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
8560 kern_pair->iKernAmount += font->ppem;
8562 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
8564 TRACE("left %u right %u value %d\n",
8565 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
8567 kern_pair++;
8569 TRACE("copied %u entries\n", nPairs);
8570 return nPairs;
8573 /*************************************************************
8574 * freetype_GetKerningPairs
8576 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
8578 DWORD length;
8579 void *buf;
8580 const struct TT_kern_table *tt_kern_table;
8581 const struct TT_kern_subtable *tt_kern_subtable;
8582 USHORT i, nTables;
8583 USHORT *glyph_to_char;
8584 GdiFont *font;
8585 struct freetype_physdev *physdev = get_freetype_dev( dev );
8587 if (!(font = physdev->font))
8589 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
8590 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
8593 GDI_CheckNotLock();
8594 EnterCriticalSection( &freetype_cs );
8595 if (font->total_kern_pairs != (DWORD)-1)
8597 if (cPairs && kern_pair)
8599 cPairs = min(cPairs, font->total_kern_pairs);
8600 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8602 else cPairs = font->total_kern_pairs;
8604 LeaveCriticalSection( &freetype_cs );
8605 return cPairs;
8608 font->total_kern_pairs = 0;
8610 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
8612 if (length == GDI_ERROR)
8614 TRACE("no kerning data in the font\n");
8615 LeaveCriticalSection( &freetype_cs );
8616 return 0;
8619 buf = HeapAlloc(GetProcessHeap(), 0, length);
8620 if (!buf)
8622 WARN("Out of memory\n");
8623 LeaveCriticalSection( &freetype_cs );
8624 return 0;
8627 get_font_data(font, MS_KERN_TAG, 0, buf, length);
8629 /* build a glyph index to char code map */
8630 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
8631 if (!glyph_to_char)
8633 WARN("Out of memory allocating a glyph index to char code map\n");
8634 HeapFree(GetProcessHeap(), 0, buf);
8635 LeaveCriticalSection( &freetype_cs );
8636 return 0;
8639 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
8641 FT_UInt glyph_code;
8642 FT_ULong char_code;
8644 glyph_code = 0;
8645 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
8647 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
8648 font->ft_face->num_glyphs, glyph_code, char_code);
8650 while (glyph_code)
8652 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
8654 /* FIXME: This doesn't match what Windows does: it does some fancy
8655 * things with duplicate glyph index to char code mappings, while
8656 * we just avoid overriding existing entries.
8658 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
8659 glyph_to_char[glyph_code] = (USHORT)char_code;
8661 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
8664 else
8666 ULONG n;
8668 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
8669 for (n = 0; n <= 65535; n++)
8670 glyph_to_char[n] = (USHORT)n;
8673 tt_kern_table = buf;
8674 nTables = GET_BE_WORD(tt_kern_table->nTables);
8675 TRACE("version %u, nTables %u\n",
8676 GET_BE_WORD(tt_kern_table->version), nTables);
8678 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
8680 for (i = 0; i < nTables; i++)
8682 struct TT_kern_subtable tt_kern_subtable_copy;
8684 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
8685 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
8686 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
8688 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8689 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
8690 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
8692 /* According to the TrueType specification this is the only format
8693 * that will be properly interpreted by Windows and OS/2
8695 if (tt_kern_subtable_copy.coverage.bits.format == 0)
8697 DWORD new_chunk, old_total = font->total_kern_pairs;
8699 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8700 glyph_to_char, NULL, 0);
8701 font->total_kern_pairs += new_chunk;
8703 if (!font->kern_pairs)
8704 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
8705 font->total_kern_pairs * sizeof(*font->kern_pairs));
8706 else
8707 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
8708 font->total_kern_pairs * sizeof(*font->kern_pairs));
8710 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8711 glyph_to_char, font->kern_pairs + old_total, new_chunk);
8713 else
8714 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
8716 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
8719 HeapFree(GetProcessHeap(), 0, glyph_to_char);
8720 HeapFree(GetProcessHeap(), 0, buf);
8722 if (cPairs && kern_pair)
8724 cPairs = min(cPairs, font->total_kern_pairs);
8725 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8727 else cPairs = font->total_kern_pairs;
8729 LeaveCriticalSection( &freetype_cs );
8730 return cPairs;
8733 static const struct gdi_dc_funcs freetype_funcs =
8735 NULL, /* pAbortDoc */
8736 NULL, /* pAbortPath */
8737 NULL, /* pAlphaBlend */
8738 NULL, /* pAngleArc */
8739 NULL, /* pArc */
8740 NULL, /* pArcTo */
8741 NULL, /* pBeginPath */
8742 NULL, /* pBlendImage */
8743 NULL, /* pChord */
8744 NULL, /* pCloseFigure */
8745 NULL, /* pCreateCompatibleDC */
8746 freetype_CreateDC, /* pCreateDC */
8747 freetype_DeleteDC, /* pDeleteDC */
8748 NULL, /* pDeleteObject */
8749 NULL, /* pDeviceCapabilities */
8750 NULL, /* pEllipse */
8751 NULL, /* pEndDoc */
8752 NULL, /* pEndPage */
8753 NULL, /* pEndPath */
8754 freetype_EnumFonts, /* pEnumFonts */
8755 NULL, /* pEnumICMProfiles */
8756 NULL, /* pExcludeClipRect */
8757 NULL, /* pExtDeviceMode */
8758 NULL, /* pExtEscape */
8759 NULL, /* pExtFloodFill */
8760 NULL, /* pExtSelectClipRgn */
8761 NULL, /* pExtTextOut */
8762 NULL, /* pFillPath */
8763 NULL, /* pFillRgn */
8764 NULL, /* pFlattenPath */
8765 freetype_FontIsLinked, /* pFontIsLinked */
8766 NULL, /* pFrameRgn */
8767 NULL, /* pGdiComment */
8768 NULL, /* pGetBoundsRect */
8769 freetype_GetCharABCWidths, /* pGetCharABCWidths */
8770 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
8771 freetype_GetCharWidth, /* pGetCharWidth */
8772 NULL, /* pGetDeviceCaps */
8773 NULL, /* pGetDeviceGammaRamp */
8774 freetype_GetFontData, /* pGetFontData */
8775 freetype_GetFontRealizationInfo, /* pGetFontRealizationInfo */
8776 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
8777 freetype_GetGlyphIndices, /* pGetGlyphIndices */
8778 freetype_GetGlyphOutline, /* pGetGlyphOutline */
8779 NULL, /* pGetICMProfile */
8780 NULL, /* pGetImage */
8781 freetype_GetKerningPairs, /* pGetKerningPairs */
8782 NULL, /* pGetNearestColor */
8783 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
8784 NULL, /* pGetPixel */
8785 NULL, /* pGetSystemPaletteEntries */
8786 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
8787 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
8788 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
8789 freetype_GetTextFace, /* pGetTextFace */
8790 freetype_GetTextMetrics, /* pGetTextMetrics */
8791 NULL, /* pGradientFill */
8792 NULL, /* pIntersectClipRect */
8793 NULL, /* pInvertRgn */
8794 NULL, /* pLineTo */
8795 NULL, /* pModifyWorldTransform */
8796 NULL, /* pMoveTo */
8797 NULL, /* pOffsetClipRgn */
8798 NULL, /* pOffsetViewportOrg */
8799 NULL, /* pOffsetWindowOrg */
8800 NULL, /* pPaintRgn */
8801 NULL, /* pPatBlt */
8802 NULL, /* pPie */
8803 NULL, /* pPolyBezier */
8804 NULL, /* pPolyBezierTo */
8805 NULL, /* pPolyDraw */
8806 NULL, /* pPolyPolygon */
8807 NULL, /* pPolyPolyline */
8808 NULL, /* pPolygon */
8809 NULL, /* pPolyline */
8810 NULL, /* pPolylineTo */
8811 NULL, /* pPutImage */
8812 NULL, /* pRealizeDefaultPalette */
8813 NULL, /* pRealizePalette */
8814 NULL, /* pRectangle */
8815 NULL, /* pResetDC */
8816 NULL, /* pRestoreDC */
8817 NULL, /* pRoundRect */
8818 NULL, /* pSaveDC */
8819 NULL, /* pScaleViewportExt */
8820 NULL, /* pScaleWindowExt */
8821 NULL, /* pSelectBitmap */
8822 NULL, /* pSelectBrush */
8823 NULL, /* pSelectClipPath */
8824 freetype_SelectFont, /* pSelectFont */
8825 NULL, /* pSelectPalette */
8826 NULL, /* pSelectPen */
8827 NULL, /* pSetArcDirection */
8828 NULL, /* pSetBkColor */
8829 NULL, /* pSetBkMode */
8830 NULL, /* pSetDCBrushColor */
8831 NULL, /* pSetDCPenColor */
8832 NULL, /* pSetDIBColorTable */
8833 NULL, /* pSetDIBitsToDevice */
8834 NULL, /* pSetDeviceClipping */
8835 NULL, /* pSetDeviceGammaRamp */
8836 NULL, /* pSetLayout */
8837 NULL, /* pSetMapMode */
8838 NULL, /* pSetMapperFlags */
8839 NULL, /* pSetPixel */
8840 NULL, /* pSetPolyFillMode */
8841 NULL, /* pSetROP2 */
8842 NULL, /* pSetRelAbs */
8843 NULL, /* pSetStretchBltMode */
8844 NULL, /* pSetTextAlign */
8845 NULL, /* pSetTextCharacterExtra */
8846 NULL, /* pSetTextColor */
8847 NULL, /* pSetTextJustification */
8848 NULL, /* pSetViewportExt */
8849 NULL, /* pSetViewportOrg */
8850 NULL, /* pSetWindowExt */
8851 NULL, /* pSetWindowOrg */
8852 NULL, /* pSetWorldTransform */
8853 NULL, /* pStartDoc */
8854 NULL, /* pStartPage */
8855 NULL, /* pStretchBlt */
8856 NULL, /* pStretchDIBits */
8857 NULL, /* pStrokeAndFillPath */
8858 NULL, /* pStrokePath */
8859 NULL, /* pUnrealizePalette */
8860 NULL, /* pWidenPath */
8861 NULL, /* wine_get_wgl_driver */
8862 GDI_PRIORITY_FONT_DRV /* priority */
8865 #else /* HAVE_FREETYPE */
8867 struct font_fileinfo;
8869 /*************************************************************************/
8871 BOOL WineEngInit(void)
8873 return FALSE;
8876 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8878 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8879 return 1;
8882 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8884 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8885 return TRUE;
8888 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
8890 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
8891 return NULL;
8894 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
8895 LPCWSTR font_file, LPCWSTR font_path )
8897 FIXME("stub\n");
8898 return FALSE;
8901 /*************************************************************************
8902 * GetRasterizerCaps (GDI32.@)
8904 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8906 lprs->nSize = sizeof(RASTERIZER_STATUS);
8907 lprs->wFlags = 0;
8908 lprs->nLanguageID = 0;
8909 return TRUE;
8912 /*************************************************************************
8913 * GetFontFileInfo (GDI32.@)
8915 BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_fileinfo *info, DWORD size, DWORD *needed)
8917 *needed = 0;
8918 return FALSE;
8921 #endif /* HAVE_FREETYPE */