TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blob693a54ddd718756e4f6238e44067d455c5bb45dd
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_Transform);
166 MAKE_FUNCPTR(FT_Vector_Unit);
167 static FT_Error (*pFT_Outline_Embolden)(FT_Outline *, FT_Pos);
168 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
169 #ifdef FT_LCD_FILTER_H
170 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
171 #endif
173 #ifdef SONAME_LIBFONTCONFIG
174 #include <fontconfig/fontconfig.h>
175 MAKE_FUNCPTR(FcConfigSubstitute);
176 MAKE_FUNCPTR(FcFontList);
177 MAKE_FUNCPTR(FcFontSetDestroy);
178 MAKE_FUNCPTR(FcInit);
179 MAKE_FUNCPTR(FcObjectSetAdd);
180 MAKE_FUNCPTR(FcObjectSetCreate);
181 MAKE_FUNCPTR(FcObjectSetDestroy);
182 MAKE_FUNCPTR(FcPatternCreate);
183 MAKE_FUNCPTR(FcPatternDestroy);
184 MAKE_FUNCPTR(FcPatternGetBool);
185 MAKE_FUNCPTR(FcPatternGetInteger);
186 MAKE_FUNCPTR(FcPatternGetString);
187 #endif
189 #undef MAKE_FUNCPTR
191 #ifndef FT_MAKE_TAG
192 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
193 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
194 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
195 #endif
197 #ifndef ft_encoding_none
198 #define FT_ENCODING_NONE ft_encoding_none
199 #endif
200 #ifndef ft_encoding_ms_symbol
201 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
202 #endif
203 #ifndef ft_encoding_unicode
204 #define FT_ENCODING_UNICODE ft_encoding_unicode
205 #endif
206 #ifndef ft_encoding_apple_roman
207 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
208 #endif
210 #ifdef WORDS_BIGENDIAN
211 #define GET_BE_WORD(x) (x)
212 #else
213 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
214 #endif
216 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
217 typedef struct {
218 FT_Short height;
219 FT_Short width;
220 FT_Pos size;
221 FT_Pos x_ppem;
222 FT_Pos y_ppem;
223 FT_Short internal_leading;
224 } Bitmap_Size;
226 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
227 So to let this compile on older versions of FreeType we'll define the
228 new structure here. */
229 typedef struct {
230 FT_Short height, width;
231 FT_Pos size, x_ppem, y_ppem;
232 } My_FT_Bitmap_Size;
234 struct enum_data
236 ENUMLOGFONTEXW elf;
237 NEWTEXTMETRICEXW ntm;
238 DWORD type;
241 typedef struct tagFace {
242 struct list entry;
243 unsigned int refcount;
244 WCHAR *StyleName;
245 WCHAR *FullName;
246 WCHAR *file;
247 dev_t dev;
248 ino_t ino;
249 void *font_data_ptr;
250 DWORD font_data_size;
251 FT_Long face_index;
252 FONTSIGNATURE fs;
253 DWORD ntmFlags;
254 FT_Fixed font_version;
255 BOOL scalable;
256 Bitmap_Size size; /* set if face is a bitmap */
257 DWORD flags; /* ADDFONT flags */
258 struct tagFamily *family;
259 /* Cached data for Enum */
260 struct enum_data *cached_enum_data;
261 } Face;
263 #define ADDFONT_EXTERNAL_FONT 0x01
264 #define ADDFONT_ALLOW_BITMAP 0x02
265 #define ADDFONT_ADD_TO_CACHE 0x04
266 #define ADDFONT_ADD_RESOURCE 0x08 /* added through AddFontResource */
267 #define ADDFONT_VERTICAL_FONT 0x10
268 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
270 typedef struct tagFamily {
271 struct list entry;
272 unsigned int refcount;
273 WCHAR *FamilyName;
274 WCHAR *EnglishName;
275 struct list faces;
276 struct list *replacement;
277 } Family;
279 typedef struct {
280 GLYPHMETRICS gm;
281 ABC abc; /* metrics of the unrotated char */
282 BOOL init;
283 } GM;
285 typedef struct {
286 FLOAT eM11, eM12;
287 FLOAT eM21, eM22;
288 } FMAT2;
290 typedef struct {
291 DWORD hash;
292 LOGFONTW lf;
293 FMAT2 matrix;
294 BOOL can_use_bitmap;
295 } FONT_DESC;
297 typedef struct tagGdiFont GdiFont;
299 #define FIRST_FONT_HANDLE 1
300 #define MAX_FONT_HANDLES 256
302 struct font_handle_entry
304 void *obj;
305 WORD generation; /* generation count for reusing handle values */
308 static struct font_handle_entry font_handles[MAX_FONT_HANDLES];
309 static struct font_handle_entry *next_free;
310 static struct font_handle_entry *next_unused = font_handles;
312 static inline DWORD entry_to_handle( struct font_handle_entry *entry )
314 unsigned int idx = entry - font_handles + FIRST_FONT_HANDLE;
315 return idx | (entry->generation << 16);
318 static inline struct font_handle_entry *handle_entry( DWORD handle )
320 unsigned int idx = LOWORD(handle) - FIRST_FONT_HANDLE;
322 if (idx < MAX_FONT_HANDLES)
324 if (!HIWORD( handle ) || HIWORD( handle ) == font_handles[idx].generation)
325 return &font_handles[idx];
327 if (handle) WARN( "invalid handle 0x%08x\n", handle );
328 return NULL;
331 static DWORD alloc_font_handle( void *obj )
333 struct font_handle_entry *entry;
335 entry = next_free;
336 if (entry)
337 next_free = entry->obj;
338 else if (next_unused < font_handles + MAX_FONT_HANDLES)
339 entry = next_unused++;
340 else
342 ERR( "out of realized font handles\n" );
343 return 0;
345 entry->obj = obj;
346 if (++entry->generation == 0xffff) entry->generation = 1;
347 return entry_to_handle( entry );
350 static void free_font_handle( DWORD handle )
352 struct font_handle_entry *entry;
354 if ((entry = handle_entry( handle )))
356 entry->obj = next_free;
357 next_free = entry;
361 typedef struct {
362 struct list entry;
363 Face *face;
364 GdiFont *font;
365 } CHILD_FONT;
367 struct font_fileinfo {
368 FILETIME writetime;
369 LARGE_INTEGER size;
370 WCHAR path[1];
373 struct tagGdiFont {
374 struct list entry;
375 struct list unused_entry;
376 unsigned int refcount;
377 GM **gm;
378 DWORD gmsize;
379 OUTLINETEXTMETRICW *potm;
380 DWORD total_kern_pairs;
381 KERNINGPAIR *kern_pairs;
382 struct list child_fonts;
384 /* the following members can be accessed without locking, they are never modified after creation */
385 FT_Face ft_face;
386 struct font_mapping *mapping;
387 LPWSTR name;
388 int charset;
389 int codepage;
390 BOOL fake_italic;
391 BOOL fake_bold;
392 BYTE underline;
393 BYTE strikeout;
394 INT orientation;
395 FONT_DESC font_desc;
396 LONG aveWidth, ppem;
397 double scale_y;
398 SHORT yMax;
399 SHORT yMin;
400 DWORD ntmFlags;
401 DWORD aa_flags;
402 UINT ntmCellHeight, ntmAvgWidth;
403 FONTSIGNATURE fs;
404 GdiFont *base_font;
405 VOID *GSUB_Table;
406 const VOID *vert_feature;
407 DWORD cache_num;
408 DWORD instance_id;
409 struct font_fileinfo *fileinfo;
412 typedef struct {
413 struct list entry;
414 const WCHAR *font_name;
415 FONTSIGNATURE fs;
416 struct list links;
417 } SYSTEM_LINKS;
419 struct enum_charset_element {
420 DWORD mask;
421 DWORD charset;
422 WCHAR name[LF_FACESIZE];
425 struct enum_charset_list {
426 DWORD total;
427 struct enum_charset_element element[32];
430 #define GM_BLOCK_SIZE 128
431 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
433 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
434 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
435 static unsigned int unused_font_count;
436 #define UNUSED_CACHE_SIZE 10
437 static struct list system_links = LIST_INIT(system_links);
439 static struct list font_subst_list = LIST_INIT(font_subst_list);
441 static struct list font_list = LIST_INIT(font_list);
443 struct freetype_physdev
445 struct gdi_physdev dev;
446 GdiFont *font;
449 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
451 return (struct freetype_physdev *)dev;
454 static const struct gdi_dc_funcs freetype_funcs;
456 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
457 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
458 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
460 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
461 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
462 'W','i','n','d','o','w','s','\\',
463 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
464 'F','o','n','t','s','\0'};
466 static const WCHAR winnt_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',' ','N','T','\\',
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 system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
472 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
473 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
474 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
476 static const WCHAR * const SystemFontValues[] = {
477 System_Value,
478 OEMFont_Value,
479 FixedSys_Value,
480 NULL
483 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
484 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
486 /* Interesting and well-known (frequently-assumed!) font names */
487 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
488 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 };
489 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
490 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
491 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
492 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
493 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
494 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
496 static const WCHAR arial[] = {'A','r','i','a','l',0};
497 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
498 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};
499 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};
500 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
501 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
502 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
503 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
504 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
505 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
507 static const WCHAR *default_serif_list[] =
509 times_new_roman,
510 liberation_serif,
511 bitstream_vera_serif,
512 NULL
515 static const WCHAR *default_fixed_list[] =
517 courier_new,
518 liberation_mono,
519 bitstream_vera_sans_mono,
520 NULL
523 static const WCHAR *default_sans_list[] =
525 arial,
526 liberation_sans,
527 bitstream_vera_sans,
528 NULL
531 typedef struct {
532 WCHAR *name;
533 INT charset;
534 } NameCs;
536 typedef struct tagFontSubst {
537 struct list entry;
538 NameCs from;
539 NameCs to;
540 } FontSubst;
542 /* Registry font cache key and value names */
543 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
544 'F','o','n','t','s',0};
545 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
546 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
547 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
548 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
549 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
550 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
551 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
552 static const WCHAR face_size_value[] = {'S','i','z','e',0};
553 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
554 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
555 static const WCHAR face_flags_value[] = {'F','l','a','g','s',0};
556 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
557 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
558 static const WCHAR face_file_name_value[] = {'F','i','l','e',' ','N','a','m','e','\0'};
559 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
562 struct font_mapping
564 struct list entry;
565 int refcount;
566 dev_t dev;
567 ino_t ino;
568 void *data;
569 size_t size;
572 static struct list mappings_list = LIST_INIT( mappings_list );
574 static UINT default_aa_flags;
575 static HKEY hkey_font_cache;
576 static BOOL antialias_fakes = TRUE;
578 static CRITICAL_SECTION freetype_cs;
579 static CRITICAL_SECTION_DEBUG critsect_debug =
581 0, 0, &freetype_cs,
582 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
583 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
585 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
587 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
589 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
590 static BOOL use_default_fallback = FALSE;
592 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL *vert);
593 static BOOL get_outline_text_metrics(GdiFont *font);
594 static BOOL get_bitmap_text_metrics(GdiFont *font);
595 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
596 static void remove_face_from_cache( Face *face );
598 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
599 'W','i','n','d','o','w','s',' ','N','T','\\',
600 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
601 'S','y','s','t','e','m','L','i','n','k',0};
603 /****************************************
604 * Notes on .fon files
606 * The fonts System, FixedSys and Terminal are special. There are typically multiple
607 * versions installed for different resolutions and codepages. Windows stores which one to use
608 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
609 * Key Meaning
610 * FIXEDFON.FON FixedSys
611 * FONTS.FON System
612 * OEMFONT.FON Terminal
613 * LogPixels Current dpi set by the display control panel applet
614 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
615 * also has a LogPixels value that appears to mirror this)
617 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
618 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
619 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
620 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
621 * so that makes sense.
623 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
624 * to be mapped into the registry on Windows 2000 at least).
625 * I have
626 * woafont=app850.fon
627 * ega80woa.fon=ega80850.fon
628 * ega40woa.fon=ega40850.fon
629 * cga80woa.fon=cga80850.fon
630 * cga40woa.fon=cga40850.fon
633 /* These are all structures needed for the GSUB table */
635 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
637 typedef struct {
638 DWORD version;
639 WORD ScriptList;
640 WORD FeatureList;
641 WORD LookupList;
642 } GSUB_Header;
644 typedef struct {
645 CHAR ScriptTag[4];
646 WORD Script;
647 } GSUB_ScriptRecord;
649 typedef struct {
650 WORD ScriptCount;
651 GSUB_ScriptRecord ScriptRecord[1];
652 } GSUB_ScriptList;
654 typedef struct {
655 CHAR LangSysTag[4];
656 WORD LangSys;
657 } GSUB_LangSysRecord;
659 typedef struct {
660 WORD DefaultLangSys;
661 WORD LangSysCount;
662 GSUB_LangSysRecord LangSysRecord[1];
663 } GSUB_Script;
665 typedef struct {
666 WORD LookupOrder; /* Reserved */
667 WORD ReqFeatureIndex;
668 WORD FeatureCount;
669 WORD FeatureIndex[1];
670 } GSUB_LangSys;
672 typedef struct {
673 CHAR FeatureTag[4];
674 WORD Feature;
675 } GSUB_FeatureRecord;
677 typedef struct {
678 WORD FeatureCount;
679 GSUB_FeatureRecord FeatureRecord[1];
680 } GSUB_FeatureList;
682 typedef struct {
683 WORD FeatureParams; /* Reserved */
684 WORD LookupCount;
685 WORD LookupListIndex[1];
686 } GSUB_Feature;
688 typedef struct {
689 WORD LookupCount;
690 WORD Lookup[1];
691 } GSUB_LookupList;
693 typedef struct {
694 WORD LookupType;
695 WORD LookupFlag;
696 WORD SubTableCount;
697 WORD SubTable[1];
698 } GSUB_LookupTable;
700 typedef struct {
701 WORD CoverageFormat;
702 WORD GlyphCount;
703 WORD GlyphArray[1];
704 } GSUB_CoverageFormat1;
706 typedef struct {
707 WORD Start;
708 WORD End;
709 WORD StartCoverageIndex;
710 } GSUB_RangeRecord;
712 typedef struct {
713 WORD CoverageFormat;
714 WORD RangeCount;
715 GSUB_RangeRecord RangeRecord[1];
716 } GSUB_CoverageFormat2;
718 typedef struct {
719 WORD SubstFormat; /* = 1 */
720 WORD Coverage;
721 WORD DeltaGlyphID;
722 } GSUB_SingleSubstFormat1;
724 typedef struct {
725 WORD SubstFormat; /* = 2 */
726 WORD Coverage;
727 WORD GlyphCount;
728 WORD Substitute[1];
729 }GSUB_SingleSubstFormat2;
731 #ifdef HAVE_CARBON_CARBON_H
732 static char *find_cache_dir(void)
734 FSRef ref;
735 OSErr err;
736 static char cached_path[MAX_PATH];
737 static const char *wine = "/Wine", *fonts = "/Fonts";
739 if(*cached_path) return cached_path;
741 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
742 if(err != noErr)
744 WARN("can't create cached data folder\n");
745 return NULL;
747 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
748 if(err != noErr)
750 WARN("can't create cached data path\n");
751 *cached_path = '\0';
752 return NULL;
754 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
756 ERR("Could not create full path\n");
757 *cached_path = '\0';
758 return NULL;
760 strcat(cached_path, wine);
762 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
764 WARN("Couldn't mkdir %s\n", cached_path);
765 *cached_path = '\0';
766 return NULL;
768 strcat(cached_path, fonts);
769 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
771 WARN("Couldn't mkdir %s\n", cached_path);
772 *cached_path = '\0';
773 return NULL;
775 return cached_path;
778 /******************************************************************
779 * expand_mac_font
781 * Extracts individual TrueType font files from a Mac suitcase font
782 * and saves them into the user's caches directory (see
783 * find_cache_dir()).
784 * Returns a NULL terminated array of filenames.
786 * We do this because they are apps that try to read ttf files
787 * themselves and they don't like Mac suitcase files.
789 static char **expand_mac_font(const char *path)
791 FSRef ref;
792 SInt16 res_ref;
793 OSStatus s;
794 unsigned int idx;
795 const char *out_dir;
796 const char *filename;
797 int output_len;
798 struct {
799 char **array;
800 unsigned int size, max_size;
801 } ret;
803 TRACE("path %s\n", path);
805 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
806 if(s != noErr)
808 WARN("failed to get ref\n");
809 return NULL;
812 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
813 if(s != noErr)
815 TRACE("no data fork, so trying resource fork\n");
816 res_ref = FSOpenResFile(&ref, fsRdPerm);
817 if(res_ref == -1)
819 TRACE("unable to open resource fork\n");
820 return NULL;
824 ret.size = 0;
825 ret.max_size = 10;
826 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
827 if(!ret.array)
829 CloseResFile(res_ref);
830 return NULL;
833 out_dir = find_cache_dir();
835 filename = strrchr(path, '/');
836 if(!filename) filename = path;
837 else filename++;
839 /* output filename has the form out_dir/filename_%04x.ttf */
840 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
842 UseResFile(res_ref);
843 idx = 1;
844 while(1)
846 FamRec *fam_rec;
847 unsigned short *num_faces_ptr, num_faces, face;
848 AsscEntry *assoc;
849 Handle fond;
850 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
852 fond = Get1IndResource(fond_res, idx);
853 if(!fond) break;
854 TRACE("got fond resource %d\n", idx);
855 HLock(fond);
857 fam_rec = *(FamRec**)fond;
858 num_faces_ptr = (unsigned short *)(fam_rec + 1);
859 num_faces = GET_BE_WORD(*num_faces_ptr);
860 num_faces++;
861 assoc = (AsscEntry*)(num_faces_ptr + 1);
862 TRACE("num faces %04x\n", num_faces);
863 for(face = 0; face < num_faces; face++, assoc++)
865 Handle sfnt;
866 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
867 unsigned short size, font_id;
868 char *output;
870 size = GET_BE_WORD(assoc->fontSize);
871 font_id = GET_BE_WORD(assoc->fontID);
872 if(size != 0)
874 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
875 continue;
878 TRACE("trying to load sfnt id %04x\n", font_id);
879 sfnt = GetResource(sfnt_res, font_id);
880 if(!sfnt)
882 TRACE("can't get sfnt resource %04x\n", font_id);
883 continue;
886 output = HeapAlloc(GetProcessHeap(), 0, output_len);
887 if(output)
889 int fd;
891 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
893 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
894 if(fd != -1 || errno == EEXIST)
896 if(fd != -1)
898 unsigned char *sfnt_data;
900 HLock(sfnt);
901 sfnt_data = *(unsigned char**)sfnt;
902 write(fd, sfnt_data, GetHandleSize(sfnt));
903 HUnlock(sfnt);
904 close(fd);
906 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
908 ret.max_size *= 2;
909 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
911 ret.array[ret.size++] = output;
913 else
915 WARN("unable to create %s\n", output);
916 HeapFree(GetProcessHeap(), 0, output);
919 ReleaseResource(sfnt);
921 HUnlock(fond);
922 ReleaseResource(fond);
923 idx++;
925 CloseResFile(res_ref);
927 return ret.array;
930 #endif /* HAVE_CARBON_CARBON_H */
932 static inline BOOL is_win9x(void)
934 return GetVersion() & 0x80000000;
937 This function builds an FT_Fixed from a double. It fails if the absolute
938 value of the float number is greater than 32768.
940 static inline FT_Fixed FT_FixedFromFloat(double f)
942 return f * 0x10000;
946 This function builds an FT_Fixed from a FIXED. It simply put f.value
947 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
949 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
951 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
954 static BOOL is_hinting_enabled(void)
956 static int enabled = -1;
958 if (enabled == -1)
960 /* Use the >= 2.2.0 function if available */
961 if (pFT_Get_TrueType_Engine_Type)
963 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
964 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
966 else enabled = FALSE;
967 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
969 return enabled;
972 static BOOL is_subpixel_rendering_enabled( void )
974 #ifdef FT_LCD_FILTER_H
975 static int enabled = -1;
976 if (enabled == -1)
978 enabled = (pFT_Library_SetLcdFilter &&
979 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature);
980 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
982 return enabled;
983 #else
984 return FALSE;
985 #endif
989 static const struct list *get_face_list_from_family(const Family *family)
991 if (!list_empty(&family->faces))
992 return &family->faces;
993 else
994 return family->replacement;
997 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
999 Family *family;
1000 Face *face;
1001 const WCHAR *file;
1003 TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
1005 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1007 const struct list *face_list;
1008 if(face_name && strcmpiW(face_name, family->FamilyName))
1009 continue;
1010 face_list = get_face_list_from_family(family);
1011 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
1013 if (!face->file)
1014 continue;
1015 file = strrchrW(face->file, '/');
1016 if(!file)
1017 file = face->file;
1018 else
1019 file++;
1020 if(strcmpiW(file, file_name)) continue;
1021 face->refcount++;
1022 return face;
1025 return NULL;
1028 static Family *find_family_from_name(const WCHAR *name)
1030 Family *family;
1032 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1034 if(!strcmpiW(family->FamilyName, name))
1035 return family;
1038 return NULL;
1041 static Family *find_family_from_any_name(const WCHAR *name)
1043 Family *family;
1045 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1047 if(!strcmpiW(family->FamilyName, name))
1048 return family;
1049 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
1050 return family;
1053 return NULL;
1056 static void DumpSubstList(void)
1058 FontSubst *psub;
1060 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
1062 if(psub->from.charset != -1 || psub->to.charset != -1)
1063 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
1064 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
1065 else
1066 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
1067 debugstr_w(psub->to.name));
1071 static LPWSTR strdupW(LPCWSTR p)
1073 LPWSTR ret;
1074 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
1075 ret = HeapAlloc(GetProcessHeap(), 0, len);
1076 memcpy(ret, p, len);
1077 return ret;
1080 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1081 INT from_charset)
1083 FontSubst *element;
1085 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1087 if(!strcmpiW(element->from.name, from_name) &&
1088 (element->from.charset == from_charset ||
1089 element->from.charset == -1))
1090 return element;
1093 return NULL;
1096 #define ADD_FONT_SUBST_FORCE 1
1098 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1100 FontSubst *from_exist, *to_exist;
1102 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1104 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1106 list_remove(&from_exist->entry);
1107 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
1108 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
1109 HeapFree(GetProcessHeap(), 0, from_exist);
1110 from_exist = NULL;
1113 if(!from_exist)
1115 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1117 if(to_exist)
1119 HeapFree(GetProcessHeap(), 0, subst->to.name);
1120 subst->to.name = strdupW(to_exist->to.name);
1123 list_add_tail(subst_list, &subst->entry);
1125 return TRUE;
1128 HeapFree(GetProcessHeap(), 0, subst->from.name);
1129 HeapFree(GetProcessHeap(), 0, subst->to.name);
1130 HeapFree(GetProcessHeap(), 0, subst);
1131 return FALSE;
1134 static WCHAR *towstr(UINT cp, const char *str)
1136 int len;
1137 WCHAR *wstr;
1139 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1140 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1141 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1142 return wstr;
1145 static char *strWtoA(UINT cp, const WCHAR *str)
1147 int len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL );
1148 char *ret = HeapAlloc( GetProcessHeap(), 0, len );
1149 WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL );
1150 return ret;
1153 static void split_subst_info(NameCs *nc, LPSTR str)
1155 CHAR *p = strrchr(str, ',');
1157 nc->charset = -1;
1158 if(p && *(p+1)) {
1159 nc->charset = strtol(p+1, NULL, 10);
1160 *p = '\0';
1162 nc->name = towstr(CP_ACP, str);
1165 static void LoadSubstList(void)
1167 FontSubst *psub;
1168 HKEY hkey;
1169 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1170 LPSTR value;
1171 LPVOID data;
1173 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1174 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1175 &hkey) == ERROR_SUCCESS) {
1177 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1178 &valuelen, &datalen, NULL, NULL);
1180 valuelen++; /* returned value doesn't include room for '\0' */
1181 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1182 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1184 dlen = datalen;
1185 vlen = valuelen;
1186 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1187 &dlen) == ERROR_SUCCESS) {
1188 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1190 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1191 split_subst_info(&psub->from, value);
1192 split_subst_info(&psub->to, data);
1194 /* Win 2000 doesn't allow mapping between different charsets
1195 or mapping of DEFAULT_CHARSET */
1196 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1197 psub->to.charset == DEFAULT_CHARSET) {
1198 HeapFree(GetProcessHeap(), 0, psub->to.name);
1199 HeapFree(GetProcessHeap(), 0, psub->from.name);
1200 HeapFree(GetProcessHeap(), 0, psub);
1201 } else {
1202 add_font_subst(&font_subst_list, psub, 0);
1204 /* reset dlen and vlen */
1205 dlen = datalen;
1206 vlen = valuelen;
1208 HeapFree(GetProcessHeap(), 0, data);
1209 HeapFree(GetProcessHeap(), 0, value);
1210 RegCloseKey(hkey);
1215 static const LANGID mac_langid_table[] =
1217 MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */
1218 MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */
1219 MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */
1220 MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */
1221 MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */
1222 MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */
1223 MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */
1224 MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */
1225 MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */
1226 MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */
1227 MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */
1228 MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */
1229 MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */
1230 MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */
1231 MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */
1232 MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */
1233 MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */
1234 MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */
1235 MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */
1236 MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
1237 MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */
1238 MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */
1239 MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */
1240 MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */
1241 MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */
1242 MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */
1243 MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */
1244 MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */
1245 MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */
1246 MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */
1247 MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */
1248 MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */
1249 MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */
1250 MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
1251 MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */
1252 MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */
1253 MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */
1254 MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */
1255 MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */
1256 MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */
1257 MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */
1258 0, /* TT_MAC_LANGID_YIDDISH */
1259 MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */
1260 MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */
1261 MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */
1262 MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */
1263 MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */
1264 MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */
1265 MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */
1266 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */
1267 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
1268 MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */
1269 MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */
1270 0, /* TT_MAC_LANGID_MOLDAVIAN */
1271 MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */
1272 MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */
1273 MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */
1274 MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */
1275 MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
1276 MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */
1277 0, /* TT_MAC_LANGID_KURDISH */
1278 MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */
1279 MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */
1280 MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */
1281 MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */
1282 MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */
1283 MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */
1284 MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */
1285 MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */
1286 MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */
1287 MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */
1288 MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */
1289 MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */
1290 MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */
1291 MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */
1292 MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */
1293 MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */
1294 0, /* TT_MAC_LANGID_BURMESE */
1295 MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */
1296 MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */
1297 MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */
1298 MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */
1299 0, /* TT_MAC_LANGID_TAGALOG */
1300 MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
1301 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
1302 MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */
1303 MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */
1304 0, /* TT_MAC_LANGID_GALLA */
1305 0, /* TT_MAC_LANGID_SOMALI */
1306 MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */
1307 0, /* TT_MAC_LANGID_RUANDA */
1308 0, /* TT_MAC_LANGID_RUNDI */
1309 0, /* TT_MAC_LANGID_CHEWA */
1310 MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */
1311 MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */
1312 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
1313 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
1314 MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */
1315 MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */
1316 MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */
1317 0, /* TT_MAC_LANGID_LATIN */
1318 MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */
1319 0, /* TT_MAC_LANGID_GUARANI */
1320 0, /* TT_MAC_LANGID_AYMARA */
1321 MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */
1322 MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */
1323 0, /* TT_MAC_LANGID_DZONGKHA */
1324 0, /* TT_MAC_LANGID_JAVANESE */
1325 0, /* TT_MAC_LANGID_SUNDANESE */
1326 MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */
1327 MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */
1328 MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */
1329 MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */
1330 MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
1331 MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */
1332 MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */
1333 0, /* TT_MAC_LANGID_TONGAN */
1334 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
1335 MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */
1336 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
1339 static inline WORD get_mac_code_page( const FT_SfntName *name )
1341 if (name->encoding_id == TT_MAC_ID_SIMPLIFIED_CHINESE) return 10008; /* special case */
1342 return 10000 + name->encoding_id;
1345 static int match_name_table_language( const FT_SfntName *name, LANGID lang )
1347 LANGID name_lang;
1348 int res = 0;
1350 switch (name->platform_id)
1352 case TT_PLATFORM_MICROSOFT:
1353 res += 5; /* prefer the Microsoft name */
1354 switch (name->encoding_id)
1356 case TT_MS_ID_UNICODE_CS:
1357 case TT_MS_ID_SYMBOL_CS:
1358 name_lang = name->language_id;
1359 break;
1360 default:
1361 return 0;
1363 break;
1364 case TT_PLATFORM_MACINTOSH:
1365 if (!IsValidCodePage( get_mac_code_page( name ))) return 0;
1366 if (name->language_id >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
1367 name_lang = mac_langid_table[name->language_id];
1368 break;
1369 case TT_PLATFORM_APPLE_UNICODE:
1370 res += 2; /* prefer Unicode encodings */
1371 switch (name->encoding_id)
1373 case TT_APPLE_ID_DEFAULT:
1374 case TT_APPLE_ID_ISO_10646:
1375 case TT_APPLE_ID_UNICODE_2_0:
1376 if (name->language_id >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
1377 name_lang = mac_langid_table[name->language_id];
1378 break;
1379 default:
1380 return 0;
1382 break;
1383 default:
1384 return 0;
1386 if (name_lang == lang) res += 30;
1387 else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20;
1388 else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10;
1389 return res;
1392 static WCHAR *copy_name_table_string( const FT_SfntName *name )
1394 WCHAR *ret;
1395 WORD codepage;
1396 int i;
1398 switch (name->platform_id)
1400 case TT_PLATFORM_APPLE_UNICODE:
1401 case TT_PLATFORM_MICROSOFT:
1402 ret = HeapAlloc( GetProcessHeap(), 0, name->string_len + sizeof(WCHAR) );
1403 for (i = 0; i < name->string_len / 2; i++)
1404 ret[i] = (name->string[i * 2] << 8) | name->string[i * 2 + 1];
1405 ret[i] = 0;
1406 return ret;
1407 case TT_PLATFORM_MACINTOSH:
1408 codepage = get_mac_code_page( name );
1409 i = MultiByteToWideChar( codepage, 0, (char *)name->string, name->string_len, NULL, 0 );
1410 ret = HeapAlloc( GetProcessHeap(), 0, (i + 1) * sizeof(WCHAR) );
1411 MultiByteToWideChar( codepage, 0, (char *)name->string, name->string_len, ret, i );
1412 ret[i] = 0;
1413 return ret;
1415 return NULL;
1418 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, LANGID language_id)
1420 FT_SfntName name;
1421 FT_UInt num_names, name_index;
1422 int res, best_lang = 0, best_index = -1;
1424 if (!FT_IS_SFNT(ft_face)) return NULL;
1426 num_names = pFT_Get_Sfnt_Name_Count( ft_face );
1428 for (name_index = 0; name_index < num_names; name_index++)
1430 if (pFT_Get_Sfnt_Name( ft_face, name_index, &name )) continue;
1431 if (name.name_id != name_id) continue;
1432 res = match_name_table_language( &name, language_id );
1433 if (res > best_lang)
1435 best_lang = res;
1436 best_index = name_index;
1440 if (best_index != -1 && !pFT_Get_Sfnt_Name( ft_face, best_index, &name ))
1442 WCHAR *ret = copy_name_table_string( &name );
1443 TRACE( "name %u found platform %u lang %04x %s\n",
1444 name_id, name.platform_id, name.language_id, debugstr_w( ret ));
1445 return ret;
1447 return NULL;
1450 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1452 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1453 if (f1->scalable) return TRUE;
1454 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1455 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1458 static void release_family( Family *family )
1460 if (--family->refcount) return;
1461 assert( list_empty( &family->faces ));
1462 list_remove( &family->entry );
1463 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1464 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1465 HeapFree( GetProcessHeap(), 0, family );
1468 static void release_face( Face *face )
1470 if (--face->refcount) return;
1471 if (face->family)
1473 if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
1474 list_remove( &face->entry );
1475 release_family( face->family );
1477 HeapFree( GetProcessHeap(), 0, face->file );
1478 HeapFree( GetProcessHeap(), 0, face->StyleName );
1479 HeapFree( GetProcessHeap(), 0, face->FullName );
1480 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1481 HeapFree( GetProcessHeap(), 0, face );
1484 static inline int style_order(const Face *face)
1486 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1488 case NTM_REGULAR:
1489 return 0;
1490 case NTM_BOLD:
1491 return 1;
1492 case NTM_ITALIC:
1493 return 2;
1494 case NTM_BOLD | NTM_ITALIC:
1495 return 3;
1496 default:
1497 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1498 debugstr_w(face->family->FamilyName),
1499 debugstr_w(face->StyleName),
1500 face->ntmFlags);
1501 return 9999;
1505 static BOOL insert_face_in_family_list( Face *face, Family *family )
1507 Face *cursor;
1509 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1511 if (faces_equal( face, cursor ))
1513 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1514 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1515 cursor->font_version, face->font_version);
1517 if (face->file && face->dev == cursor->dev && face->ino == cursor->ino)
1519 cursor->refcount++;
1520 TRACE("Font %s already in list, refcount now %d\n",
1521 debugstr_w(face->file), cursor->refcount);
1522 return FALSE;
1524 if (face->font_version <= cursor->font_version)
1526 TRACE("Original font %s is newer so skipping %s\n",
1527 debugstr_w(cursor->file), debugstr_w(face->file));
1528 return FALSE;
1530 else
1532 TRACE("Replacing original %s with %s\n",
1533 debugstr_w(cursor->file), debugstr_w(face->file));
1534 list_add_before( &cursor->entry, &face->entry );
1535 face->family = family;
1536 family->refcount++;
1537 face->refcount++;
1538 release_face( cursor );
1539 return TRUE;
1542 else
1543 TRACE("Adding new %s\n", debugstr_w(face->file));
1545 if (style_order( face ) < style_order( cursor )) break;
1548 list_add_before( &cursor->entry, &face->entry );
1549 face->family = family;
1550 family->refcount++;
1551 face->refcount++;
1552 return TRUE;
1555 /****************************************************************
1556 * NB This function stores the ptrs to the strings to save copying.
1557 * Don't free them after calling.
1559 static Family *create_family( WCHAR *name, WCHAR *english_name )
1561 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1562 family->refcount = 1;
1563 family->FamilyName = name;
1564 family->EnglishName = english_name;
1565 list_init( &family->faces );
1566 family->replacement = &family->faces;
1567 list_add_tail( &font_list, &family->entry );
1569 return family;
1572 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1574 DWORD type, size = sizeof(DWORD);
1576 if (RegQueryValueExW(hkey, value, NULL, &type, (BYTE *)data, &size) ||
1577 type != REG_DWORD || size != sizeof(DWORD))
1579 *data = 0;
1580 return ERROR_BAD_CONFIGURATION;
1582 return ERROR_SUCCESS;
1585 static inline LONG reg_load_ftlong(HKEY hkey, const WCHAR *value, FT_Long *data)
1587 DWORD dw;
1588 LONG ret = reg_load_dword(hkey, value, &dw);
1589 *data = dw;
1590 return ret;
1593 static inline LONG reg_load_ftshort(HKEY hkey, const WCHAR *value, FT_Short *data)
1595 DWORD dw;
1596 LONG ret = reg_load_dword(hkey, value, &dw);
1597 *data = dw;
1598 return ret;
1601 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1603 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1606 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1608 DWORD needed, strike_index = 0;
1609 HKEY hkey_strike;
1611 /* If we have a File Name key then this is a real font, not just the parent
1612 key of a bunch of non-scalable strikes */
1613 needed = buffer_size;
1614 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1616 Face *face;
1617 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1618 face->cached_enum_data = NULL;
1619 face->family = NULL;
1621 face->refcount = 1;
1622 face->file = strdupW( buffer );
1623 face->StyleName = strdupW(face_name);
1625 needed = buffer_size;
1626 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1627 face->FullName = strdupW( buffer );
1628 else
1629 face->FullName = NULL;
1631 reg_load_ftlong(hkey_face, face_index_value, &face->face_index);
1632 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1633 reg_load_ftlong(hkey_face, face_version_value, &face->font_version);
1634 reg_load_dword(hkey_face, face_flags_value, &face->flags);
1636 needed = sizeof(face->fs);
1637 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1639 if(reg_load_ftshort(hkey_face, face_height_value, &face->size.height) != ERROR_SUCCESS)
1641 face->scalable = TRUE;
1642 memset(&face->size, 0, sizeof(face->size));
1644 else
1646 face->scalable = FALSE;
1647 reg_load_ftshort(hkey_face, face_width_value, &face->size.width);
1648 reg_load_ftlong(hkey_face, face_size_value, &face->size.size);
1649 reg_load_ftlong(hkey_face, face_x_ppem_value, &face->size.x_ppem);
1650 reg_load_ftlong(hkey_face, face_y_ppem_value, &face->size.y_ppem);
1651 reg_load_ftshort(hkey_face, face_internal_leading_value, &face->size.internal_leading);
1653 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1654 face->size.height, face->size.width, face->size.size >> 6,
1655 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1658 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1659 face->fs.fsCsb[0], face->fs.fsCsb[1],
1660 face->fs.fsUsb[0], face->fs.fsUsb[1],
1661 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1663 if (insert_face_in_family_list(face, family))
1664 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1666 release_face( face );
1669 /* load bitmap strikes */
1671 needed = buffer_size;
1672 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1674 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1676 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1677 RegCloseKey(hkey_strike);
1679 needed = buffer_size;
1683 /* move vertical fonts after their horizontal counterpart */
1684 /* assumes that font_list is already sorted by family name */
1685 static void reorder_vertical_fonts(void)
1687 Family *family, *next, *vert_family;
1688 struct list *ptr, *vptr;
1689 struct list vertical_families = LIST_INIT( vertical_families );
1691 LIST_FOR_EACH_ENTRY_SAFE( family, next, &font_list, Family, entry )
1693 if (family->FamilyName[0] != '@') continue;
1694 list_remove( &family->entry );
1695 list_add_tail( &vertical_families, &family->entry );
1698 ptr = list_head( &font_list );
1699 vptr = list_head( &vertical_families );
1700 while (ptr && vptr)
1702 family = LIST_ENTRY( ptr, Family, entry );
1703 vert_family = LIST_ENTRY( vptr, Family, entry );
1704 if (strcmpiW( family->FamilyName, vert_family->FamilyName + 1 ) > 0)
1706 list_remove( vptr );
1707 list_add_before( ptr, vptr );
1708 vptr = list_head( &vertical_families );
1710 else ptr = list_next( &font_list, ptr );
1712 list_move_tail( &font_list, &vertical_families );
1715 static void load_font_list_from_cache(HKEY hkey_font_cache)
1717 DWORD size, family_index = 0;
1718 Family *family;
1719 HKEY hkey_family;
1720 WCHAR buffer[4096];
1722 size = sizeof(buffer);
1723 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1725 WCHAR *english_family = NULL;
1726 WCHAR *family_name = strdupW( buffer );
1727 DWORD face_index = 0;
1729 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1730 TRACE("opened family key %s\n", debugstr_w(family_name));
1731 size = sizeof(buffer);
1732 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1733 english_family = strdupW( buffer );
1735 family = create_family(family_name, english_family);
1737 if(english_family)
1739 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1740 subst->from.name = strdupW(english_family);
1741 subst->from.charset = -1;
1742 subst->to.name = strdupW(family_name);
1743 subst->to.charset = -1;
1744 add_font_subst(&font_subst_list, subst, 0);
1747 size = sizeof(buffer);
1748 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1750 WCHAR *face_name = strdupW( buffer );
1751 HKEY hkey_face;
1753 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1755 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1756 RegCloseKey(hkey_face);
1758 HeapFree( GetProcessHeap(), 0, face_name );
1759 size = sizeof(buffer);
1761 RegCloseKey(hkey_family);
1762 release_family( family );
1763 size = sizeof(buffer);
1766 reorder_vertical_fonts();
1769 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1771 LONG ret;
1772 HKEY hkey_wine_fonts;
1774 /* We don't want to create the fonts key as volatile, so open this first */
1775 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1776 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1777 if(ret != ERROR_SUCCESS)
1779 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1780 return ret;
1783 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1784 KEY_ALL_ACCESS, NULL, hkey, disposition);
1785 RegCloseKey(hkey_wine_fonts);
1786 return ret;
1789 static void add_face_to_cache(Face *face)
1791 HKEY hkey_family, hkey_face;
1792 WCHAR *face_key_name;
1794 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1795 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1796 if(face->family->EnglishName)
1797 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1798 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1800 if(face->scalable)
1801 face_key_name = face->StyleName;
1802 else
1804 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1805 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1806 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1808 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1809 &hkey_face, NULL);
1810 if(!face->scalable)
1811 HeapFree(GetProcessHeap(), 0, face_key_name);
1813 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1814 (strlenW(face->file) + 1) * sizeof(WCHAR));
1815 if (face->FullName)
1816 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1817 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1819 reg_save_dword(hkey_face, face_index_value, face->face_index);
1820 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1821 reg_save_dword(hkey_face, face_version_value, face->font_version);
1822 if (face->flags) reg_save_dword(hkey_face, face_flags_value, face->flags);
1824 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1826 if(!face->scalable)
1828 reg_save_dword(hkey_face, face_height_value, face->size.height);
1829 reg_save_dword(hkey_face, face_width_value, face->size.width);
1830 reg_save_dword(hkey_face, face_size_value, face->size.size);
1831 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1832 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1833 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1835 RegCloseKey(hkey_face);
1836 RegCloseKey(hkey_family);
1839 static void remove_face_from_cache( Face *face )
1841 HKEY hkey_family;
1843 RegOpenKeyExW( hkey_font_cache, face->family->FamilyName, 0, KEY_ALL_ACCESS, &hkey_family );
1845 if (face->scalable)
1847 RegDeleteKeyW( hkey_family, face->StyleName );
1849 else
1851 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1852 WCHAR *face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1853 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1854 RegDeleteKeyW( hkey_family, face_key_name );
1855 HeapFree(GetProcessHeap(), 0, face_key_name);
1857 RegCloseKey(hkey_family);
1860 static WCHAR *prepend_at(WCHAR *family)
1862 WCHAR *str;
1864 if (!family)
1865 return NULL;
1867 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1868 str[0] = '@';
1869 strcpyW(str + 1, family);
1870 HeapFree(GetProcessHeap(), 0, family);
1871 return str;
1874 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1876 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT) );
1877 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1879 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1880 if (!*name)
1882 *name = *english;
1883 *english = NULL;
1885 else if (!strcmpiW( *name, *english ))
1887 HeapFree( GetProcessHeap(), 0, *english );
1888 *english = NULL;
1891 if (vertical)
1893 *name = prepend_at( *name );
1894 *english = prepend_at( *english );
1898 static Family *get_family( FT_Face ft_face, BOOL vertical )
1900 Family *family;
1901 WCHAR *name, *english_name;
1903 get_family_names( ft_face, &name, &english_name, vertical );
1905 family = find_family_from_name( name );
1907 if (!family)
1909 family = create_family( name, english_name );
1910 if (english_name)
1912 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1913 subst->from.name = strdupW( english_name );
1914 subst->from.charset = -1;
1915 subst->to.name = strdupW( name );
1916 subst->to.charset = -1;
1917 add_font_subst( &font_subst_list, subst, 0 );
1920 else
1922 HeapFree( GetProcessHeap(), 0, name );
1923 HeapFree( GetProcessHeap(), 0, english_name );
1924 family->refcount++;
1927 return family;
1930 static inline FT_Fixed get_font_version( FT_Face ft_face )
1932 FT_Fixed version = 0;
1933 TT_Header *header;
1935 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1936 if (header) version = header->Font_Revision;
1938 return version;
1941 static inline DWORD get_ntm_flags( FT_Face ft_face )
1943 DWORD flags = 0;
1944 FT_ULong table_size = 0;
1946 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1947 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1948 if (flags == 0) flags = NTM_REGULAR;
1950 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1951 flags |= NTM_PS_OPENTYPE;
1953 return flags;
1956 static inline void get_bitmap_size( FT_Face ft_face, Bitmap_Size *face_size )
1958 My_FT_Bitmap_Size *size;
1959 FT_WinFNT_HeaderRec winfnt_header;
1961 size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1962 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1963 size->height, size->width, size->size >> 6,
1964 size->x_ppem >> 6, size->y_ppem >> 6);
1965 face_size->height = size->height;
1966 face_size->width = size->width;
1967 face_size->size = size->size;
1968 face_size->x_ppem = size->x_ppem;
1969 face_size->y_ppem = size->y_ppem;
1971 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header )) {
1972 face_size->internal_leading = winfnt_header.internal_leading;
1973 if (winfnt_header.external_leading > 0 &&
1974 (face_size->height ==
1975 winfnt_header.pixel_height + winfnt_header.external_leading))
1976 face_size->height = winfnt_header.pixel_height;
1980 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1982 TT_OS2 *os2;
1983 FT_UInt dummy;
1984 CHARSETINFO csi;
1985 FT_WinFNT_HeaderRec winfnt_header;
1986 int i;
1988 memset( fs, 0, sizeof(*fs) );
1990 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1991 if (os2)
1993 fs->fsUsb[0] = os2->ulUnicodeRange1;
1994 fs->fsUsb[1] = os2->ulUnicodeRange2;
1995 fs->fsUsb[2] = os2->ulUnicodeRange3;
1996 fs->fsUsb[3] = os2->ulUnicodeRange4;
1998 if (os2->version == 0)
2000 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
2001 fs->fsCsb[0] = FS_LATIN1;
2002 else
2003 fs->fsCsb[0] = FS_SYMBOL;
2005 else
2007 fs->fsCsb[0] = os2->ulCodePageRange1;
2008 fs->fsCsb[1] = os2->ulCodePageRange2;
2011 else
2013 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
2015 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
2016 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
2017 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
2018 *fs = csi.fs;
2022 if (fs->fsCsb[0] == 0)
2024 /* let's see if we can find any interesting cmaps */
2025 for (i = 0; i < ft_face->num_charmaps; i++)
2027 switch (ft_face->charmaps[i]->encoding)
2029 case FT_ENCODING_UNICODE:
2030 case FT_ENCODING_APPLE_ROMAN:
2031 fs->fsCsb[0] |= FS_LATIN1;
2032 break;
2033 case FT_ENCODING_MS_SYMBOL:
2034 fs->fsCsb[0] |= FS_SYMBOL;
2035 break;
2036 default:
2037 break;
2043 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
2044 DWORD flags )
2046 struct stat st;
2047 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
2049 face->refcount = 1;
2050 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
2051 if (!face->StyleName) face->StyleName = towstr( CP_ACP, ft_face->style_name );
2053 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
2054 if (flags & ADDFONT_VERTICAL_FONT)
2055 face->FullName = prepend_at( face->FullName );
2057 face->dev = 0;
2058 face->ino = 0;
2059 if (file)
2061 face->file = towstr( CP_UNIXCP, file );
2062 face->font_data_ptr = NULL;
2063 face->font_data_size = 0;
2064 if (!stat( file, &st ))
2066 face->dev = st.st_dev;
2067 face->ino = st.st_ino;
2070 else
2072 face->file = NULL;
2073 face->font_data_ptr = font_data_ptr;
2074 face->font_data_size = font_data_size;
2077 face->face_index = face_index;
2078 get_fontsig( ft_face, &face->fs );
2079 face->ntmFlags = get_ntm_flags( ft_face );
2080 face->font_version = get_font_version( ft_face );
2082 if (FT_IS_SCALABLE( ft_face ))
2084 memset( &face->size, 0, sizeof(face->size) );
2085 face->scalable = TRUE;
2087 else
2089 get_bitmap_size( ft_face, &face->size );
2090 face->scalable = FALSE;
2093 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
2094 face->flags = flags;
2095 face->family = NULL;
2096 face->cached_enum_data = NULL;
2098 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
2099 face->fs.fsCsb[0], face->fs.fsCsb[1],
2100 face->fs.fsUsb[0], face->fs.fsUsb[1],
2101 face->fs.fsUsb[2], face->fs.fsUsb[3]);
2103 return face;
2106 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
2107 FT_Long face_index, DWORD flags )
2109 Face *face;
2110 Family *family;
2112 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags );
2113 family = get_family( ft_face, flags & ADDFONT_VERTICAL_FONT );
2114 if (strlenW(family->FamilyName) >= LF_FACESIZE)
2116 WARN("Ignoring %s because name is too long\n", debugstr_w(family->FamilyName));
2117 release_face( face );
2118 release_family( family );
2119 return;
2122 if (insert_face_in_family_list( face, family ))
2124 if (flags & ADDFONT_ADD_TO_CACHE)
2125 add_face_to_cache( face );
2127 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
2128 debugstr_w(face->StyleName));
2130 release_face( face );
2131 release_family( family );
2134 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
2135 FT_Long face_index, BOOL allow_bitmap )
2137 FT_Error err;
2138 TT_OS2 *pOS2;
2139 FT_Face ft_face;
2141 if (file)
2143 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
2144 err = pFT_New_Face(library, file, face_index, &ft_face);
2146 else
2148 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
2149 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
2152 if (err != 0)
2154 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
2155 return NULL;
2158 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
2159 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
2161 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
2162 goto fail;
2165 if (!FT_IS_SFNT( ft_face ))
2167 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
2169 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
2170 goto fail;
2173 else
2175 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
2176 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
2177 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
2179 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
2180 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
2181 goto fail;
2184 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
2185 we don't want to load these. */
2186 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
2188 FT_ULong len = 0;
2190 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
2192 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
2193 goto fail;
2198 if (!ft_face->family_name || !ft_face->style_name)
2200 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
2201 goto fail;
2204 return ft_face;
2205 fail:
2206 pFT_Done_Face( ft_face );
2207 return NULL;
2210 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
2212 FT_Face ft_face;
2213 FT_Long face_index = 0, num_faces;
2214 INT ret = 0;
2216 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
2217 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
2219 #ifdef HAVE_CARBON_CARBON_H
2220 if(file)
2222 char **mac_list = expand_mac_font(file);
2223 if(mac_list)
2225 BOOL had_one = FALSE;
2226 char **cursor;
2227 for(cursor = mac_list; *cursor; cursor++)
2229 had_one = TRUE;
2230 AddFontToList(*cursor, NULL, 0, flags);
2231 HeapFree(GetProcessHeap(), 0, *cursor);
2233 HeapFree(GetProcessHeap(), 0, mac_list);
2234 if(had_one)
2235 return 1;
2238 #endif /* HAVE_CARBON_CARBON_H */
2240 do {
2241 const DWORD FS_DBCS_MASK = FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB;
2242 FONTSIGNATURE fs;
2244 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_ALLOW_BITMAP );
2245 if (!ft_face) return 0;
2247 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
2249 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
2250 pFT_Done_Face(ft_face);
2251 return 0;
2254 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags);
2255 ++ret;
2257 get_fontsig(ft_face, &fs);
2258 if (fs.fsCsb[0] & FS_DBCS_MASK)
2260 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index,
2261 flags | ADDFONT_VERTICAL_FONT);
2262 ++ret;
2265 num_faces = ft_face->num_faces;
2266 pFT_Done_Face(ft_face);
2267 } while(num_faces > ++face_index);
2268 return ret;
2271 static int remove_font_resource( const char *file, DWORD flags )
2273 Family *family, *family_next;
2274 Face *face, *face_next;
2275 struct stat st;
2276 int count = 0;
2278 if (stat( file, &st ) == -1) return 0;
2279 LIST_FOR_EACH_ENTRY_SAFE( family, family_next, &font_list, Family, entry )
2281 family->refcount++;
2282 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, Face, entry )
2284 if (!face->file) continue;
2285 if (LOWORD(face->flags) != LOWORD(flags)) continue;
2286 if (st.st_dev == face->dev && st.st_ino == face->ino)
2288 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount );
2289 release_face( face );
2290 count++;
2293 release_family( family );
2295 return count;
2298 static void DumpFontList(void)
2300 Family *family;
2301 Face *face;
2303 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2304 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
2305 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2306 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
2307 if(!face->scalable)
2308 TRACE(" %d", face->size.height);
2309 TRACE("\n");
2314 static BOOL map_font_family(const WCHAR *orig, const WCHAR *repl)
2316 Family *family = find_family_from_any_name(repl);
2317 if (family != NULL)
2319 Family *new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2320 if (new_family != NULL)
2322 TRACE("mapping %s to %s\n", debugstr_w(repl), debugstr_w(orig));
2323 new_family->FamilyName = strdupW(orig);
2324 new_family->EnglishName = NULL;
2325 list_init(&new_family->faces);
2326 new_family->replacement = &family->faces;
2327 list_add_tail(&font_list, &new_family->entry);
2328 return TRUE;
2331 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(repl));
2332 return FALSE;
2335 /***********************************************************
2336 * The replacement list is a way to map an entire font
2337 * family onto another family. For example adding
2339 * [HKCU\Software\Wine\Fonts\Replacements]
2340 * "Wingdings"="Winedings"
2342 * would enumerate the Winedings font both as Winedings and
2343 * Wingdings. However if a real Wingdings font is present the
2344 * replacement does not take place.
2347 static void LoadReplaceList(void)
2349 HKEY hkey;
2350 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2351 LPWSTR value;
2352 LPVOID data;
2354 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2355 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
2357 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2358 &valuelen, &datalen, NULL, NULL);
2360 valuelen++; /* returned value doesn't include room for '\0' */
2361 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2362 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2364 dlen = datalen;
2365 vlen = valuelen;
2366 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data, &dlen) == ERROR_SUCCESS)
2368 /* "NewName"="Oldname" */
2369 if(!find_family_from_any_name(value))
2371 if (type == REG_MULTI_SZ)
2373 WCHAR *replace = data;
2374 while(*replace)
2376 if (map_font_family(value, replace))
2377 break;
2378 replace += strlenW(replace) + 1;
2381 else
2382 map_font_family(value, data);
2384 else
2385 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2387 /* reset dlen and vlen */
2388 dlen = datalen;
2389 vlen = valuelen;
2391 HeapFree(GetProcessHeap(), 0, data);
2392 HeapFree(GetProcessHeap(), 0, value);
2393 RegCloseKey(hkey);
2397 static const WCHAR *font_links_list[] =
2399 Lucida_Sans_Unicode,
2400 Microsoft_Sans_Serif,
2401 Tahoma
2404 static const struct font_links_defaults_list
2406 /* Keyed off substitution for "MS Shell Dlg" */
2407 const WCHAR *shelldlg;
2408 /* Maximum of four substitutes, plus terminating NULL pointer */
2409 const WCHAR *substitutes[5];
2410 } font_links_defaults_list[] =
2412 /* Non East-Asian */
2413 { Tahoma, /* FIXME unverified ordering */
2414 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2416 /* Below lists are courtesy of
2417 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2419 /* Japanese */
2420 { MS_UI_Gothic,
2421 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2423 /* Chinese Simplified */
2424 { SimSun,
2425 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2427 /* Korean */
2428 { Gulim,
2429 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2431 /* Chinese Traditional */
2432 { PMingLiU,
2433 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2438 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2440 SYSTEM_LINKS *font_link;
2442 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2444 if(!strcmpiW(font_link->font_name, name))
2445 return font_link;
2448 return NULL;
2451 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2453 const WCHAR *value;
2454 int i;
2455 FontSubst *psub;
2456 Family *family;
2457 Face *face;
2458 const WCHAR *file;
2460 if (values)
2462 SYSTEM_LINKS *font_link;
2464 psub = get_font_subst(&font_subst_list, name, -1);
2465 /* Don't store fonts that are only substitutes for other fonts */
2466 if(psub)
2468 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2469 return;
2472 font_link = find_font_link(name);
2473 if (font_link == NULL)
2475 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2476 font_link->font_name = strdupW(name);
2477 list_init(&font_link->links);
2478 list_add_tail(&system_links, &font_link->entry);
2481 memset(&font_link->fs, 0, sizeof font_link->fs);
2482 for (i = 0; values[i] != NULL; i++)
2484 const struct list *face_list;
2485 CHILD_FONT *child_font;
2487 value = values[i];
2488 if (!strcmpiW(name,value))
2489 continue;
2490 psub = get_font_subst(&font_subst_list, value, -1);
2491 if(psub)
2492 value = psub->to.name;
2493 family = find_family_from_name(value);
2494 if (!family)
2495 continue;
2496 file = NULL;
2497 /* Use first extant filename for this Family */
2498 face_list = get_face_list_from_family(family);
2499 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2501 if (!face->file)
2502 continue;
2503 file = strrchrW(face->file, '/');
2504 if (!file)
2505 file = face->file;
2506 else
2507 file++;
2508 break;
2510 if (!file)
2511 continue;
2512 face = find_face_from_filename(file, value);
2513 if(!face)
2515 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2516 continue;
2519 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2520 child_font->face = face;
2521 child_font->font = NULL;
2522 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2523 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2524 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2525 child_font->face->face_index);
2526 list_add_tail(&font_link->links, &child_font->entry);
2528 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2534 /*************************************************************
2535 * init_system_links
2537 static BOOL init_system_links(void)
2539 HKEY hkey;
2540 BOOL ret = FALSE;
2541 DWORD type, max_val, max_data, val_len, data_len, index;
2542 WCHAR *value, *data;
2543 WCHAR *entry, *next;
2544 SYSTEM_LINKS *font_link, *system_font_link;
2545 CHILD_FONT *child_font;
2546 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2547 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2548 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2549 Face *face;
2550 FontSubst *psub;
2551 UINT i, j;
2553 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2555 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2556 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2557 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2558 val_len = max_val + 1;
2559 data_len = max_data;
2560 index = 0;
2561 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2563 psub = get_font_subst(&font_subst_list, value, -1);
2564 /* Don't store fonts that are only substitutes for other fonts */
2565 if(psub)
2567 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2568 goto next;
2570 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2571 font_link->font_name = strdupW(value);
2572 memset(&font_link->fs, 0, sizeof font_link->fs);
2573 list_init(&font_link->links);
2574 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2576 WCHAR *face_name;
2577 CHILD_FONT *child_font;
2579 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2581 next = entry + strlenW(entry) + 1;
2583 face_name = strchrW(entry, ',');
2584 if(face_name)
2586 *face_name++ = 0;
2587 while(isspaceW(*face_name))
2588 face_name++;
2590 psub = get_font_subst(&font_subst_list, face_name, -1);
2591 if(psub)
2592 face_name = psub->to.name;
2594 face = find_face_from_filename(entry, face_name);
2595 if(!face)
2597 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2598 continue;
2601 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2602 child_font->face = face;
2603 child_font->font = NULL;
2604 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2605 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2606 TRACE("Adding file %s index %ld\n",
2607 debugstr_w(child_font->face->file), child_font->face->face_index);
2608 list_add_tail(&font_link->links, &child_font->entry);
2610 list_add_tail(&system_links, &font_link->entry);
2611 next:
2612 val_len = max_val + 1;
2613 data_len = max_data;
2616 HeapFree(GetProcessHeap(), 0, value);
2617 HeapFree(GetProcessHeap(), 0, data);
2618 RegCloseKey(hkey);
2622 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2623 if (!psub) {
2624 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2625 goto skip_internal;
2628 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2630 const FontSubst *psub2;
2631 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2633 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2635 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2636 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2638 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2639 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2641 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2643 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2647 skip_internal:
2649 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2650 that Tahoma has */
2652 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2653 system_font_link->font_name = strdupW(System);
2654 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2655 list_init(&system_font_link->links);
2657 face = find_face_from_filename(tahoma_ttf, Tahoma);
2658 if(face)
2660 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2661 child_font->face = face;
2662 child_font->font = NULL;
2663 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2664 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2665 TRACE("Found Tahoma in %s index %ld\n",
2666 debugstr_w(child_font->face->file), child_font->face->face_index);
2667 list_add_tail(&system_font_link->links, &child_font->entry);
2669 font_link = find_font_link(Tahoma);
2670 if (font_link != NULL)
2672 CHILD_FONT *font_link_entry;
2673 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2675 CHILD_FONT *new_child;
2676 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2677 new_child->face = font_link_entry->face;
2678 new_child->font = NULL;
2679 new_child->face->refcount++;
2680 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2681 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2682 list_add_tail(&system_font_link->links, &new_child->entry);
2685 list_add_tail(&system_links, &system_font_link->entry);
2686 return ret;
2689 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2691 DIR *dir;
2692 struct dirent *dent;
2693 char path[MAX_PATH];
2695 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2697 dir = opendir(dirname);
2698 if(!dir) {
2699 WARN("Can't open directory %s\n", debugstr_a(dirname));
2700 return FALSE;
2702 while((dent = readdir(dir)) != NULL) {
2703 struct stat statbuf;
2705 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2706 continue;
2708 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2710 sprintf(path, "%s/%s", dirname, dent->d_name);
2712 if(stat(path, &statbuf) == -1)
2714 WARN("Can't stat %s\n", debugstr_a(path));
2715 continue;
2717 if(S_ISDIR(statbuf.st_mode))
2718 ReadFontDir(path, external_fonts);
2719 else
2721 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2722 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2723 AddFontToList(path, NULL, 0, addfont_flags);
2726 closedir(dir);
2727 return TRUE;
2730 #ifdef SONAME_LIBFONTCONFIG
2732 static BOOL fontconfig_enabled;
2734 static UINT parse_aa_pattern( FcPattern *pattern )
2736 FcBool antialias;
2737 int rgba;
2738 UINT aa_flags = 0;
2740 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2741 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2743 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2745 switch (rgba)
2747 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2748 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2749 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2750 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2751 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2754 return aa_flags;
2757 static void init_fontconfig(void)
2759 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2761 if (!fc_handle)
2763 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2764 return;
2767 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2768 LOAD_FUNCPTR(FcConfigSubstitute);
2769 LOAD_FUNCPTR(FcFontList);
2770 LOAD_FUNCPTR(FcFontSetDestroy);
2771 LOAD_FUNCPTR(FcInit);
2772 LOAD_FUNCPTR(FcObjectSetAdd);
2773 LOAD_FUNCPTR(FcObjectSetCreate);
2774 LOAD_FUNCPTR(FcObjectSetDestroy);
2775 LOAD_FUNCPTR(FcPatternCreate);
2776 LOAD_FUNCPTR(FcPatternDestroy);
2777 LOAD_FUNCPTR(FcPatternGetBool);
2778 LOAD_FUNCPTR(FcPatternGetInteger);
2779 LOAD_FUNCPTR(FcPatternGetString);
2780 #undef LOAD_FUNCPTR
2782 if (pFcInit())
2784 FcPattern *pattern = pFcPatternCreate();
2785 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2786 default_aa_flags = parse_aa_pattern( pattern );
2787 pFcPatternDestroy( pattern );
2788 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2789 fontconfig_enabled = TRUE;
2793 static void load_fontconfig_fonts(void)
2795 FcPattern *pat;
2796 FcObjectSet *os;
2797 FcFontSet *fontset;
2798 int i, len;
2799 char *file;
2800 const char *ext;
2802 if (!fontconfig_enabled) return;
2804 pat = pFcPatternCreate();
2805 os = pFcObjectSetCreate();
2806 pFcObjectSetAdd(os, FC_FILE);
2807 pFcObjectSetAdd(os, FC_SCALABLE);
2808 pFcObjectSetAdd(os, FC_ANTIALIAS);
2809 pFcObjectSetAdd(os, FC_RGBA);
2810 fontset = pFcFontList(NULL, pat, os);
2811 if(!fontset) return;
2812 for(i = 0; i < fontset->nfont; i++) {
2813 FcBool scalable;
2814 DWORD aa_flags;
2816 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2817 continue;
2819 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2821 /* We're just interested in OT/TT fonts for now, so this hack just
2822 picks up the scalable fonts without extensions .pf[ab] to save time
2823 loading every other font */
2825 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2827 TRACE("not scalable\n");
2828 continue;
2831 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2832 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2834 len = strlen( file );
2835 if(len < 4) continue;
2836 ext = &file[ len - 3 ];
2837 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2838 AddFontToList(file, NULL, 0,
2839 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2841 pFcFontSetDestroy(fontset);
2842 pFcObjectSetDestroy(os);
2843 pFcPatternDestroy(pat);
2846 #elif defined(HAVE_CARBON_CARBON_H)
2848 static void load_mac_font_callback(const void *value, void *context)
2850 CFStringRef pathStr = value;
2851 CFIndex len;
2852 char* path;
2854 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2855 path = HeapAlloc(GetProcessHeap(), 0, len);
2856 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2858 TRACE("font file %s\n", path);
2859 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2861 HeapFree(GetProcessHeap(), 0, path);
2864 static void load_mac_fonts(void)
2866 CFStringRef removeDupesKey;
2867 CFBooleanRef removeDupesValue;
2868 CFDictionaryRef options;
2869 CTFontCollectionRef col;
2870 CFArrayRef descs;
2871 CFMutableSetRef paths;
2872 CFIndex i;
2874 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2875 removeDupesValue = kCFBooleanTrue;
2876 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2877 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2878 col = CTFontCollectionCreateFromAvailableFonts(options);
2879 if (options) CFRelease(options);
2880 if (!col)
2882 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2883 return;
2886 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2887 CFRelease(col);
2888 if (!descs)
2890 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2891 return;
2894 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2895 if (!paths)
2897 WARN("CFSetCreateMutable failed\n");
2898 CFRelease(descs);
2899 return;
2902 for (i = 0; i < CFArrayGetCount(descs); i++)
2904 CTFontDescriptorRef desc;
2905 CTFontRef font;
2906 ATSFontRef atsFont;
2907 OSStatus status;
2908 FSRef fsref;
2909 CFURLRef url;
2910 CFStringRef ext;
2911 CFStringRef path;
2913 desc = CFArrayGetValueAtIndex(descs, i);
2915 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2916 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2917 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2918 if (!font) continue;
2920 atsFont = CTFontGetPlatformFont(font, NULL);
2921 if (!atsFont)
2923 CFRelease(font);
2924 continue;
2927 status = ATSFontGetFileReference(atsFont, &fsref);
2928 CFRelease(font);
2929 if (status != noErr) continue;
2931 url = CFURLCreateFromFSRef(NULL, &fsref);
2932 if (!url) continue;
2934 ext = CFURLCopyPathExtension(url);
2935 if (ext)
2937 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2938 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2939 CFRelease(ext);
2940 if (skip)
2942 CFRelease(url);
2943 continue;
2947 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2948 CFRelease(url);
2949 if (!path) continue;
2951 CFSetAddValue(paths, path);
2952 CFRelease(path);
2955 CFRelease(descs);
2957 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2958 CFRelease(paths);
2961 #endif
2963 static char *get_data_dir_path( LPCWSTR file )
2965 char *unix_name = NULL;
2966 const char *data_dir = wine_get_data_dir();
2968 if (!data_dir) data_dir = wine_get_build_dir();
2970 if (data_dir)
2972 INT len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2974 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2975 strcpy(unix_name, data_dir);
2976 strcat(unix_name, "/fonts/");
2978 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2980 return unix_name;
2983 static BOOL load_font_from_data_dir(LPCWSTR file)
2985 BOOL ret = FALSE;
2986 char *unix_name = get_data_dir_path( file );
2988 if (unix_name)
2990 EnterCriticalSection( &freetype_cs );
2991 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
2992 LeaveCriticalSection( &freetype_cs );
2993 HeapFree(GetProcessHeap(), 0, unix_name);
2995 return ret;
2998 static char *get_winfonts_dir_path(LPCWSTR file)
3000 static const WCHAR slashW[] = {'\\','\0'};
3001 WCHAR windowsdir[MAX_PATH];
3003 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3004 strcatW(windowsdir, fontsW);
3005 strcatW(windowsdir, slashW);
3006 strcatW(windowsdir, file);
3007 return wine_get_unix_file_name( windowsdir );
3010 static void load_system_fonts(void)
3012 HKEY hkey;
3013 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
3014 const WCHAR * const *value;
3015 DWORD dlen, type;
3016 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3017 char *unixname;
3019 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
3020 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3021 strcatW(windowsdir, fontsW);
3022 for(value = SystemFontValues; *value; value++) {
3023 dlen = sizeof(data);
3024 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
3025 type == REG_SZ) {
3026 BOOL added = FALSE;
3028 sprintfW(pathW, fmtW, windowsdir, data);
3029 if((unixname = wine_get_unix_file_name(pathW))) {
3030 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3031 HeapFree(GetProcessHeap(), 0, unixname);
3033 if (!added)
3034 load_font_from_data_dir(data);
3037 RegCloseKey(hkey);
3041 /*************************************************************
3043 * This adds registry entries for any externally loaded fonts
3044 * (fonts from fontconfig or FontDirs). It also deletes entries
3045 * of no longer existing fonts.
3048 static void update_reg_entries(void)
3050 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
3051 LPWSTR valueW;
3052 DWORD len;
3053 Family *family;
3054 Face *face;
3055 WCHAR *file, *path;
3056 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
3058 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
3059 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
3060 ERR("Can't create Windows font reg key\n");
3061 goto end;
3064 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
3065 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
3066 ERR("Can't create Windows font reg key\n");
3067 goto end;
3070 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
3071 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
3072 ERR("Can't create external font reg key\n");
3073 goto end;
3076 /* enumerate the fonts and add external ones to the two keys */
3078 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
3079 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
3080 char *buffer;
3081 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
3083 if(face->FullName)
3085 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
3086 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3087 strcpyW(valueW, face->FullName);
3089 else
3091 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
3092 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3093 strcpyW(valueW, family->FamilyName);
3096 buffer = strWtoA( CP_UNIXCP, face->file );
3097 path = wine_get_dos_file_name( buffer );
3098 HeapFree( GetProcessHeap(), 0, buffer );
3100 if (path)
3101 file = path;
3102 else if ((file = strrchrW(face->file, '/')))
3103 file++;
3104 else
3105 file = face->file;
3107 len = strlenW(file) + 1;
3108 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3109 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3110 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3112 HeapFree(GetProcessHeap(), 0, path);
3113 HeapFree(GetProcessHeap(), 0, valueW);
3116 end:
3117 if(external_key) RegCloseKey(external_key);
3118 if(win9x_key) RegCloseKey(win9x_key);
3119 if(winnt_key) RegCloseKey(winnt_key);
3122 static void delete_external_font_keys(void)
3124 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
3125 DWORD dlen, vlen, datalen, valuelen, i, type;
3126 LPWSTR valueW;
3127 LPVOID data;
3129 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
3130 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
3131 ERR("Can't create Windows font reg key\n");
3132 goto end;
3135 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
3136 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
3137 ERR("Can't create Windows font reg key\n");
3138 goto end;
3141 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
3142 ERR("Can't create external font reg key\n");
3143 goto end;
3146 /* Delete all external fonts added last time */
3148 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3149 &valuelen, &datalen, NULL, NULL);
3150 valuelen++; /* returned value doesn't include room for '\0' */
3151 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3152 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3154 dlen = datalen * sizeof(WCHAR);
3155 vlen = valuelen;
3156 i = 0;
3157 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
3158 &dlen) == ERROR_SUCCESS) {
3160 RegDeleteValueW(winnt_key, valueW);
3161 RegDeleteValueW(win9x_key, valueW);
3162 /* reset dlen and vlen */
3163 dlen = datalen;
3164 vlen = valuelen;
3166 HeapFree(GetProcessHeap(), 0, data);
3167 HeapFree(GetProcessHeap(), 0, valueW);
3169 /* Delete the old external fonts key */
3170 RegCloseKey(external_key);
3171 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
3173 end:
3174 if(win9x_key) RegCloseKey(win9x_key);
3175 if(winnt_key) RegCloseKey(winnt_key);
3178 /*************************************************************
3179 * WineEngAddFontResourceEx
3182 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3184 INT ret = 0;
3186 GDI_CheckNotLock();
3188 if (ft_handle) /* do it only if we have freetype up and running */
3190 char *unixname;
3192 EnterCriticalSection( &freetype_cs );
3194 if((unixname = wine_get_unix_file_name(file)))
3196 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3198 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3199 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
3200 HeapFree(GetProcessHeap(), 0, unixname);
3202 if (!ret && !strchrW(file, '\\')) {
3203 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
3204 if ((unixname = get_winfonts_dir_path( file )))
3206 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3207 HeapFree(GetProcessHeap(), 0, unixname);
3209 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
3210 if (!ret && (unixname = get_data_dir_path( file )))
3212 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3213 HeapFree(GetProcessHeap(), 0, unixname);
3217 LeaveCriticalSection( &freetype_cs );
3219 return ret;
3222 /*************************************************************
3223 * WineEngAddFontMemResourceEx
3226 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3228 GDI_CheckNotLock();
3230 if (ft_handle) /* do it only if we have freetype up and running */
3232 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
3234 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
3235 memcpy(pFontCopy, pbFont, cbFont);
3237 EnterCriticalSection( &freetype_cs );
3238 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3239 LeaveCriticalSection( &freetype_cs );
3241 if (*pcFonts == 0)
3243 TRACE("AddFontToList failed\n");
3244 HeapFree(GetProcessHeap(), 0, pFontCopy);
3245 return 0;
3247 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
3248 * For now return something unique but quite random
3250 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
3251 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
3254 *pcFonts = 0;
3255 return 0;
3258 /*************************************************************
3259 * WineEngRemoveFontResourceEx
3262 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3264 INT ret = 0;
3266 GDI_CheckNotLock();
3268 if (ft_handle) /* do it only if we have freetype up and running */
3270 char *unixname;
3272 EnterCriticalSection( &freetype_cs );
3274 if ((unixname = wine_get_unix_file_name(file)))
3276 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3278 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3279 ret = remove_font_resource( unixname, addfont_flags );
3280 HeapFree(GetProcessHeap(), 0, unixname);
3282 if (!ret && !strchrW(file, '\\'))
3284 if ((unixname = get_winfonts_dir_path( file )))
3286 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3287 HeapFree(GetProcessHeap(), 0, unixname);
3289 if (!ret && (unixname = get_data_dir_path( file )))
3291 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3292 HeapFree(GetProcessHeap(), 0, unixname);
3296 LeaveCriticalSection( &freetype_cs );
3298 return ret;
3301 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
3303 WCHAR *fullname;
3304 char *unix_name;
3305 int file_len;
3307 if (!font_file) return NULL;
3309 file_len = strlenW( font_file );
3311 if (font_path && font_path[0])
3313 int path_len = strlenW( font_path );
3314 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
3315 if (!fullname) return NULL;
3316 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
3317 fullname[path_len] = '\\';
3318 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
3320 else
3322 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
3323 if (!len) return NULL;
3324 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3325 if (!fullname) return NULL;
3326 GetFullPathNameW( font_file, len, fullname, NULL );
3329 unix_name = wine_get_unix_file_name( fullname );
3330 HeapFree( GetProcessHeap(), 0, fullname );
3331 return unix_name;
3334 #include <pshpack1.h>
3335 struct fontdir
3337 WORD num_of_resources;
3338 WORD res_id;
3339 WORD dfVersion;
3340 DWORD dfSize;
3341 CHAR dfCopyright[60];
3342 WORD dfType;
3343 WORD dfPoints;
3344 WORD dfVertRes;
3345 WORD dfHorizRes;
3346 WORD dfAscent;
3347 WORD dfInternalLeading;
3348 WORD dfExternalLeading;
3349 BYTE dfItalic;
3350 BYTE dfUnderline;
3351 BYTE dfStrikeOut;
3352 WORD dfWeight;
3353 BYTE dfCharSet;
3354 WORD dfPixWidth;
3355 WORD dfPixHeight;
3356 BYTE dfPitchAndFamily;
3357 WORD dfAvgWidth;
3358 WORD dfMaxWidth;
3359 BYTE dfFirstChar;
3360 BYTE dfLastChar;
3361 BYTE dfDefaultChar;
3362 BYTE dfBreakChar;
3363 WORD dfWidthBytes;
3364 DWORD dfDevice;
3365 DWORD dfFace;
3366 DWORD dfReserved;
3367 CHAR szFaceName[LF_FACESIZE];
3370 #include <poppack.h>
3372 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
3373 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
3375 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
3377 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3378 Face *face;
3379 WCHAR *name, *english_name;
3380 ENUMLOGFONTEXW elf;
3381 NEWTEXTMETRICEXW ntm;
3382 DWORD type;
3384 if (!ft_face) return FALSE;
3385 face = create_face( ft_face, 0, unix_name, NULL, 0, 0 );
3386 get_family_names( ft_face, &name, &english_name, FALSE );
3387 pFT_Done_Face( ft_face );
3389 GetEnumStructs( face, name, &elf, &ntm, &type );
3390 release_face( face );
3391 HeapFree( GetProcessHeap(), 0, name );
3392 HeapFree( GetProcessHeap(), 0, english_name );
3394 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3396 memset( fd, 0, sizeof(*fd) );
3398 fd->num_of_resources = 1;
3399 fd->res_id = 0;
3400 fd->dfVersion = 0x200;
3401 fd->dfSize = sizeof(*fd);
3402 strcpy( fd->dfCopyright, "Wine fontdir" );
3403 fd->dfType = 0x4003; /* 0x0080 set if private */
3404 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3405 fd->dfVertRes = 72;
3406 fd->dfHorizRes = 72;
3407 fd->dfAscent = ntm.ntmTm.tmAscent;
3408 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3409 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3410 fd->dfItalic = ntm.ntmTm.tmItalic;
3411 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3412 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3413 fd->dfWeight = ntm.ntmTm.tmWeight;
3414 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3415 fd->dfPixWidth = 0;
3416 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3417 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3418 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3419 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3420 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3421 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3422 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3423 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3424 fd->dfWidthBytes = 0;
3425 fd->dfDevice = 0;
3426 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3427 fd->dfReserved = 0;
3428 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3430 return TRUE;
3433 #define NE_FFLAGS_LIBMODULE 0x8000
3434 #define NE_OSFLAGS_WINDOWS 0x02
3436 static const char dos_string[0x40] = "This is a TrueType resource file";
3437 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3439 #include <pshpack2.h>
3441 struct ne_typeinfo
3443 WORD type_id;
3444 WORD count;
3445 DWORD res;
3448 struct ne_nameinfo
3450 WORD off;
3451 WORD len;
3452 WORD flags;
3453 WORD id;
3454 DWORD res;
3457 struct rsrc_tab
3459 WORD align;
3460 struct ne_typeinfo fontdir_type;
3461 struct ne_nameinfo fontdir_name;
3462 struct ne_typeinfo scalable_type;
3463 struct ne_nameinfo scalable_name;
3464 WORD end_of_rsrc;
3465 BYTE fontdir_res_name[8];
3468 #include <poppack.h>
3470 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3472 BOOL ret = FALSE;
3473 HANDLE file;
3474 DWORD size, written;
3475 BYTE *ptr, *start;
3476 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3477 char *font_fileA, *last_part, *ext;
3478 IMAGE_DOS_HEADER dos;
3479 IMAGE_OS2_HEADER ne =
3481 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3482 0, 0, 0, 0, 0, 0,
3483 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3484 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3486 struct rsrc_tab rsrc_tab =
3489 { 0x8007, 1, 0 },
3490 { 0, 0, 0x0c50, 0x2c, 0 },
3491 { 0x80cc, 1, 0 },
3492 { 0, 0, 0x0c50, 0x8001, 0 },
3494 { 7,'F','O','N','T','D','I','R'}
3497 memset( &dos, 0, sizeof(dos) );
3498 dos.e_magic = IMAGE_DOS_SIGNATURE;
3499 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3501 /* import name is last part\0, resident name is last part without extension
3502 non-resident name is "FONTRES:" + lfFaceName */
3504 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3505 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3506 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3508 last_part = strrchr( font_fileA, '\\' );
3509 if (last_part) last_part++;
3510 else last_part = font_fileA;
3511 import_name_len = strlen( last_part ) + 1;
3513 ext = strchr( last_part, '.' );
3514 if (ext) res_name_len = ext - last_part;
3515 else res_name_len = import_name_len - 1;
3517 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3519 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3520 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3521 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3522 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3523 ne.ne_cbenttab = 2;
3524 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3526 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3527 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3528 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3529 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3531 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3532 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3534 if (!ptr)
3536 HeapFree( GetProcessHeap(), 0, font_fileA );
3537 return FALSE;
3540 memcpy( ptr, &dos, sizeof(dos) );
3541 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3542 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3544 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3545 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3547 ptr = start + dos.e_lfanew + ne.ne_restab;
3548 *ptr++ = res_name_len;
3549 memcpy( ptr, last_part, res_name_len );
3551 ptr = start + dos.e_lfanew + ne.ne_imptab;
3552 *ptr++ = import_name_len;
3553 memcpy( ptr, last_part, import_name_len );
3555 ptr = start + ne.ne_nrestab;
3556 *ptr++ = non_res_name_len;
3557 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3558 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3560 ptr = start + (rsrc_tab.scalable_name.off << 4);
3561 memcpy( ptr, font_fileA, font_file_len );
3563 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3564 memcpy( ptr, fontdir, fontdir->dfSize );
3566 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3567 if (file != INVALID_HANDLE_VALUE)
3569 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3570 ret = TRUE;
3571 CloseHandle( file );
3574 HeapFree( GetProcessHeap(), 0, start );
3575 HeapFree( GetProcessHeap(), 0, font_fileA );
3577 return ret;
3580 /*************************************************************
3581 * WineEngCreateScalableFontResource
3584 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3585 LPCWSTR font_file, LPCWSTR font_path )
3587 char *unix_name = get_ttf_file_name( font_file, font_path );
3588 struct fontdir fontdir;
3589 BOOL ret = FALSE;
3591 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3592 SetLastError( ERROR_INVALID_PARAMETER );
3593 else
3595 if (hidden) fontdir.dfType |= 0x80;
3596 ret = create_fot( resource, font_file, &fontdir );
3599 HeapFree( GetProcessHeap(), 0, unix_name );
3600 return ret;
3603 static const struct nls_update_font_list
3605 UINT ansi_cp, oem_cp;
3606 const char *oem, *fixed, *system;
3607 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3608 /* these are for font substitutes */
3609 const char *shelldlg, *tmsrmn;
3610 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3611 *helv_0, *tmsrmn_0;
3612 const struct subst
3614 const char *from, *to;
3615 } arial_0, courier_new_0, times_new_roman_0;
3616 } nls_update_font_list[] =
3618 /* Latin 1 (United States) */
3619 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3620 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3621 "Tahoma","Times New Roman",
3622 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3623 { 0 }, { 0 }, { 0 }
3625 /* Latin 1 (Multilingual) */
3626 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3627 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3628 "Tahoma","Times New Roman", /* FIXME unverified */
3629 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3630 { 0 }, { 0 }, { 0 }
3632 /* Eastern Europe */
3633 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3634 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3635 "Tahoma","Times New Roman", /* FIXME unverified */
3636 "Fixedsys,238", "System,238",
3637 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3638 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3639 { "Arial CE,0", "Arial,238" },
3640 { "Courier New CE,0", "Courier New,238" },
3641 { "Times New Roman CE,0", "Times New Roman,238" }
3643 /* Cyrillic */
3644 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3645 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3646 "Tahoma","Times New Roman", /* FIXME unverified */
3647 "Fixedsys,204", "System,204",
3648 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3649 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3650 { "Arial Cyr,0", "Arial,204" },
3651 { "Courier New Cyr,0", "Courier New,204" },
3652 { "Times New Roman Cyr,0", "Times New Roman,204" }
3654 /* Greek */
3655 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3656 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3657 "Tahoma","Times New Roman", /* FIXME unverified */
3658 "Fixedsys,161", "System,161",
3659 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3660 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3661 { "Arial Greek,0", "Arial,161" },
3662 { "Courier New Greek,0", "Courier New,161" },
3663 { "Times New Roman Greek,0", "Times New Roman,161" }
3665 /* Turkish */
3666 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3667 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3668 "Tahoma","Times New Roman", /* FIXME unverified */
3669 "Fixedsys,162", "System,162",
3670 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3671 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3672 { "Arial Tur,0", "Arial,162" },
3673 { "Courier New Tur,0", "Courier New,162" },
3674 { "Times New Roman Tur,0", "Times New Roman,162" }
3676 /* Hebrew */
3677 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3678 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3679 "Tahoma","Times New Roman", /* FIXME unverified */
3680 "Fixedsys,177", "System,177",
3681 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3682 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3683 { 0 }, { 0 }, { 0 }
3685 /* Arabic */
3686 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3687 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3688 "Microsoft Sans Serif","Times New Roman",
3689 "Fixedsys,178", "System,178",
3690 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3691 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3692 { 0 }, { 0 }, { 0 }
3694 /* Baltic */
3695 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3696 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3697 "Tahoma","Times New Roman", /* FIXME unverified */
3698 "Fixedsys,186", "System,186",
3699 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3700 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3701 { "Arial Baltic,0", "Arial,186" },
3702 { "Courier New Baltic,0", "Courier New,186" },
3703 { "Times New Roman Baltic,0", "Times New Roman,186" }
3705 /* Vietnamese */
3706 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3707 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3708 "Tahoma","Times New Roman", /* FIXME unverified */
3709 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3710 { 0 }, { 0 }, { 0 }
3712 /* Thai */
3713 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3714 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3715 "Tahoma","Times New Roman", /* FIXME unverified */
3716 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3717 { 0 }, { 0 }, { 0 }
3719 /* Japanese */
3720 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3721 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3722 "MS UI Gothic","MS Serif",
3723 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3724 { 0 }, { 0 }, { 0 }
3726 /* Chinese Simplified */
3727 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3728 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3729 "SimSun", "NSimSun",
3730 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3731 { 0 }, { 0 }, { 0 }
3733 /* Korean */
3734 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3735 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3736 "Gulim", "Batang",
3737 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3738 { 0 }, { 0 }, { 0 }
3740 /* Chinese Traditional */
3741 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3742 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3743 "PMingLiU", "MingLiU",
3744 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3745 { 0 }, { 0 }, { 0 }
3749 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3751 return ( ansi_cp == 932 /* CP932 for Japanese */
3752 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3753 || ansi_cp == 949 /* CP949 for Korean */
3754 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3757 static inline HKEY create_fonts_NT_registry_key(void)
3759 HKEY hkey = 0;
3761 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3762 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3763 return hkey;
3766 static inline HKEY create_fonts_9x_registry_key(void)
3768 HKEY hkey = 0;
3770 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3771 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3772 return hkey;
3775 static inline HKEY create_config_fonts_registry_key(void)
3777 HKEY hkey = 0;
3779 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3780 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3781 return hkey;
3784 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3786 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3788 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3789 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3790 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3791 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3794 static void set_value_key(HKEY hkey, const char *name, const char *value)
3796 if (value)
3797 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3798 else if (name)
3799 RegDeleteValueA(hkey, name);
3802 static void update_font_association_info(UINT current_ansi_codepage)
3804 static const char *font_assoc_reg_key = "System\\CurrentControlSet\\Control\\FontAssoc";
3805 static const char *assoc_charset_subkey = "Associated Charset";
3807 if (is_dbcs_ansi_cp(current_ansi_codepage))
3809 HKEY hkey;
3810 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, font_assoc_reg_key, &hkey) == ERROR_SUCCESS)
3812 HKEY hsubkey;
3813 if (RegCreateKeyA(hkey, assoc_charset_subkey, &hsubkey) == ERROR_SUCCESS)
3815 switch (current_ansi_codepage)
3817 case 932:
3818 set_value_key(hsubkey, "ANSI(00)", "NO");
3819 set_value_key(hsubkey, "OEM(FF)", "NO");
3820 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3821 break;
3822 case 936:
3823 case 949:
3824 case 950:
3825 set_value_key(hsubkey, "ANSI(00)", "YES");
3826 set_value_key(hsubkey, "OEM(FF)", "YES");
3827 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3828 break;
3830 RegCloseKey(hsubkey);
3833 /* TODO: Associated DefaultFonts */
3835 RegCloseKey(hkey);
3838 else
3839 RegDeleteTreeA(HKEY_LOCAL_MACHINE, font_assoc_reg_key);
3842 static void set_multi_value_key(HKEY hkey, const WCHAR *name, const WCHAR *value, DWORD len)
3844 if (value)
3845 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (const BYTE *)value, len);
3846 else if (name)
3847 RegDeleteValueW(hkey, name);
3850 static void update_font_system_link_info(UINT current_ansi_codepage)
3852 static const WCHAR system_link_simplified_chinese[] =
3853 {'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3854 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3855 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3856 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3857 '\0'};
3858 static const WCHAR system_link_traditional_chinese[] =
3859 {'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3860 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3861 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3862 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3863 '\0'};
3864 static const WCHAR system_link_japanese[] =
3865 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3866 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3867 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3868 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3869 '\0'};
3870 static const WCHAR system_link_korean[] =
3871 {'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3872 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3873 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3874 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3875 '\0'};
3876 static const WCHAR system_link_non_cjk[] =
3877 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3878 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3879 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3880 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3881 '\0'};
3882 HKEY hkey;
3884 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
3886 const WCHAR *link;
3887 DWORD len;
3889 switch (current_ansi_codepage)
3891 case 932:
3892 link = system_link_japanese;
3893 len = sizeof(system_link_japanese);
3894 break;
3895 case 936:
3896 link = system_link_simplified_chinese;
3897 len = sizeof(system_link_simplified_chinese);
3898 break;
3899 case 949:
3900 link = system_link_korean;
3901 len = sizeof(system_link_korean);
3902 break;
3903 case 950:
3904 link = system_link_traditional_chinese;
3905 len = sizeof(system_link_traditional_chinese);
3906 break;
3907 default:
3908 link = system_link_non_cjk;
3909 len = sizeof(system_link_non_cjk);
3911 set_multi_value_key(hkey, Lucida_Sans_Unicode, link, len);
3912 set_multi_value_key(hkey, Microsoft_Sans_Serif, link, len);
3913 set_multi_value_key(hkey, Tahoma, link, len);
3914 RegCloseKey(hkey);
3918 static void update_font_info(void)
3920 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3921 char buf[40], cpbuf[40];
3922 DWORD len, type;
3923 HKEY hkey = 0;
3924 UINT i, ansi_cp = 0, oem_cp = 0;
3925 DWORD screen_dpi = 96, font_dpi = 0;
3926 BOOL done = FALSE;
3928 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3929 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3930 &hkey) == ERROR_SUCCESS)
3932 reg_load_dword(hkey, logpixels, &screen_dpi);
3933 RegCloseKey(hkey);
3936 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3937 return;
3939 reg_load_dword(hkey, logpixels, &font_dpi);
3941 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3942 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3943 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3944 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3945 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3947 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3948 if (is_dbcs_ansi_cp(ansi_cp))
3949 use_default_fallback = TRUE;
3951 buf[0] = 0;
3952 len = sizeof(buf);
3953 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3955 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3957 RegCloseKey(hkey);
3958 return;
3960 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3961 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3963 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3964 ansi_cp, oem_cp, screen_dpi);
3966 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3967 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3968 RegCloseKey(hkey);
3970 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3972 HKEY hkey;
3974 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3975 nls_update_font_list[i].oem_cp == oem_cp)
3977 hkey = create_config_fonts_registry_key();
3978 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3979 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3980 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3981 RegCloseKey(hkey);
3983 hkey = create_fonts_NT_registry_key();
3984 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3985 RegCloseKey(hkey);
3987 hkey = create_fonts_9x_registry_key();
3988 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3989 RegCloseKey(hkey);
3991 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3993 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3994 strlen(nls_update_font_list[i].shelldlg)+1);
3995 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3996 strlen(nls_update_font_list[i].tmsrmn)+1);
3998 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3999 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
4000 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
4001 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
4002 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
4003 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
4004 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
4005 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
4007 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
4008 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
4009 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
4011 RegCloseKey(hkey);
4013 done = TRUE;
4015 else
4017 /* Delete the FontSubstitutes from other locales */
4018 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
4020 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
4021 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
4022 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
4023 RegCloseKey(hkey);
4027 if (!done)
4028 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
4030 /* update locale dependent font association info and font system link info in registry.
4031 update only when codepages changed, not logpixels. */
4032 if (strcmp(buf, cpbuf) != 0)
4034 update_font_association_info(ansi_cp);
4035 update_font_system_link_info(ansi_cp);
4039 static BOOL init_freetype(void)
4041 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
4042 if(!ft_handle) {
4043 WINE_MESSAGE(
4044 "Wine cannot find the FreeType font library. To enable Wine to\n"
4045 "use TrueType fonts please install a version of FreeType greater than\n"
4046 "or equal to 2.0.5.\n"
4047 "http://www.freetype.org\n");
4048 return FALSE;
4051 #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;}
4053 LOAD_FUNCPTR(FT_Done_Face)
4054 LOAD_FUNCPTR(FT_Get_Char_Index)
4055 LOAD_FUNCPTR(FT_Get_First_Char)
4056 LOAD_FUNCPTR(FT_Get_Next_Char)
4057 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
4058 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
4059 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
4060 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
4061 LOAD_FUNCPTR(FT_Init_FreeType)
4062 LOAD_FUNCPTR(FT_Library_Version)
4063 LOAD_FUNCPTR(FT_Load_Glyph)
4064 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
4065 LOAD_FUNCPTR(FT_Matrix_Multiply)
4066 #ifndef FT_MULFIX_INLINED
4067 LOAD_FUNCPTR(FT_MulFix)
4068 #endif
4069 LOAD_FUNCPTR(FT_New_Face)
4070 LOAD_FUNCPTR(FT_New_Memory_Face)
4071 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
4072 LOAD_FUNCPTR(FT_Outline_Get_CBox)
4073 LOAD_FUNCPTR(FT_Outline_Transform)
4074 LOAD_FUNCPTR(FT_Outline_Translate)
4075 LOAD_FUNCPTR(FT_Render_Glyph)
4076 LOAD_FUNCPTR(FT_Select_Charmap)
4077 LOAD_FUNCPTR(FT_Set_Charmap)
4078 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
4079 LOAD_FUNCPTR(FT_Vector_Transform)
4080 LOAD_FUNCPTR(FT_Vector_Unit)
4081 #undef LOAD_FUNCPTR
4082 /* Don't warn if these ones are missing */
4083 pFT_Outline_Embolden = wine_dlsym(ft_handle, "FT_Outline_Embolden", NULL, 0);
4084 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
4085 #ifdef FT_LCD_FILTER_H
4086 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
4087 #endif
4089 if(pFT_Init_FreeType(&library) != 0) {
4090 ERR("Can't init FreeType library\n");
4091 wine_dlclose(ft_handle, NULL, 0);
4092 ft_handle = NULL;
4093 return FALSE;
4095 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
4097 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
4098 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
4099 ((FT_Version.minor << 8) & 0x00ff00) |
4100 ((FT_Version.patch ) & 0x0000ff);
4102 font_driver = &freetype_funcs;
4103 return TRUE;
4105 sym_not_found:
4106 WINE_MESSAGE(
4107 "Wine cannot find certain functions that it needs inside the FreeType\n"
4108 "font library. To enable Wine to use TrueType fonts please upgrade\n"
4109 "FreeType to at least version 2.1.4.\n"
4110 "http://www.freetype.org\n");
4111 wine_dlclose(ft_handle, NULL, 0);
4112 ft_handle = NULL;
4113 return FALSE;
4116 static void init_font_list(void)
4118 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
4119 static const WCHAR pathW[] = {'P','a','t','h',0};
4120 HKEY hkey;
4121 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
4122 WCHAR windowsdir[MAX_PATH];
4123 char *unixname;
4124 const char *data_dir;
4126 delete_external_font_keys();
4128 /* load the system bitmap fonts */
4129 load_system_fonts();
4131 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
4132 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
4133 strcatW(windowsdir, fontsW);
4134 if((unixname = wine_get_unix_file_name(windowsdir)))
4136 ReadFontDir(unixname, FALSE);
4137 HeapFree(GetProcessHeap(), 0, unixname);
4140 /* load the system truetype fonts */
4141 data_dir = wine_get_data_dir();
4142 if (!data_dir) data_dir = wine_get_build_dir();
4143 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
4145 strcpy(unixname, data_dir);
4146 strcat(unixname, "/fonts/");
4147 ReadFontDir(unixname, TRUE);
4148 HeapFree(GetProcessHeap(), 0, unixname);
4151 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
4152 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
4153 full path as the entry. Also look for any .fon fonts, since ReadFontDir
4154 will skip these. */
4155 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
4156 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
4157 &hkey) == ERROR_SUCCESS)
4159 LPWSTR data, valueW;
4160 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
4161 &valuelen, &datalen, NULL, NULL);
4163 valuelen++; /* returned value doesn't include room for '\0' */
4164 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
4165 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
4166 if (valueW && data)
4168 dlen = datalen * sizeof(WCHAR);
4169 vlen = valuelen;
4170 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
4171 &dlen) == ERROR_SUCCESS)
4173 if(data[0] && (data[1] == ':'))
4175 if((unixname = wine_get_unix_file_name(data)))
4177 AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
4178 HeapFree(GetProcessHeap(), 0, unixname);
4181 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
4183 WCHAR pathW[MAX_PATH];
4184 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
4185 BOOL added = FALSE;
4187 sprintfW(pathW, fmtW, windowsdir, data);
4188 if((unixname = wine_get_unix_file_name(pathW)))
4190 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
4191 HeapFree(GetProcessHeap(), 0, unixname);
4193 if (!added)
4194 load_font_from_data_dir(data);
4196 /* reset dlen and vlen */
4197 dlen = datalen;
4198 vlen = valuelen;
4201 HeapFree(GetProcessHeap(), 0, data);
4202 HeapFree(GetProcessHeap(), 0, valueW);
4203 RegCloseKey(hkey);
4206 #ifdef SONAME_LIBFONTCONFIG
4207 load_fontconfig_fonts();
4208 #elif defined(HAVE_CARBON_CARBON_H)
4209 load_mac_fonts();
4210 #endif
4212 /* then look in any directories that we've specified in the config file */
4213 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
4214 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
4216 DWORD len;
4217 LPWSTR valueW;
4218 LPSTR valueA, ptr;
4220 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
4222 len += sizeof(WCHAR);
4223 valueW = HeapAlloc( GetProcessHeap(), 0, len );
4224 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
4226 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
4227 valueA = HeapAlloc( GetProcessHeap(), 0, len );
4228 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
4229 TRACE( "got font path %s\n", debugstr_a(valueA) );
4230 ptr = valueA;
4231 while (ptr)
4233 const char* home;
4234 LPSTR next = strchr( ptr, ':' );
4235 if (next) *next++ = 0;
4236 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
4237 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
4239 strcpy( unixname, home );
4240 strcat( unixname, ptr + 1 );
4241 ReadFontDir( unixname, TRUE );
4242 HeapFree( GetProcessHeap(), 0, unixname );
4244 else
4245 ReadFontDir( ptr, TRUE );
4246 ptr = next;
4248 HeapFree( GetProcessHeap(), 0, valueA );
4250 HeapFree( GetProcessHeap(), 0, valueW );
4252 RegCloseKey(hkey);
4256 static BOOL move_to_front(const WCHAR *name)
4258 Family *family, *cursor2;
4259 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
4261 if(!strcmpiW(family->FamilyName, name))
4263 list_remove(&family->entry);
4264 list_add_head(&font_list, &family->entry);
4265 return TRUE;
4268 return FALSE;
4271 static BOOL set_default(const WCHAR **name_list)
4273 while (*name_list)
4275 if (move_to_front(*name_list)) return TRUE;
4276 name_list++;
4279 return FALSE;
4282 static void reorder_font_list(void)
4284 set_default( default_serif_list );
4285 set_default( default_fixed_list );
4286 set_default( default_sans_list );
4289 /*************************************************************
4290 * WineEngInit
4292 * Initialize FreeType library and create a list of available faces
4294 BOOL WineEngInit(void)
4296 HKEY hkey;
4297 DWORD disposition;
4298 HANDLE font_mutex;
4300 /* update locale dependent font info in registry */
4301 update_font_info();
4303 if(!init_freetype()) return FALSE;
4305 #ifdef SONAME_LIBFONTCONFIG
4306 init_fontconfig();
4307 #endif
4309 if (!RegOpenKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, KEY_READ, &hkey))
4311 static const WCHAR antialias_fake_bold_or_italic[] = { 'A','n','t','i','a','l','i','a','s','F','a','k','e',
4312 'B','o','l','d','O','r','I','t','a','l','i','c',0 };
4313 static const WCHAR true_options[] = { 'y','Y','t','T','1',0 };
4314 DWORD type, size;
4315 WCHAR buffer[20];
4317 size = sizeof(buffer);
4318 if (!RegQueryValueExW(hkey, antialias_fake_bold_or_italic, NULL, &type, (BYTE*)buffer, &size) &&
4319 type == REG_SZ && size >= 1)
4321 antialias_fakes = (strchrW(true_options, buffer[0]) != NULL);
4323 RegCloseKey(hkey);
4326 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
4328 ERR("Failed to create font mutex\n");
4329 return FALSE;
4331 WaitForSingleObject(font_mutex, INFINITE);
4333 create_font_cache_key(&hkey_font_cache, &disposition);
4335 if(disposition == REG_CREATED_NEW_KEY)
4336 init_font_list();
4337 else
4338 load_font_list_from_cache(hkey_font_cache);
4340 reorder_font_list();
4342 DumpFontList();
4343 LoadSubstList();
4344 DumpSubstList();
4345 LoadReplaceList();
4347 if(disposition == REG_CREATED_NEW_KEY)
4348 update_reg_entries();
4350 init_system_links();
4352 ReleaseMutex(font_mutex);
4353 return TRUE;
4356 /* Some fonts have large usWinDescent values, as a result of storing signed short
4357 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
4358 some font generation tools. */
4359 static inline USHORT get_fixed_windescent(USHORT windescent)
4361 return abs((SHORT)windescent);
4364 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
4366 TT_OS2 *pOS2;
4367 TT_HoriHeader *pHori;
4369 LONG ppem;
4370 const LONG MAX_PPEM = (1 << 16) - 1;
4372 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4373 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4375 if(height == 0) height = 16;
4377 /* Calc. height of EM square:
4379 * For +ve lfHeight we have
4380 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
4381 * Re-arranging gives:
4382 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4384 * For -ve lfHeight we have
4385 * |lfHeight| = ppem
4386 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4387 * with il = winAscent + winDescent - units_per_em]
4391 if(height > 0) {
4392 USHORT windescent = get_fixed_windescent(pOS2->usWinDescent);
4393 if(pOS2->usWinAscent + windescent == 0)
4394 ppem = MulDiv(ft_face->units_per_EM, height,
4395 pHori->Ascender - pHori->Descender);
4396 else
4397 ppem = MulDiv(ft_face->units_per_EM, height,
4398 pOS2->usWinAscent + windescent);
4399 if(ppem > MAX_PPEM) {
4400 WARN("Ignoring too large height %d, ppem %d\n", height, ppem);
4401 ppem = 1;
4404 else if(height >= -MAX_PPEM)
4405 ppem = -height;
4406 else {
4407 WARN("Ignoring too large height %d\n", height);
4408 ppem = 1;
4411 return ppem;
4414 static struct font_mapping *map_font_file( const char *name )
4416 struct font_mapping *mapping;
4417 struct stat st;
4418 int fd;
4420 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
4421 if (fstat( fd, &st ) == -1) goto error;
4423 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
4425 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
4427 mapping->refcount++;
4428 close( fd );
4429 return mapping;
4432 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
4433 goto error;
4435 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
4436 close( fd );
4438 if (mapping->data == MAP_FAILED)
4440 HeapFree( GetProcessHeap(), 0, mapping );
4441 return NULL;
4443 mapping->refcount = 1;
4444 mapping->dev = st.st_dev;
4445 mapping->ino = st.st_ino;
4446 mapping->size = st.st_size;
4447 list_add_tail( &mappings_list, &mapping->entry );
4448 return mapping;
4450 error:
4451 close( fd );
4452 return NULL;
4455 static void unmap_font_file( struct font_mapping *mapping )
4457 if (!--mapping->refcount)
4459 list_remove( &mapping->entry );
4460 munmap( mapping->data, mapping->size );
4461 HeapFree( GetProcessHeap(), 0, mapping );
4465 static LONG load_VDMX(GdiFont*, LONG);
4467 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
4469 FT_Error err;
4470 FT_Face ft_face;
4471 void *data_ptr;
4472 DWORD data_size;
4474 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
4476 if (face->file)
4478 char *filename = strWtoA( CP_UNIXCP, face->file );
4479 font->mapping = map_font_file( filename );
4480 HeapFree( GetProcessHeap(), 0, filename );
4481 if (!font->mapping)
4483 WARN("failed to map %s\n", debugstr_w(face->file));
4484 return 0;
4486 data_ptr = font->mapping->data;
4487 data_size = font->mapping->size;
4489 else
4491 data_ptr = face->font_data_ptr;
4492 data_size = face->font_data_size;
4495 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
4496 if(err) {
4497 ERR("FT_New_Face rets %d\n", err);
4498 return 0;
4501 /* set it here, as load_VDMX needs it */
4502 font->ft_face = ft_face;
4504 if(FT_IS_SCALABLE(ft_face)) {
4505 /* load the VDMX table if we have one */
4506 font->ppem = load_VDMX(font, height);
4507 if(font->ppem == 0)
4508 font->ppem = calc_ppem_for_height(ft_face, height);
4509 TRACE("height %d => ppem %d\n", height, font->ppem);
4511 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
4512 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
4513 } else {
4514 font->ppem = height;
4515 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
4516 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
4518 return ft_face;
4522 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
4524 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4525 a single face with the requested charset. The idea is to check if
4526 the selected font supports the current ANSI codepage, if it does
4527 return the corresponding charset, else return the first charset */
4529 CHARSETINFO csi;
4530 int acp = GetACP(), i;
4531 DWORD fs0;
4533 *cp = acp;
4534 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
4536 const SYSTEM_LINKS *font_link;
4538 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4539 return csi.ciCharset;
4541 font_link = find_font_link(family_name);
4542 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4543 return csi.ciCharset;
4546 for(i = 0; i < 32; i++) {
4547 fs0 = 1L << i;
4548 if(face->fs.fsCsb[0] & fs0) {
4549 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4550 *cp = csi.ciACP;
4551 return csi.ciCharset;
4553 else
4554 FIXME("TCI failing on %x\n", fs0);
4558 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4559 face->fs.fsCsb[0], debugstr_w(face->file));
4560 *cp = acp;
4561 return DEFAULT_CHARSET;
4564 static GdiFont *alloc_font(void)
4566 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4567 ret->refcount = 1;
4568 ret->gmsize = 1;
4569 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4570 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4571 ret->potm = NULL;
4572 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4573 ret->total_kern_pairs = (DWORD)-1;
4574 ret->kern_pairs = NULL;
4575 ret->instance_id = alloc_font_handle(ret);
4576 list_init(&ret->child_fonts);
4577 return ret;
4580 static void free_font(GdiFont *font)
4582 CHILD_FONT *child, *child_next;
4583 DWORD i;
4585 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
4587 list_remove(&child->entry);
4588 if(child->font)
4589 free_font(child->font);
4590 release_face( child->face );
4591 HeapFree(GetProcessHeap(), 0, child);
4594 HeapFree(GetProcessHeap(), 0, font->fileinfo);
4595 free_font_handle(font->instance_id);
4596 if (font->ft_face) pFT_Done_Face(font->ft_face);
4597 if (font->mapping) unmap_font_file( font->mapping );
4598 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4599 HeapFree(GetProcessHeap(), 0, font->potm);
4600 HeapFree(GetProcessHeap(), 0, font->name);
4601 for (i = 0; i < font->gmsize; i++)
4602 HeapFree(GetProcessHeap(),0,font->gm[i]);
4603 HeapFree(GetProcessHeap(), 0, font->gm);
4604 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4605 HeapFree(GetProcessHeap(), 0, font);
4609 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4611 FT_Face ft_face = font->ft_face;
4612 FT_ULong len;
4613 FT_Error err;
4615 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4617 if(!buf)
4618 len = 0;
4619 else
4620 len = cbData;
4622 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4624 /* make sure value of len is the value freetype says it needs */
4625 if (buf && len)
4627 FT_ULong needed = 0;
4628 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4629 if( !err && needed < len) len = needed;
4631 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4632 if (err)
4634 TRACE("Can't find table %c%c%c%c\n",
4635 /* bytes were reversed */
4636 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4637 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4638 return GDI_ERROR;
4640 return len;
4643 /*************************************************************
4644 * load_VDMX
4646 * load the vdmx entry for the specified height
4649 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4650 ( ( (FT_ULong)_x4 << 24 ) | \
4651 ( (FT_ULong)_x3 << 16 ) | \
4652 ( (FT_ULong)_x2 << 8 ) | \
4653 (FT_ULong)_x1 )
4655 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4657 typedef struct {
4658 WORD version;
4659 WORD numRecs;
4660 WORD numRatios;
4661 } VDMX_Header;
4663 typedef struct {
4664 BYTE bCharSet;
4665 BYTE xRatio;
4666 BYTE yStartRatio;
4667 BYTE yEndRatio;
4668 } Ratios;
4670 typedef struct {
4671 WORD recs;
4672 BYTE startsz;
4673 BYTE endsz;
4674 } VDMX_group;
4676 typedef struct {
4677 WORD yPelHeight;
4678 WORD yMax;
4679 WORD yMin;
4680 } VDMX_vTable;
4682 static LONG load_VDMX(GdiFont *font, LONG height)
4684 VDMX_Header hdr;
4685 VDMX_group group;
4686 BYTE devXRatio, devYRatio;
4687 USHORT numRecs, numRatios;
4688 DWORD result, offset = -1;
4689 LONG ppem = 0;
4690 int i;
4692 result = get_font_data(font, MS_VDMX_TAG, 0, &hdr, sizeof(hdr));
4694 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4695 return ppem;
4697 /* FIXME: need the real device aspect ratio */
4698 devXRatio = 1;
4699 devYRatio = 1;
4701 numRecs = GET_BE_WORD(hdr.numRecs);
4702 numRatios = GET_BE_WORD(hdr.numRatios);
4704 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr.version), numRecs, numRatios);
4705 for(i = 0; i < numRatios; i++) {
4706 Ratios ratio;
4708 offset = sizeof(hdr) + (i * sizeof(Ratios));
4709 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4710 offset = -1;
4712 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4714 if (!ratio.bCharSet) continue;
4716 if((ratio.xRatio == 0 &&
4717 ratio.yStartRatio == 0 &&
4718 ratio.yEndRatio == 0) ||
4719 (devXRatio == ratio.xRatio &&
4720 devYRatio >= ratio.yStartRatio &&
4721 devYRatio <= ratio.yEndRatio))
4723 WORD group_offset;
4725 offset = sizeof(hdr) + numRatios * sizeof(ratio) + i * sizeof(group_offset);
4726 get_font_data(font, MS_VDMX_TAG, offset, &group_offset, sizeof(group_offset));
4727 offset = GET_BE_WORD(group_offset);
4728 break;
4732 if(offset == -1) return 0;
4734 if(get_font_data(font, MS_VDMX_TAG, offset, &group, sizeof(group)) != GDI_ERROR) {
4735 USHORT recs;
4736 BYTE startsz, endsz;
4737 WORD *vTable;
4739 recs = GET_BE_WORD(group.recs);
4740 startsz = group.startsz;
4741 endsz = group.endsz;
4743 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4745 vTable = HeapAlloc(GetProcessHeap(), 0, recs * sizeof(VDMX_vTable));
4746 result = get_font_data(font, MS_VDMX_TAG, offset + sizeof(group), vTable, recs * sizeof(VDMX_vTable));
4747 if(result == GDI_ERROR) {
4748 FIXME("Failed to retrieve vTable\n");
4749 goto end;
4752 if(height > 0) {
4753 for(i = 0; i < recs; i++) {
4754 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4755 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4756 ppem = GET_BE_WORD(vTable[i * 3]);
4758 if(yMax + -yMin == height) {
4759 font->yMax = yMax;
4760 font->yMin = yMin;
4761 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4762 break;
4764 if(yMax + -yMin > height) {
4765 if(--i < 0) {
4766 ppem = 0;
4767 goto end; /* failed */
4769 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4770 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4771 ppem = GET_BE_WORD(vTable[i * 3]);
4772 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4773 break;
4776 if(!font->yMax) {
4777 ppem = 0;
4778 TRACE("ppem not found for height %d\n", height);
4780 } else {
4781 ppem = -height;
4782 if(ppem < startsz || ppem > endsz)
4784 ppem = 0;
4785 goto end;
4788 for(i = 0; i < recs; i++) {
4789 USHORT yPelHeight;
4790 yPelHeight = GET_BE_WORD(vTable[i * 3]);
4792 if(yPelHeight > ppem)
4794 ppem = 0;
4795 break; /* failed */
4798 if(yPelHeight == ppem) {
4799 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4800 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4801 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
4802 break;
4806 end:
4807 HeapFree(GetProcessHeap(), 0, vTable);
4810 return ppem;
4813 static void dump_gdi_font_list(void)
4815 GdiFont *font;
4817 TRACE("---------- Font Cache ----------\n");
4818 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct tagGdiFont, entry )
4819 TRACE("font=%p ref=%u %s %d\n", font, font->refcount,
4820 debugstr_w(font->font_desc.lf.lfFaceName), font->font_desc.lf.lfHeight);
4823 static void grab_font( GdiFont *font )
4825 if (!font->refcount++)
4827 list_remove( &font->unused_entry );
4828 unused_font_count--;
4832 static void release_font( GdiFont *font )
4834 if (!font) return;
4835 if (!--font->refcount)
4837 TRACE( "font %p\n", font );
4839 /* add it to the unused list */
4840 list_add_head( &unused_gdi_font_list, &font->unused_entry );
4841 if (unused_font_count > UNUSED_CACHE_SIZE)
4843 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct tagGdiFont, unused_entry );
4844 TRACE( "freeing %p\n", font );
4845 list_remove( &font->entry );
4846 list_remove( &font->unused_entry );
4847 free_font( font );
4849 else unused_font_count++;
4851 if (TRACE_ON(font)) dump_gdi_font_list();
4855 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4857 if(font->font_desc.hash != fd->hash) return TRUE;
4858 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4859 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4860 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4861 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4864 static void calc_hash(FONT_DESC *pfd)
4866 DWORD hash = 0, *ptr, two_chars;
4867 WORD *pwc;
4868 unsigned int i;
4870 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4871 hash ^= *ptr;
4872 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4873 hash ^= *ptr;
4874 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4875 two_chars = *ptr;
4876 pwc = (WCHAR *)&two_chars;
4877 if(!*pwc) break;
4878 *pwc = toupperW(*pwc);
4879 pwc++;
4880 *pwc = toupperW(*pwc);
4881 hash ^= two_chars;
4882 if(!*pwc) break;
4884 hash ^= !pfd->can_use_bitmap;
4885 pfd->hash = hash;
4888 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4890 GdiFont *ret;
4891 FONT_DESC fd;
4893 fd.lf = *plf;
4894 fd.matrix = *pmat;
4895 fd.can_use_bitmap = can_use_bitmap;
4896 calc_hash(&fd);
4898 /* try the in-use list */
4899 LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
4901 if(fontcmp(ret, &fd)) continue;
4902 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4903 list_remove( &ret->entry );
4904 list_add_head( &gdi_font_list, &ret->entry );
4905 grab_font( ret );
4906 return ret;
4908 return NULL;
4911 static void add_to_cache(GdiFont *font)
4913 static DWORD cache_num = 1;
4915 font->cache_num = cache_num++;
4916 list_add_head(&gdi_font_list, &font->entry);
4917 TRACE( "font %p\n", font );
4920 /*************************************************************
4921 * create_child_font_list
4923 static BOOL create_child_font_list(GdiFont *font)
4925 BOOL ret = FALSE;
4926 SYSTEM_LINKS *font_link;
4927 CHILD_FONT *font_link_entry, *new_child;
4928 FontSubst *psub;
4929 WCHAR* font_name;
4931 psub = get_font_subst(&font_subst_list, font->name, -1);
4932 font_name = psub ? psub->to.name : font->name;
4933 font_link = find_font_link(font_name);
4934 if (font_link != NULL)
4936 TRACE("found entry in system list\n");
4937 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4939 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4940 new_child->face = font_link_entry->face;
4941 new_child->font = NULL;
4942 new_child->face->refcount++;
4943 list_add_tail(&font->child_fonts, &new_child->entry);
4944 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4946 ret = TRUE;
4949 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4950 * Sans Serif. This is how asian windows get default fallbacks for fonts
4952 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4953 font->charset != OEM_CHARSET &&
4954 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4956 font_link = find_font_link(szDefaultFallbackLink);
4957 if (font_link != NULL)
4959 TRACE("found entry in default fallback list\n");
4960 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4962 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4963 new_child->face = font_link_entry->face;
4964 new_child->font = NULL;
4965 new_child->face->refcount++;
4966 list_add_tail(&font->child_fonts, &new_child->entry);
4967 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4969 ret = TRUE;
4973 return ret;
4976 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4978 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4980 if (pFT_Set_Charmap)
4982 FT_Int i;
4983 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4985 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4987 for (i = 0; i < ft_face->num_charmaps; i++)
4989 if (ft_face->charmaps[i]->encoding == encoding)
4991 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4992 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4994 switch (ft_face->charmaps[i]->platform_id)
4996 default:
4997 cmap_def = ft_face->charmaps[i];
4998 break;
4999 case 0: /* Apple Unicode */
5000 cmap0 = ft_face->charmaps[i];
5001 break;
5002 case 1: /* Macintosh */
5003 cmap1 = ft_face->charmaps[i];
5004 break;
5005 case 2: /* ISO */
5006 cmap2 = ft_face->charmaps[i];
5007 break;
5008 case 3: /* Microsoft */
5009 cmap3 = ft_face->charmaps[i];
5010 break;
5014 if (cmap3) /* prefer Microsoft cmap table */
5015 ft_err = pFT_Set_Charmap(ft_face, cmap3);
5016 else if (cmap1)
5017 ft_err = pFT_Set_Charmap(ft_face, cmap1);
5018 else if (cmap2)
5019 ft_err = pFT_Set_Charmap(ft_face, cmap2);
5020 else if (cmap0)
5021 ft_err = pFT_Set_Charmap(ft_face, cmap0);
5022 else if (cmap_def)
5023 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
5025 return ft_err == FT_Err_Ok;
5028 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
5032 /*************************************************************
5033 * freetype_CreateDC
5035 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
5036 LPCWSTR output, const DEVMODEW *devmode )
5038 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
5040 if (!physdev) return FALSE;
5041 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
5042 return TRUE;
5046 /*************************************************************
5047 * freetype_DeleteDC
5049 static BOOL freetype_DeleteDC( PHYSDEV dev )
5051 struct freetype_physdev *physdev = get_freetype_dev( dev );
5052 release_font( physdev->font );
5053 HeapFree( GetProcessHeap(), 0, physdev );
5054 return TRUE;
5057 static FT_Encoding pick_charmap( FT_Face face, int charset )
5059 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
5060 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
5061 const FT_Encoding *encs = regular_order;
5063 if (charset == SYMBOL_CHARSET) encs = symbol_order;
5065 while (*encs != 0)
5067 if (select_charmap( face, *encs )) break;
5068 encs++;
5070 return *encs;
5073 #define GASP_GRIDFIT 0x01
5074 #define GASP_DOGRAY 0x02
5075 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
5077 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
5079 DWORD size;
5080 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
5081 WORD *alloced = NULL, *ptr = buf;
5082 WORD num_recs, version;
5083 BOOL ret = FALSE;
5085 *flags = 0;
5086 size = get_font_data( font, GASP_TAG, 0, NULL, 0 );
5087 if (size == GDI_ERROR) return FALSE;
5088 if (size < 4 * sizeof(WORD)) return FALSE;
5089 if (size > sizeof(buf))
5091 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
5092 if (!ptr) return FALSE;
5095 get_font_data( font, GASP_TAG, 0, ptr, size );
5097 version = GET_BE_WORD( *ptr++ );
5098 num_recs = GET_BE_WORD( *ptr++ );
5100 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
5102 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
5103 goto done;
5106 while (num_recs--)
5108 *flags = GET_BE_WORD( *(ptr + 1) );
5109 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
5110 ptr += 2;
5112 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
5113 ret = TRUE;
5115 done:
5116 HeapFree( GetProcessHeap(), 0, alloced );
5117 return ret;
5120 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5122 const GSUB_ScriptList *script;
5123 const GSUB_Script *deflt = NULL;
5124 int i;
5125 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5127 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5128 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5130 const GSUB_Script *scr;
5131 int offset;
5133 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5134 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5136 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5137 return scr;
5138 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5139 deflt = scr;
5141 return deflt;
5144 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5146 int i;
5147 int offset;
5148 const GSUB_LangSys *Lang;
5150 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5152 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5154 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5155 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5157 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5158 return Lang;
5160 offset = GET_BE_WORD(script->DefaultLangSys);
5161 if (offset)
5163 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5164 return Lang;
5166 return NULL;
5169 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5171 int i;
5172 const GSUB_FeatureList *feature;
5173 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5175 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5176 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5178 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5179 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5181 const GSUB_Feature *feat;
5182 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5183 return feat;
5186 return NULL;
5189 static const char* get_opentype_script(const GdiFont *font)
5192 * I am not sure if this is the correct way to generate our script tag
5195 switch (font->charset)
5197 case ANSI_CHARSET: return "latn";
5198 case BALTIC_CHARSET: return "latn"; /* ?? */
5199 case CHINESEBIG5_CHARSET: return "hani";
5200 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5201 case GB2312_CHARSET: return "hani";
5202 case GREEK_CHARSET: return "grek";
5203 case HANGUL_CHARSET: return "hang";
5204 case RUSSIAN_CHARSET: return "cyrl";
5205 case SHIFTJIS_CHARSET: return "kana";
5206 case TURKISH_CHARSET: return "latn"; /* ?? */
5207 case VIETNAMESE_CHARSET: return "latn";
5208 case JOHAB_CHARSET: return "latn"; /* ?? */
5209 case ARABIC_CHARSET: return "arab";
5210 case HEBREW_CHARSET: return "hebr";
5211 case THAI_CHARSET: return "thai";
5212 default: return "latn";
5216 static const VOID * get_GSUB_vert_feature(const GdiFont *font)
5218 const GSUB_Header *header;
5219 const GSUB_Script *script;
5220 const GSUB_LangSys *language;
5221 const GSUB_Feature *feature;
5223 if (!font->GSUB_Table)
5224 return NULL;
5226 header = font->GSUB_Table;
5228 script = GSUB_get_script_table(header, get_opentype_script(font));
5229 if (!script)
5231 TRACE("Script not found\n");
5232 return NULL;
5234 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5235 if (!language)
5237 TRACE("Language not found\n");
5238 return NULL;
5240 feature = GSUB_get_feature(header, language, "vrt2");
5241 if (!feature)
5242 feature = GSUB_get_feature(header, language, "vert");
5243 if (!feature)
5245 TRACE("vrt2/vert feature not found\n");
5246 return NULL;
5248 return feature;
5251 static void fill_fileinfo_from_face( GdiFont *font, Face *face )
5253 WIN32_FILE_ATTRIBUTE_DATA info;
5254 int len;
5256 if (!face->file)
5258 font->fileinfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*font->fileinfo));
5259 return;
5262 len = strlenW(face->file);
5263 font->fileinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*font->fileinfo) + len * sizeof(WCHAR));
5264 if (GetFileAttributesExW(face->file, GetFileExInfoStandard, &info))
5266 font->fileinfo->writetime = info.ftLastWriteTime;
5267 font->fileinfo->size.QuadPart = (LONGLONG)info.nFileSizeHigh << 32 | info.nFileSizeLow;
5268 strcpyW(font->fileinfo->path, face->file);
5270 else
5271 memset(font->fileinfo, 0, sizeof(*font->fileinfo) + len * sizeof(WCHAR));
5274 /*************************************************************
5275 * freetype_SelectFont
5277 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
5279 struct freetype_physdev *physdev = get_freetype_dev( dev );
5280 GdiFont *ret;
5281 Face *face, *best, *best_bitmap;
5282 Family *family, *last_resort_family;
5283 const struct list *face_list;
5284 INT height, width = 0;
5285 unsigned int score = 0, new_score;
5286 signed int diff = 0, newdiff;
5287 BOOL bd, it, can_use_bitmap, want_vertical;
5288 LOGFONTW lf;
5289 CHARSETINFO csi;
5290 FMAT2 dcmat;
5291 FontSubst *psub = NULL;
5292 DC *dc = get_dc_ptr( dev->hdc );
5293 const SYSTEM_LINKS *font_link;
5295 if (!hfont) /* notification that the font has been changed by another driver */
5297 release_font( physdev->font );
5298 physdev->font = NULL;
5299 release_dc_ptr( dc );
5300 return 0;
5303 GetObjectW( hfont, sizeof(lf), &lf );
5304 lf.lfWidth = abs(lf.lfWidth);
5306 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
5308 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
5309 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
5310 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
5311 lf.lfEscapement);
5313 if(dc->GraphicsMode == GM_ADVANCED)
5315 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
5316 /* Try to avoid not necessary glyph transformations */
5317 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
5319 lf.lfHeight *= fabs(dcmat.eM11);
5320 lf.lfWidth *= fabs(dcmat.eM11);
5321 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
5324 else
5326 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
5327 font scaling abilities. */
5328 dcmat.eM11 = dcmat.eM22 = 1.0;
5329 dcmat.eM21 = dcmat.eM12 = 0;
5330 lf.lfOrientation = lf.lfEscapement;
5331 if (dc->vport2WorldValid)
5333 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
5334 lf.lfOrientation = -lf.lfOrientation;
5335 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
5336 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
5340 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
5341 dcmat.eM21, dcmat.eM22);
5343 GDI_CheckNotLock();
5344 EnterCriticalSection( &freetype_cs );
5346 /* check the cache first */
5347 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5348 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
5349 goto done;
5352 TRACE("not in cache\n");
5353 ret = alloc_font();
5355 ret->font_desc.matrix = dcmat;
5356 ret->font_desc.lf = lf;
5357 ret->font_desc.can_use_bitmap = can_use_bitmap;
5358 calc_hash(&ret->font_desc);
5360 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
5361 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
5362 original value lfCharSet. Note this is a special case for
5363 Symbol and doesn't happen at least for "Wingdings*" */
5365 if(!strcmpiW(lf.lfFaceName, SymbolW))
5366 lf.lfCharSet = SYMBOL_CHARSET;
5368 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
5369 switch(lf.lfCharSet) {
5370 case DEFAULT_CHARSET:
5371 csi.fs.fsCsb[0] = 0;
5372 break;
5373 default:
5374 FIXME("Untranslated charset %d\n", lf.lfCharSet);
5375 csi.fs.fsCsb[0] = 0;
5376 break;
5380 family = NULL;
5381 if(lf.lfFaceName[0] != '\0') {
5382 CHILD_FONT *font_link_entry;
5383 LPWSTR FaceName = lf.lfFaceName;
5385 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
5387 if(psub) {
5388 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
5389 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
5390 if (psub->to.charset != -1)
5391 lf.lfCharSet = psub->to.charset;
5394 /* We want a match on name and charset or just name if
5395 charset was DEFAULT_CHARSET. If the latter then
5396 we fixup the returned charset later in get_nearest_charset
5397 where we'll either use the charset of the current ansi codepage
5398 or if that's unavailable the first charset that the font supports.
5400 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5401 if (!strcmpiW(family->FamilyName, FaceName) ||
5402 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
5404 font_link = find_font_link(family->FamilyName);
5405 face_list = get_face_list_from_family(family);
5406 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5407 if (!(face->scalable || can_use_bitmap))
5408 continue;
5409 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5410 goto found;
5411 if (font_link != NULL &&
5412 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5413 goto found;
5414 if (!csi.fs.fsCsb[0])
5415 goto found;
5420 /* Search by full face name. */
5421 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5422 face_list = get_face_list_from_family(family);
5423 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5424 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
5425 (face->scalable || can_use_bitmap))
5427 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5428 goto found_face;
5429 font_link = find_font_link(family->FamilyName);
5430 if (font_link != NULL &&
5431 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5432 goto found_face;
5438 * Try check the SystemLink list first for a replacement font.
5439 * We may find good replacements there.
5441 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
5443 if(!strcmpiW(font_link->font_name, FaceName) ||
5444 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
5446 TRACE("found entry in system list\n");
5447 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5449 const SYSTEM_LINKS *links;
5451 face = font_link_entry->face;
5452 if (!(face->scalable || can_use_bitmap))
5453 continue;
5454 family = face->family;
5455 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5456 goto found;
5457 links = find_font_link(family->FamilyName);
5458 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
5459 goto found;
5465 psub = NULL; /* substitution is no more relevant */
5467 /* If requested charset was DEFAULT_CHARSET then try using charset
5468 corresponding to the current ansi codepage */
5469 if (!csi.fs.fsCsb[0])
5471 INT acp = GetACP();
5472 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
5473 FIXME("TCI failed on codepage %d\n", acp);
5474 csi.fs.fsCsb[0] = 0;
5475 } else
5476 lf.lfCharSet = csi.ciCharset;
5479 want_vertical = (lf.lfFaceName[0] == '@');
5481 /* Face families are in the top 4 bits of lfPitchAndFamily,
5482 so mask with 0xF0 before testing */
5484 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
5485 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
5486 strcpyW(lf.lfFaceName, defFixed);
5487 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
5488 strcpyW(lf.lfFaceName, defSerif);
5489 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
5490 strcpyW(lf.lfFaceName, defSans);
5491 else
5492 strcpyW(lf.lfFaceName, defSans);
5493 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5494 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
5495 font_link = find_font_link(family->FamilyName);
5496 face_list = get_face_list_from_family(family);
5497 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5498 if (!(face->scalable || can_use_bitmap))
5499 continue;
5500 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5501 goto found;
5502 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5503 goto found;
5508 last_resort_family = NULL;
5509 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5510 font_link = find_font_link(family->FamilyName);
5511 face_list = get_face_list_from_family(family);
5512 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5513 if(!(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical &&
5514 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5515 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
5516 if(face->scalable)
5517 goto found;
5518 if(can_use_bitmap && !last_resort_family)
5519 last_resort_family = family;
5524 if(last_resort_family) {
5525 family = last_resort_family;
5526 csi.fs.fsCsb[0] = 0;
5527 goto found;
5530 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5531 face_list = get_face_list_from_family(family);
5532 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5533 if(face->scalable && !(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical) {
5534 csi.fs.fsCsb[0] = 0;
5535 WARN("just using first face for now\n");
5536 goto found;
5538 if(can_use_bitmap && !last_resort_family)
5539 last_resort_family = family;
5542 if(!last_resort_family) {
5543 FIXME("can't find a single appropriate font - bailing\n");
5544 free_font(ret);
5545 ret = NULL;
5546 goto done;
5549 WARN("could only find a bitmap font - this will probably look awful!\n");
5550 family = last_resort_family;
5551 csi.fs.fsCsb[0] = 0;
5553 found:
5554 it = lf.lfItalic ? 1 : 0;
5555 bd = lf.lfWeight > 550 ? 1 : 0;
5557 height = lf.lfHeight;
5559 face = best = best_bitmap = NULL;
5560 font_link = find_font_link(family->FamilyName);
5561 face_list = get_face_list_from_family(family);
5562 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5564 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5565 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
5566 !csi.fs.fsCsb[0])
5568 BOOL italic, bold;
5570 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
5571 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
5572 new_score = (italic ^ it) + (bold ^ bd);
5573 if(!best || new_score <= score)
5575 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5576 italic, bold, it, bd);
5577 score = new_score;
5578 best = face;
5579 if(best->scalable && score == 0) break;
5580 if(!best->scalable)
5582 if(height > 0)
5583 newdiff = height - (signed int)(best->size.height);
5584 else
5585 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
5586 if(!best_bitmap || new_score < score ||
5587 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
5589 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
5590 diff = newdiff;
5591 best_bitmap = best;
5592 if(score == 0 && diff == 0) break;
5598 if(best)
5599 face = best->scalable ? best : best_bitmap;
5600 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
5601 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
5603 found_face:
5604 height = lf.lfHeight;
5606 ret->fs = face->fs;
5608 if(csi.fs.fsCsb[0]) {
5609 ret->charset = lf.lfCharSet;
5610 ret->codepage = csi.ciACP;
5612 else
5613 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
5615 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
5616 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
5618 ret->aveWidth = height ? lf.lfWidth : 0;
5620 if(!face->scalable) {
5621 /* Windows uses integer scaling factors for bitmap fonts */
5622 INT scale, scaled_height;
5623 GdiFont *cachedfont;
5625 /* FIXME: rotation of bitmap fonts is ignored */
5626 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
5627 if (ret->aveWidth)
5628 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
5629 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
5630 dcmat.eM11 = dcmat.eM22 = 1.0;
5631 /* As we changed the matrix, we need to search the cache for the font again,
5632 * otherwise we might explode the cache. */
5633 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5634 TRACE("Found cached font after non-scalable matrix rescale!\n");
5635 free_font( ret );
5636 ret = cachedfont;
5637 goto done;
5639 calc_hash(&ret->font_desc);
5641 if (height != 0) height = diff;
5642 height += face->size.height;
5644 scale = (height + face->size.height - 1) / face->size.height;
5645 scaled_height = scale * face->size.height;
5646 /* Only jump to the next height if the difference <= 25% original height */
5647 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
5648 /* The jump between unscaled and doubled is delayed by 1 */
5649 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
5650 ret->scale_y = scale;
5652 width = face->size.x_ppem >> 6;
5653 height = face->size.y_ppem >> 6;
5655 else
5656 ret->scale_y = 1.0;
5657 TRACE("font scale y: %f\n", ret->scale_y);
5659 ret->ft_face = OpenFontFace(ret, face, width, height);
5661 if (!ret->ft_face)
5663 free_font( ret );
5664 ret = NULL;
5665 goto done;
5668 fill_fileinfo_from_face( ret, face );
5669 ret->ntmFlags = face->ntmFlags;
5671 pick_charmap( ret->ft_face, ret->charset );
5673 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
5674 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
5675 ret->underline = lf.lfUnderline ? 0xff : 0;
5676 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
5677 create_child_font_list(ret);
5679 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
5681 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
5682 if (length != GDI_ERROR)
5684 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
5685 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
5686 TRACE("Loaded GSUB table of %i bytes\n",length);
5687 ret->vert_feature = get_GSUB_vert_feature(ret);
5688 if (!ret->vert_feature)
5690 TRACE("Vertical feature not found\n");
5691 HeapFree(GetProcessHeap(), 0, ret->GSUB_Table);
5692 ret->GSUB_Table = NULL;
5696 ret->aa_flags = HIWORD( face->flags );
5698 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
5700 add_to_cache(ret);
5701 done:
5702 if (ret)
5704 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
5706 switch (lf.lfQuality)
5708 case NONANTIALIASED_QUALITY:
5709 case ANTIALIASED_QUALITY:
5710 next->funcs->pSelectFont( dev, hfont, aa_flags );
5711 break;
5712 case CLEARTYPE_QUALITY:
5713 case CLEARTYPE_NATURAL_QUALITY:
5714 default:
5715 if (!*aa_flags) *aa_flags = ret->aa_flags;
5716 next->funcs->pSelectFont( dev, hfont, aa_flags );
5718 /* fixup the antialiasing flags for that font */
5719 switch (*aa_flags)
5721 case WINE_GGO_HRGB_BITMAP:
5722 case WINE_GGO_HBGR_BITMAP:
5723 case WINE_GGO_VRGB_BITMAP:
5724 case WINE_GGO_VBGR_BITMAP:
5725 if (is_subpixel_rendering_enabled()) break;
5726 *aa_flags = GGO_GRAY4_BITMAP;
5727 /* fall through */
5728 case GGO_GRAY2_BITMAP:
5729 case GGO_GRAY4_BITMAP:
5730 case GGO_GRAY8_BITMAP:
5731 case WINE_GGO_GRAY16_BITMAP:
5732 if ((!antialias_fakes || (!ret->fake_bold && !ret->fake_italic)) && is_hinting_enabled())
5734 WORD gasp_flags;
5735 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
5737 TRACE( "font %s %d aa disabled by GASP\n",
5738 debugstr_w(lf.lfFaceName), lf.lfHeight );
5739 *aa_flags = GGO_BITMAP;
5744 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5745 release_font( physdev->font );
5746 physdev->font = ret;
5748 LeaveCriticalSection( &freetype_cs );
5749 release_dc_ptr( dc );
5750 return ret ? hfont : 0;
5753 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5755 HRSRC rsrc;
5756 HGLOBAL hMem;
5757 WCHAR *p;
5758 int i;
5760 id += IDS_FIRST_SCRIPT;
5761 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5762 if (!rsrc) return 0;
5763 hMem = LoadResource( gdi32_module, rsrc );
5764 if (!hMem) return 0;
5766 p = LockResource( hMem );
5767 id &= 0x000f;
5768 while (id--) p += *p + 1;
5770 i = min(LF_FACESIZE - 1, *p);
5771 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5772 buffer[i] = 0;
5773 return i;
5776 static inline BOOL is_complex_script_ansi_cp(UINT ansi_cp)
5778 return (ansi_cp == 874 /* Thai */
5779 || ansi_cp == 1255 /* Hebrew */
5780 || ansi_cp == 1256 /* Arabic */
5784 /***************************************************
5785 * create_enum_charset_list
5787 * This function creates charset enumeration list because in DEFAULT_CHARSET
5788 * case, the ANSI codepage's charset takes precedence over other charsets.
5789 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
5790 * This function works as a filter other than DEFAULT_CHARSET case.
5792 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5794 CHARSETINFO csi;
5795 DWORD n = 0;
5797 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5798 csi.fs.fsCsb[0] != 0) {
5799 list->element[n].mask = csi.fs.fsCsb[0];
5800 list->element[n].charset = csi.ciCharset;
5801 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5802 n++;
5804 else { /* charset is DEFAULT_CHARSET or invalid. */
5805 INT acp, i;
5806 DWORD mask = 0;
5808 /* Set the current codepage's charset as the first element. */
5809 acp = GetACP();
5810 if (!is_complex_script_ansi_cp(acp) &&
5811 TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5812 csi.fs.fsCsb[0] != 0) {
5813 list->element[n].mask = csi.fs.fsCsb[0];
5814 list->element[n].charset = csi.ciCharset;
5815 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5816 mask |= csi.fs.fsCsb[0];
5817 n++;
5820 /* Fill out left elements. */
5821 for (i = 0; i < 32; i++) {
5822 FONTSIGNATURE fs;
5823 fs.fsCsb[0] = 1L << i;
5824 fs.fsCsb[1] = 0;
5825 if (fs.fsCsb[0] & mask)
5826 continue; /* skip, already added. */
5827 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5828 continue; /* skip, this is an invalid fsCsb bit. */
5830 list->element[n].mask = fs.fsCsb[0];
5831 list->element[n].charset = csi.ciCharset;
5832 load_script_name( i, list->element[n].name );
5833 mask |= fs.fsCsb[0];
5834 n++;
5837 /* add catch all mask for remaining bits */
5838 if (~mask)
5840 list->element[n].mask = ~mask;
5841 list->element[n].charset = DEFAULT_CHARSET;
5842 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5843 n++;
5846 list->total = n;
5848 return n;
5851 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
5852 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5854 GdiFont *font;
5855 LONG width, height;
5857 if (face->cached_enum_data)
5859 TRACE("Cached\n");
5860 *pelf = face->cached_enum_data->elf;
5861 *pntm = face->cached_enum_data->ntm;
5862 *ptype = face->cached_enum_data->type;
5863 return;
5866 font = alloc_font();
5868 if(face->scalable) {
5869 height = 100;
5870 width = 0;
5871 } else {
5872 height = face->size.y_ppem >> 6;
5873 width = face->size.x_ppem >> 6;
5875 font->scale_y = 1.0;
5877 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5879 free_font(font);
5880 return;
5883 font->name = strdupW( family_name );
5884 font->ntmFlags = face->ntmFlags;
5886 if (get_outline_text_metrics(font))
5888 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5890 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5891 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5892 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5894 lstrcpynW(pelf->elfLogFont.lfFaceName,
5895 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5896 LF_FACESIZE);
5897 lstrcpynW(pelf->elfFullName,
5898 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5899 LF_FULLFACESIZE);
5900 lstrcpynW(pelf->elfStyle,
5901 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5902 LF_FACESIZE);
5904 else
5906 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5908 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5909 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5910 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5912 lstrcpynW(pelf->elfLogFont.lfFaceName, family_name, LF_FACESIZE);
5913 if (face->FullName)
5914 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5915 else
5916 lstrcpynW(pelf->elfFullName, family_name, LF_FULLFACESIZE);
5917 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5920 pntm->ntmTm.ntmFlags = face->ntmFlags;
5921 pntm->ntmFontSig = face->fs;
5923 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5925 pelf->elfLogFont.lfEscapement = 0;
5926 pelf->elfLogFont.lfOrientation = 0;
5927 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5928 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5929 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5930 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5931 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5932 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5933 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5934 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5935 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5936 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5937 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5939 *ptype = 0;
5940 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5941 *ptype |= TRUETYPE_FONTTYPE;
5942 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5943 *ptype |= DEVICE_FONTTYPE;
5944 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5945 *ptype |= RASTER_FONTTYPE;
5947 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5948 if (face->cached_enum_data)
5950 face->cached_enum_data->elf = *pelf;
5951 face->cached_enum_data->ntm = *pntm;
5952 face->cached_enum_data->type = *ptype;
5955 free_font(font);
5958 static BOOL family_matches(Family *family, const WCHAR *face_name)
5960 Face *face;
5961 const struct list *face_list;
5963 if (!strcmpiW(face_name, family->FamilyName)) return TRUE;
5965 face_list = get_face_list_from_family(family);
5966 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5967 if (face->FullName && !strcmpiW(face_name, face->FullName)) return TRUE;
5969 return FALSE;
5972 static BOOL face_matches(const WCHAR *family_name, Face *face, const WCHAR *face_name)
5974 if (!strcmpiW(face_name, family_name)) return TRUE;
5976 return (face->FullName && !strcmpiW(face_name, face->FullName));
5979 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5980 FONTENUMPROCW proc, LPARAM lparam, const WCHAR *subst)
5982 ENUMLOGFONTEXW elf;
5983 NEWTEXTMETRICEXW ntm;
5984 DWORD type = 0;
5985 DWORD i;
5987 GetEnumStructs(face, face->family->FamilyName, &elf, &ntm, &type);
5988 for(i = 0; i < list->total; i++) {
5989 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5990 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5991 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
5992 i = list->total; /* break out of loop after enumeration */
5994 else
5996 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
5997 /* use the DEFAULT_CHARSET case only if no other charset is present */
5998 if (list->element[i].charset == DEFAULT_CHARSET &&
5999 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
6000 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
6001 strcpyW(elf.elfScript, list->element[i].name);
6002 if (!elf.elfScript[0])
6003 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
6005 /* Font Replacement */
6006 if (family != face->family)
6008 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
6009 if (face->FullName)
6010 strcpyW(elf.elfFullName, face->FullName);
6011 else
6012 strcpyW(elf.elfFullName, family->FamilyName);
6014 if (subst)
6015 strcpyW(elf.elfLogFont.lfFaceName, subst);
6016 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
6017 debugstr_w(elf.elfLogFont.lfFaceName),
6018 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
6019 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
6020 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
6021 ntm.ntmTm.ntmFlags);
6022 /* release section before callback (FIXME) */
6023 LeaveCriticalSection( &freetype_cs );
6024 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
6025 EnterCriticalSection( &freetype_cs );
6027 return TRUE;
6030 /*************************************************************
6031 * freetype_EnumFonts
6033 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
6035 Family *family;
6036 Face *face;
6037 const struct list *face_list;
6038 LOGFONTW lf;
6039 struct enum_charset_list enum_charsets;
6041 if (!plf)
6043 lf.lfCharSet = DEFAULT_CHARSET;
6044 lf.lfPitchAndFamily = 0;
6045 lf.lfFaceName[0] = 0;
6046 plf = &lf;
6049 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
6051 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
6053 GDI_CheckNotLock();
6054 EnterCriticalSection( &freetype_cs );
6055 if(plf->lfFaceName[0]) {
6056 WCHAR *face_name = plf->lfFaceName;
6057 FontSubst *psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
6059 if(psub) {
6060 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
6061 debugstr_w(psub->to.name));
6062 face_name = psub->to.name;
6065 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
6066 if (!family_matches(family, face_name)) continue;
6067 face_list = get_face_list_from_family(family);
6068 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
6069 if (!face_matches(family->FamilyName, face, face_name)) continue;
6070 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam, psub ? psub->from.name : NULL)) return FALSE;
6073 } else {
6074 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
6075 face_list = get_face_list_from_family(family);
6076 face = LIST_ENTRY(list_head(face_list), Face, entry);
6077 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam, NULL)) return FALSE;
6080 LeaveCriticalSection( &freetype_cs );
6081 return TRUE;
6084 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
6086 pt->x.value = vec->x >> 6;
6087 pt->x.fract = (vec->x & 0x3f) << 10;
6088 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
6089 pt->y.value = vec->y >> 6;
6090 pt->y.fract = (vec->y & 0x3f) << 10;
6091 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
6094 /***************************************************
6095 * According to the MSDN documentation on WideCharToMultiByte,
6096 * certain codepages cannot set the default_used parameter.
6097 * This returns TRUE if the codepage can set that parameter, false else
6098 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
6100 static BOOL codepage_sets_default_used(UINT codepage)
6102 switch (codepage)
6104 case CP_UTF7:
6105 case CP_UTF8:
6106 case CP_SYMBOL:
6107 return FALSE;
6108 default:
6109 return TRUE;
6114 * GSUB Table handling functions
6117 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
6119 const GSUB_CoverageFormat1* cf1;
6121 cf1 = table;
6123 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
6125 int count = GET_BE_WORD(cf1->GlyphCount);
6126 int i;
6127 TRACE("Coverage Format 1, %i glyphs\n",count);
6128 for (i = 0; i < count; i++)
6129 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
6130 return i;
6131 return -1;
6133 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
6135 const GSUB_CoverageFormat2* cf2;
6136 int i;
6137 int count;
6138 cf2 = (const GSUB_CoverageFormat2*)cf1;
6140 count = GET_BE_WORD(cf2->RangeCount);
6141 TRACE("Coverage Format 2, %i ranges\n",count);
6142 for (i = 0; i < count; i++)
6144 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
6145 return -1;
6146 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
6147 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
6149 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
6150 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
6153 return -1;
6155 else
6156 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
6158 return -1;
6161 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
6163 int i;
6164 int offset;
6165 const GSUB_LookupList *lookup;
6166 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
6168 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
6169 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
6171 const GSUB_LookupTable *look;
6172 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
6173 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
6174 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
6175 if (GET_BE_WORD(look->LookupType) != 1)
6176 FIXME("We only handle SubType 1\n");
6177 else
6179 int j;
6181 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
6183 const GSUB_SingleSubstFormat1 *ssf1;
6184 offset = GET_BE_WORD(look->SubTable[j]);
6185 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
6186 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
6188 int offset = GET_BE_WORD(ssf1->Coverage);
6189 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
6190 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
6192 TRACE(" Glyph 0x%x ->",glyph);
6193 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
6194 TRACE(" 0x%x\n",glyph);
6197 else
6199 const GSUB_SingleSubstFormat2 *ssf2;
6200 INT index;
6201 INT offset;
6203 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
6204 offset = GET_BE_WORD(ssf1->Coverage);
6205 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
6206 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
6207 TRACE(" Coverage index %i\n",index);
6208 if (index != -1)
6210 TRACE(" Glyph is 0x%x ->",glyph);
6211 glyph = GET_BE_WORD(ssf2->Substitute[index]);
6212 TRACE("0x%x\n",glyph);
6218 return glyph;
6222 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
6224 const GSUB_Header *header;
6225 const GSUB_Feature *feature;
6227 if (!font->GSUB_Table)
6228 return glyph;
6230 header = font->GSUB_Table;
6231 feature = font->vert_feature;
6233 return GSUB_apply_feature(header, feature, glyph);
6236 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
6238 FT_UInt glyphId;
6240 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
6241 WCHAR wc = (WCHAR)glyph;
6242 BOOL default_used;
6243 BOOL *default_used_pointer;
6244 FT_UInt ret;
6245 char buf;
6246 default_used_pointer = NULL;
6247 default_used = FALSE;
6248 if (codepage_sets_default_used(font->codepage))
6249 default_used_pointer = &default_used;
6250 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
6252 if (font->codepage == CP_SYMBOL && wc < 0x100)
6253 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
6254 else
6255 ret = 0;
6257 else
6258 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
6259 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6260 return ret;
6263 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
6265 if (glyph < 0x100) glyph += 0xf000;
6266 /* there is a number of old pre-Unicode "broken" TTFs, which
6267 do have symbols at U+00XX instead of U+f0XX */
6268 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
6269 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
6271 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
6273 return glyphId;
6276 /* helper for freetype_GetGlyphIndices */
6277 static FT_UInt get_gdi_glyph_index(const GdiFont *font, UINT glyph)
6279 WCHAR wc = (WCHAR)glyph;
6280 BOOL default_used = FALSE;
6281 BOOL *default_used_pointer = NULL;
6282 FT_UInt ret;
6283 char buf;
6285 if(font->ft_face->charmap->encoding != FT_ENCODING_NONE)
6286 return get_glyph_index(font, glyph);
6288 if (codepage_sets_default_used(font->codepage))
6289 default_used_pointer = &default_used;
6290 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer)
6291 || default_used)
6293 if (font->codepage == CP_SYMBOL && wc < 0x100)
6294 ret = (unsigned char)wc;
6295 else
6296 ret = 0;
6298 else
6299 ret = (unsigned char)buf;
6300 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6301 return ret;
6304 static FT_UInt get_default_char_index(GdiFont *font)
6306 FT_UInt default_char;
6308 if (FT_IS_SFNT(font->ft_face))
6310 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
6311 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
6313 else
6315 TEXTMETRICW textm;
6316 get_text_metrics(font, &textm);
6317 default_char = textm.tmDefaultChar;
6320 return default_char;
6323 /*************************************************************
6324 * freetype_GetGlyphIndices
6326 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
6328 struct freetype_physdev *physdev = get_freetype_dev( dev );
6329 int i;
6330 WORD default_char;
6331 BOOL got_default = FALSE;
6333 if (!physdev->font)
6335 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
6336 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
6339 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
6341 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
6342 got_default = TRUE;
6345 GDI_CheckNotLock();
6346 EnterCriticalSection( &freetype_cs );
6348 for(i = 0; i < count; i++)
6350 pgi[i] = get_gdi_glyph_index(physdev->font, lpstr[i]);
6351 if (pgi[i] == 0)
6353 if (!got_default)
6355 default_char = get_default_char_index(physdev->font);
6356 got_default = TRUE;
6358 pgi[i] = default_char;
6360 else
6361 pgi[i] = get_GSUB_vert_glyph(physdev->font, pgi[i]);
6363 LeaveCriticalSection( &freetype_cs );
6364 return count;
6367 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
6369 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
6370 return !memcmp(matrix, &identity, sizeof(FMAT2));
6373 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
6375 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
6376 return !memcmp(matrix, &identity, sizeof(MAT2));
6379 static void synthesize_bold_glyph(FT_GlyphSlot glyph, LONG ppem, FT_Glyph_Metrics *metrics)
6381 FT_Error err;
6382 static UINT once;
6384 switch(glyph->format) {
6385 case FT_GLYPH_FORMAT_OUTLINE:
6387 FT_Pos strength;
6388 FT_BBox bbox;
6389 if(!pFT_Outline_Embolden)
6390 break;
6392 strength = MulDiv(ppem, 1 << 6, 24);
6393 err = pFT_Outline_Embolden(&glyph->outline, strength);
6394 if(err) {
6395 TRACE("FT_Ouline_Embolden returns %d, ignored\n", err);
6396 break;
6399 pFT_Outline_Get_CBox(&glyph->outline, &bbox);
6400 metrics->width = bbox.xMax - bbox.xMin;
6401 metrics->height = bbox.yMax - bbox.yMin;
6402 metrics->horiBearingX = bbox.xMin;
6403 metrics->horiBearingY = bbox.yMax;
6404 metrics->horiAdvance += (1 << 6);
6405 metrics->vertAdvance += (1 << 6);
6406 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
6407 metrics->vertBearingY = (metrics->vertAdvance - metrics->height) / 2;
6408 break;
6410 default:
6411 if (!once++)
6412 WARN("Emboldening format 0x%x is not supported\n", glyph->format);
6413 return;
6417 static inline BYTE get_max_level( UINT format )
6419 switch( format )
6421 case GGO_GRAY2_BITMAP: return 4;
6422 case GGO_GRAY4_BITMAP: return 16;
6423 case GGO_GRAY8_BITMAP: return 64;
6425 return 255;
6428 extern const unsigned short vertical_orientation_table[];
6430 static BOOL check_unicode_tategaki(WCHAR uchar)
6432 unsigned short orientation = vertical_orientation_table[vertical_orientation_table[vertical_orientation_table[uchar >> 8]+((uchar >> 4) & 0x0f)]+ (uchar & 0xf)];
6434 /* We only reach this code if typographical substitution did not occur */
6435 /* Type: U or Type: Tu */
6436 return (orientation == 1 || orientation == 3);
6439 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
6441 TTPOLYGONHEADER *pph;
6442 TTPOLYCURVE *ppc;
6443 unsigned int needed = 0, point = 0, contour, first_pt;
6444 unsigned int pph_start, cpfx;
6445 DWORD type;
6447 for (contour = 0; contour < outline->n_contours; contour++)
6449 /* Ignore contours containing one point */
6450 if (point == outline->contours[contour])
6452 point++;
6453 continue;
6456 pph_start = needed;
6457 pph = (TTPOLYGONHEADER *)(buf + needed);
6458 first_pt = point;
6459 if (buf)
6461 pph->dwType = TT_POLYGON_TYPE;
6462 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6464 needed += sizeof(*pph);
6465 point++;
6466 while (point <= outline->contours[contour])
6468 ppc = (TTPOLYCURVE *)(buf + needed);
6469 type = outline->tags[point] & FT_Curve_Tag_On ?
6470 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6471 cpfx = 0;
6474 if (buf)
6475 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6476 cpfx++;
6477 point++;
6478 } while (point <= outline->contours[contour] &&
6479 (outline->tags[point] & FT_Curve_Tag_On) ==
6480 (outline->tags[point-1] & FT_Curve_Tag_On));
6481 /* At the end of a contour Windows adds the start point, but
6482 only for Beziers */
6483 if (point > outline->contours[contour] &&
6484 !(outline->tags[point-1] & FT_Curve_Tag_On))
6486 if (buf)
6487 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6488 cpfx++;
6490 else if (point <= outline->contours[contour] &&
6491 outline->tags[point] & FT_Curve_Tag_On)
6493 /* add closing pt for bezier */
6494 if (buf)
6495 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6496 cpfx++;
6497 point++;
6499 if (buf)
6501 ppc->wType = type;
6502 ppc->cpfx = cpfx;
6504 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6506 if (buf)
6507 pph->cb = needed - pph_start;
6509 return needed;
6512 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
6514 /* Convert the quadratic Beziers to cubic Beziers.
6515 The parametric eqn for a cubic Bezier is, from PLRM:
6516 r(t) = at^3 + bt^2 + ct + r0
6517 with the control points:
6518 r1 = r0 + c/3
6519 r2 = r1 + (c + b)/3
6520 r3 = r0 + c + b + a
6522 A quadratic Bezier has the form:
6523 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6525 So equating powers of t leads to:
6526 r1 = 2/3 p1 + 1/3 p0
6527 r2 = 2/3 p1 + 1/3 p2
6528 and of course r0 = p0, r3 = p2
6530 int contour, point = 0, first_pt;
6531 TTPOLYGONHEADER *pph;
6532 TTPOLYCURVE *ppc;
6533 DWORD pph_start, cpfx, type;
6534 FT_Vector cubic_control[4];
6535 unsigned int needed = 0;
6537 for (contour = 0; contour < outline->n_contours; contour++)
6539 pph_start = needed;
6540 pph = (TTPOLYGONHEADER *)(buf + needed);
6541 first_pt = point;
6542 if (buf)
6544 pph->dwType = TT_POLYGON_TYPE;
6545 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6547 needed += sizeof(*pph);
6548 point++;
6549 while (point <= outline->contours[contour])
6551 ppc = (TTPOLYCURVE *)(buf + needed);
6552 type = outline->tags[point] & FT_Curve_Tag_On ?
6553 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6554 cpfx = 0;
6557 if (type == TT_PRIM_LINE)
6559 if (buf)
6560 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6561 cpfx++;
6562 point++;
6564 else
6566 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6567 so cpfx = 3n */
6569 /* FIXME: Possible optimization in endpoint calculation
6570 if there are two consecutive curves */
6571 cubic_control[0] = outline->points[point-1];
6572 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
6574 cubic_control[0].x += outline->points[point].x + 1;
6575 cubic_control[0].y += outline->points[point].y + 1;
6576 cubic_control[0].x >>= 1;
6577 cubic_control[0].y >>= 1;
6579 if (point+1 > outline->contours[contour])
6580 cubic_control[3] = outline->points[first_pt];
6581 else
6583 cubic_control[3] = outline->points[point+1];
6584 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
6586 cubic_control[3].x += outline->points[point].x + 1;
6587 cubic_control[3].y += outline->points[point].y + 1;
6588 cubic_control[3].x >>= 1;
6589 cubic_control[3].y >>= 1;
6592 /* r1 = 1/3 p0 + 2/3 p1
6593 r2 = 1/3 p2 + 2/3 p1 */
6594 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6595 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6596 cubic_control[2] = cubic_control[1];
6597 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6598 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6599 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6600 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6601 if (buf)
6603 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6604 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6605 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6607 cpfx += 3;
6608 point++;
6610 } while (point <= outline->contours[contour] &&
6611 (outline->tags[point] & FT_Curve_Tag_On) ==
6612 (outline->tags[point-1] & FT_Curve_Tag_On));
6613 /* At the end of a contour Windows adds the start point,
6614 but only for Beziers and we've already done that.
6616 if (point <= outline->contours[contour] &&
6617 outline->tags[point] & FT_Curve_Tag_On)
6619 /* This is the closing pt of a bezier, but we've already
6620 added it, so just inc point and carry on */
6621 point++;
6623 if (buf)
6625 ppc->wType = type;
6626 ppc->cpfx = cpfx;
6628 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6630 if (buf)
6631 pph->cb = needed - pph_start;
6633 return needed;
6636 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6638 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
6639 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
6640 const MAT2* lpmat)
6642 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
6643 GLYPHMETRICS gm;
6644 FT_Face ft_face = incoming_font->ft_face;
6645 GdiFont *font = incoming_font;
6646 FT_Glyph_Metrics metrics;
6647 FT_UInt glyph_index;
6648 DWORD width, height, pitch, needed = 0;
6649 FT_Bitmap ft_bitmap;
6650 FT_Error err;
6651 INT left, right, top = 0, bottom = 0, adv;
6652 INT origin_x = 0, origin_y = 0;
6653 FT_Angle angle = 0;
6654 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
6655 double widthRatio = 1.0;
6656 FT_Matrix transMat = identityMat;
6657 FT_Matrix transMatUnrotated;
6658 FT_Matrix transMatTategaki;
6659 BOOL needsTransform = FALSE;
6660 BOOL tategaki = (font->name[0] == '@');
6661 BOOL vertical_metrics;
6662 UINT original_index;
6663 LONG avgAdvance = 0;
6664 FT_Fixed em_scale;
6666 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
6667 buflen, buf, lpmat);
6669 TRACE("font transform %f %f %f %f\n",
6670 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
6671 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
6673 if(format & GGO_GLYPH_INDEX) {
6674 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
6675 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
6676 as glyph index. "Treasure Adventure Game" depends on this. */
6677 glyph_index = pFT_Get_Char_Index(font->ft_face, glyph);
6678 TRACE("translate glyph index %04x -> %04x\n", glyph, glyph_index);
6679 } else
6680 glyph_index = glyph;
6681 original_index = glyph_index;
6682 format &= ~GGO_GLYPH_INDEX;
6683 /* TODO: Window also turns off tategaki for glyphs passed in by index
6684 if their unicode code points fall outside of the range that is
6685 rotated. */
6686 } else {
6687 BOOL vert;
6688 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index, &vert);
6689 ft_face = font->ft_face;
6690 original_index = glyph_index;
6691 if (!vert && tategaki)
6692 tategaki = check_unicode_tategaki(glyph);
6695 if(format & GGO_UNHINTED) {
6696 load_flags |= FT_LOAD_NO_HINTING;
6697 format &= ~GGO_UNHINTED;
6700 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
6701 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
6702 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
6703 font->gmsize * sizeof(GM*));
6704 } else {
6705 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
6706 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
6708 *lpgm = FONT_GM(font,original_index)->gm;
6709 *abc = FONT_GM(font,original_index)->abc;
6710 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6711 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6712 lpgm->gmCellIncX, lpgm->gmCellIncY);
6713 return 1; /* FIXME */
6717 if (!font->gm[original_index / GM_BLOCK_SIZE])
6718 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
6720 /* Scaling factor */
6721 if (font->aveWidth)
6723 TEXTMETRICW tm;
6725 get_text_metrics(font, &tm);
6727 widthRatio = (double)font->aveWidth;
6728 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6730 else
6731 widthRatio = font->scale_y;
6733 /* Scaling transform */
6734 if (widthRatio != 1.0 || font->scale_y != 1.0)
6736 FT_Matrix scaleMat;
6737 scaleMat.xx = FT_FixedFromFloat(widthRatio);
6738 scaleMat.xy = 0;
6739 scaleMat.yx = 0;
6740 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
6742 pFT_Matrix_Multiply(&scaleMat, &transMat);
6743 needsTransform = TRUE;
6746 /* Slant transform */
6747 if (font->fake_italic) {
6748 FT_Matrix slantMat;
6750 slantMat.xx = (1 << 16);
6751 slantMat.xy = ((1 << 16) >> 2);
6752 slantMat.yx = 0;
6753 slantMat.yy = (1 << 16);
6754 pFT_Matrix_Multiply(&slantMat, &transMat);
6755 needsTransform = TRUE;
6758 /* Rotation transform */
6759 transMatUnrotated = transMat;
6760 transMatTategaki = transMat;
6761 if(font->orientation || tategaki) {
6762 FT_Matrix rotationMat;
6763 FT_Matrix taterotationMat;
6764 FT_Vector vecAngle;
6766 double orient = font->orientation / 10.0;
6767 double tate_orient = 0.f;
6769 if (tategaki)
6770 tate_orient = ((font->orientation+900)%3600)/10.0;
6771 else
6772 tate_orient = font->orientation/10.0;
6774 if (orient)
6776 angle = FT_FixedFromFloat(orient);
6777 pFT_Vector_Unit(&vecAngle, angle);
6778 rotationMat.xx = vecAngle.x;
6779 rotationMat.xy = -vecAngle.y;
6780 rotationMat.yx = -rotationMat.xy;
6781 rotationMat.yy = rotationMat.xx;
6783 pFT_Matrix_Multiply(&rotationMat, &transMat);
6786 if (tate_orient)
6788 angle = FT_FixedFromFloat(tate_orient);
6789 pFT_Vector_Unit(&vecAngle, angle);
6790 taterotationMat.xx = vecAngle.x;
6791 taterotationMat.xy = -vecAngle.y;
6792 taterotationMat.yx = -taterotationMat.xy;
6793 taterotationMat.yy = taterotationMat.xx;
6794 pFT_Matrix_Multiply(&taterotationMat, &transMatTategaki);
6797 needsTransform = TRUE;
6800 /* World transform */
6801 if (!is_identity_FMAT2(&font->font_desc.matrix))
6803 FT_Matrix worldMat;
6804 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
6805 worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21);
6806 worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12);
6807 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
6808 pFT_Matrix_Multiply(&worldMat, &transMat);
6809 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
6810 pFT_Matrix_Multiply(&worldMat, &transMatTategaki);
6811 needsTransform = TRUE;
6814 /* Extra transformation specified by caller */
6815 if (!is_identity_MAT2(lpmat))
6817 FT_Matrix extraMat;
6818 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
6819 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
6820 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
6821 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
6822 pFT_Matrix_Multiply(&extraMat, &transMat);
6823 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
6824 pFT_Matrix_Multiply(&extraMat, &transMatTategaki);
6825 needsTransform = TRUE;
6828 vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face));
6829 /* there is a freetype bug where vertical metrics are only
6830 properly scaled and correct in 2.4.0 or greater */
6831 if ((vertical_metrics) && (FT_Version.major < 2 || (FT_Version.major == 2 && FT_Version.minor < 4)))
6832 vertical_metrics = FALSE;
6834 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
6835 if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
6837 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
6839 if(err) {
6840 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
6841 return GDI_ERROR;
6844 metrics = ft_face->glyph->metrics;
6845 if(font->fake_bold)
6846 synthesize_bold_glyph(ft_face->glyph, font->ppem, &metrics);
6848 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6849 * by the text metrics. The proper behavior is to clip the glyph metrics to
6850 * fit within the maximums specified in the text metrics. */
6851 if(incoming_font->potm || get_outline_text_metrics(incoming_font) ||
6852 get_bitmap_text_metrics(incoming_font)) {
6853 TEXTMETRICW *ptm = &incoming_font->potm->otmTextMetrics;
6854 top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
6855 bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
6856 metrics.horiBearingY = top;
6857 metrics.height = top - bottom;
6859 /* TODO: Are we supposed to clip the width as well...? */
6860 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6863 em_scale = MulDiv(incoming_font->ppem, 1 << 16, incoming_font->ft_face->units_per_EM);
6865 if(FT_IS_SCALABLE(incoming_font->ft_face) && !font->fake_bold) {
6866 TEXTMETRICW tm;
6867 if (get_text_metrics(incoming_font, &tm) &&
6868 !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
6869 avgAdvance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
6870 if (avgAdvance &&
6871 (metrics.horiAdvance+63) >> 6 == pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale))
6872 TRACE("Fixed-pitch full-width character detected\n");
6873 else
6874 avgAdvance = 0; /* cancel this feature */
6878 if(!needsTransform) {
6879 left = (INT)(metrics.horiBearingX) & -64;
6880 right = (INT)((metrics.horiBearingX + metrics.width) + 63) & -64;
6881 if (!avgAdvance)
6882 adv = (INT)(metrics.horiAdvance + 63) >> 6;
6883 else
6884 adv = (INT)avgAdvance * 2;
6886 top = (metrics.horiBearingY + 63) & -64;
6887 bottom = (metrics.horiBearingY - metrics.height) & -64;
6888 gm.gmCellIncX = adv;
6889 gm.gmCellIncY = 0;
6890 origin_x = left;
6891 origin_y = top;
6892 abc->abcA = origin_x >> 6;
6893 abc->abcB = metrics.width >> 6;
6894 } else {
6895 INT xc, yc;
6896 FT_Vector vec;
6897 FT_Pos lsb;
6899 left = right = 0;
6901 for(xc = 0; xc < 2; xc++) {
6902 for(yc = 0; yc < 2; yc++) {
6903 vec.x = metrics.horiBearingX + xc * metrics.width;
6904 vec.y = metrics.horiBearingY - yc * metrics.height;
6905 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
6906 pFT_Vector_Transform(&vec, &transMatTategaki);
6907 if(xc == 0 && yc == 0) {
6908 left = right = vec.x;
6909 top = bottom = vec.y;
6910 } else {
6911 if(vec.x < left) left = vec.x;
6912 else if(vec.x > right) right = vec.x;
6913 if(vec.y < bottom) bottom = vec.y;
6914 else if(vec.y > top) top = vec.y;
6918 left = left & -64;
6919 right = (right + 63) & -64;
6920 bottom = bottom & -64;
6921 top = (top + 63) & -64;
6923 if (tategaki && (font->potm || get_outline_text_metrics(font)))
6925 if (vertical_metrics)
6926 lsb = metrics.horiBearingY + metrics.vertBearingY;
6927 else
6928 lsb = metrics.vertAdvance + (font->potm->otmDescent << 6);
6929 vec.x = lsb;
6930 vec.y = font->potm->otmDescent << 6;
6931 TRACE ("Vec %ld,%ld\n", vec.x>>6, vec.y>>6);
6932 pFT_Vector_Transform(&vec, &transMat);
6933 origin_x = (vec.x + left) & -64;
6934 origin_y = (vec.y + top + 63) & -64;
6936 else
6938 origin_x = left;
6939 origin_y = top;
6940 lsb = metrics.horiBearingX;
6943 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
6944 if (vertical_metrics)
6945 vec.x = metrics.vertAdvance;
6946 else
6947 vec.x = metrics.horiAdvance;
6948 vec.y = 0;
6949 pFT_Vector_Transform(&vec, &transMat);
6950 gm.gmCellIncY = -((vec.y+63) >> 6);
6951 if (!avgAdvance || vec.y)
6952 gm.gmCellIncX = (vec.x+63) >> 6;
6953 else {
6954 vec.x = incoming_font->ntmAvgWidth;
6955 vec.y = 0;
6956 pFT_Vector_Transform(&vec, &transMat);
6957 gm.gmCellIncX = pFT_MulFix(vec.x, em_scale) * 2;
6960 if (vertical_metrics)
6961 vec.x = metrics.vertAdvance;
6962 else
6963 vec.x = metrics.horiAdvance;
6964 vec.y = 0;
6965 pFT_Vector_Transform(&vec, &transMatUnrotated);
6966 if (!avgAdvance || vec.y)
6967 adv = (vec.x+63) >> 6;
6968 else {
6969 vec.x = incoming_font->ntmAvgWidth;
6970 vec.y = 0;
6971 pFT_Vector_Transform(&vec, &transMatUnrotated);
6972 adv = pFT_MulFix(vec.x, em_scale) * 2;
6975 vec.x = lsb;
6976 vec.y = 0;
6977 pFT_Vector_Transform(&vec, &transMatUnrotated);
6978 abc->abcA = vec.x >> 6;
6980 vec.x = metrics.width;
6981 vec.y = 0;
6982 pFT_Vector_Transform(&vec, &transMatUnrotated);
6983 if (vec.x >= 0)
6984 abc->abcB = vec.x >> 6;
6985 else
6986 abc->abcB = -vec.x >> 6;
6989 width = (right - left) >> 6;
6990 height = (top - bottom) >> 6;
6991 gm.gmBlackBoxX = width ? width : 1;
6992 gm.gmBlackBoxY = height ? height : 1;
6993 gm.gmptGlyphOrigin.x = origin_x >> 6;
6994 gm.gmptGlyphOrigin.y = origin_y >> 6;
6995 if (!abc->abcB) abc->abcB = 1;
6996 abc->abcC = adv - abc->abcA - abc->abcB;
6998 TRACE("%u,%u,%s,%d,%d\n", gm.gmBlackBoxX, gm.gmBlackBoxY,
6999 wine_dbgstr_point(&gm.gmptGlyphOrigin),
7000 gm.gmCellIncX, gm.gmCellIncY);
7002 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
7003 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
7005 FONT_GM(font,original_index)->gm = gm;
7006 FONT_GM(font,original_index)->abc = *abc;
7007 FONT_GM(font,original_index)->init = TRUE;
7010 if(format == GGO_METRICS)
7012 *lpgm = gm;
7013 return 1; /* FIXME */
7016 if(ft_face->glyph->format != ft_glyph_format_outline &&
7017 (format == GGO_NATIVE || format == GGO_BEZIER))
7019 TRACE("loaded a bitmap\n");
7020 return GDI_ERROR;
7023 switch(format) {
7024 case GGO_BITMAP:
7025 pitch = ((width + 31) >> 5) << 2;
7026 needed = pitch * height;
7028 if(!buf || !buflen) break;
7029 if (!needed) return GDI_ERROR; /* empty glyph */
7030 if (needed > buflen)
7031 return GDI_ERROR;
7033 switch(ft_face->glyph->format) {
7034 case ft_glyph_format_bitmap:
7036 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
7037 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
7038 INT h = min( height, ft_face->glyph->bitmap.rows );
7039 while(h--) {
7040 memcpy(dst, src, w);
7041 src += ft_face->glyph->bitmap.pitch;
7042 dst += pitch;
7044 break;
7047 case ft_glyph_format_outline:
7048 ft_bitmap.width = width;
7049 ft_bitmap.rows = height;
7050 ft_bitmap.pitch = pitch;
7051 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
7052 ft_bitmap.buffer = buf;
7054 if(needsTransform)
7055 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
7057 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
7059 /* Note: FreeType will only set 'black' bits for us. */
7060 memset(buf, 0, needed);
7061 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
7062 break;
7064 default:
7065 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
7066 return GDI_ERROR;
7068 break;
7070 case GGO_GRAY2_BITMAP:
7071 case GGO_GRAY4_BITMAP:
7072 case GGO_GRAY8_BITMAP:
7073 case WINE_GGO_GRAY16_BITMAP:
7075 unsigned int max_level, row, col;
7076 BYTE *start, *ptr;
7078 pitch = (width + 3) / 4 * 4;
7079 needed = pitch * height;
7081 if(!buf || !buflen) break;
7082 if (!needed) return GDI_ERROR; /* empty glyph */
7083 if (needed > buflen)
7084 return GDI_ERROR;
7086 max_level = get_max_level( format );
7088 switch(ft_face->glyph->format) {
7089 case ft_glyph_format_bitmap:
7091 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
7092 INT h = min( height, ft_face->glyph->bitmap.rows );
7093 INT x;
7094 memset( buf, 0, needed );
7095 while(h--) {
7096 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
7097 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
7098 src += ft_face->glyph->bitmap.pitch;
7099 dst += pitch;
7101 break;
7103 case ft_glyph_format_outline:
7105 ft_bitmap.width = width;
7106 ft_bitmap.rows = height;
7107 ft_bitmap.pitch = pitch;
7108 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
7109 ft_bitmap.buffer = buf;
7111 if(needsTransform)
7112 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
7114 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
7116 memset(ft_bitmap.buffer, 0, buflen);
7118 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
7120 if (max_level != 255)
7122 for (row = 0, start = buf; row < height; row++)
7124 for (col = 0, ptr = start; col < width; col++, ptr++)
7125 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
7126 start += pitch;
7129 break;
7132 default:
7133 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
7134 return GDI_ERROR;
7136 break;
7139 case WINE_GGO_HRGB_BITMAP:
7140 case WINE_GGO_HBGR_BITMAP:
7141 case WINE_GGO_VRGB_BITMAP:
7142 case WINE_GGO_VBGR_BITMAP:
7143 #ifdef FT_LCD_FILTER_H
7145 switch (ft_face->glyph->format)
7147 case FT_GLYPH_FORMAT_BITMAP:
7149 BYTE *src, *dst;
7150 INT src_pitch, x;
7152 pitch = width * 4;
7153 needed = pitch * height;
7155 if (!buf || !buflen) break;
7156 if (!needed) return GDI_ERROR; /* empty glyph */
7157 if (needed > buflen)
7158 return GDI_ERROR;
7160 memset(buf, 0, buflen);
7161 dst = buf;
7162 src = ft_face->glyph->bitmap.buffer;
7163 src_pitch = ft_face->glyph->bitmap.pitch;
7165 height = min( height, ft_face->glyph->bitmap.rows );
7166 while ( height-- )
7168 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
7170 if ( src[x / 8] & masks[x % 8] )
7171 ((unsigned int *)dst)[x] = ~0u;
7173 src += src_pitch;
7174 dst += pitch;
7177 break;
7180 case FT_GLYPH_FORMAT_OUTLINE:
7182 unsigned int *dst;
7183 BYTE *src;
7184 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
7185 INT x_shift, y_shift;
7186 BOOL rgb;
7187 FT_Render_Mode render_mode =
7188 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
7189 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
7191 if (!width || !height)
7193 if (!buf || !buflen) break;
7194 return GDI_ERROR;
7197 if ( render_mode == FT_RENDER_MODE_LCD)
7199 gm.gmBlackBoxX += 2;
7200 gm.gmptGlyphOrigin.x -= 1;
7201 left -= (1 << 6);
7203 else
7205 gm.gmBlackBoxY += 2;
7206 gm.gmptGlyphOrigin.y += 1;
7207 top += (1 << 6);
7210 width = gm.gmBlackBoxX;
7211 height = gm.gmBlackBoxY;
7212 pitch = width * 4;
7213 needed = pitch * height;
7215 if (!buf || !buflen) break;
7216 if (needed > buflen)
7217 return GDI_ERROR;
7219 memset(buf, 0, buflen);
7220 dst = buf;
7221 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
7223 if ( needsTransform )
7224 pFT_Outline_Transform (&ft_face->glyph->outline, &transMatTategaki);
7226 if ( pFT_Library_SetLcdFilter )
7227 pFT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT );
7228 pFT_Render_Glyph (ft_face->glyph, render_mode);
7230 src = ft_face->glyph->bitmap.buffer;
7231 src_pitch = ft_face->glyph->bitmap.pitch;
7232 src_width = ft_face->glyph->bitmap.width;
7233 src_height = ft_face->glyph->bitmap.rows;
7235 if ( render_mode == FT_RENDER_MODE_LCD)
7237 rgb_interval = 1;
7238 hmul = 3;
7239 vmul = 1;
7241 else
7243 rgb_interval = src_pitch;
7244 hmul = 1;
7245 vmul = 3;
7248 x_shift = ft_face->glyph->bitmap_left - (left >> 6);
7249 if ( x_shift < 0 )
7251 src += hmul * -x_shift;
7252 src_width -= hmul * -x_shift;
7254 else if ( x_shift > 0 )
7256 dst += x_shift;
7257 width -= x_shift;
7260 y_shift = (top >> 6) - ft_face->glyph->bitmap_top;
7261 if ( y_shift < 0 )
7263 src += src_pitch * vmul * -y_shift;
7264 src_height -= vmul * -y_shift;
7266 else if ( y_shift > 0 )
7268 dst += y_shift * ( pitch / sizeof(*dst) );
7269 height -= y_shift;
7272 width = min( width, src_width / hmul );
7273 height = min( height, src_height / vmul );
7275 while ( height-- )
7277 for ( x = 0; x < width; x++ )
7279 if ( rgb )
7281 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
7282 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
7283 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
7284 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
7286 else
7288 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
7289 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
7290 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
7291 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
7294 src += src_pitch * vmul;
7295 dst += pitch / sizeof(*dst);
7298 break;
7301 default:
7302 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
7303 return GDI_ERROR;
7306 break;
7308 #else
7309 return GDI_ERROR;
7310 #endif
7312 case GGO_NATIVE:
7314 FT_Outline *outline = &ft_face->glyph->outline;
7316 if(buflen == 0) buf = NULL;
7318 if (needsTransform && buf)
7319 pFT_Outline_Transform(outline, &transMatTategaki);
7321 needed = get_native_glyph_outline(outline, buflen, NULL);
7323 if (!buf || !buflen)
7324 break;
7325 if (needed > buflen)
7326 return GDI_ERROR;
7328 get_native_glyph_outline(outline, buflen, buf);
7329 break;
7331 case GGO_BEZIER:
7333 FT_Outline *outline = &ft_face->glyph->outline;
7334 if(buflen == 0) buf = NULL;
7336 if (needsTransform && buf)
7337 pFT_Outline_Transform(outline, &transMat);
7339 needed = get_bezier_glyph_outline(outline, buflen, NULL);
7341 if (!buf || !buflen)
7342 break;
7343 if (needed > buflen)
7344 return GDI_ERROR;
7346 get_bezier_glyph_outline(outline, buflen, buf);
7347 break;
7350 default:
7351 FIXME("Unsupported format %d\n", format);
7352 return GDI_ERROR;
7354 *lpgm = gm;
7355 return needed;
7358 static BOOL get_bitmap_text_metrics(GdiFont *font)
7360 FT_Face ft_face = font->ft_face;
7361 FT_WinFNT_HeaderRec winfnt_header;
7362 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
7363 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
7364 font->potm->otmSize = size;
7366 #define TM font->potm->otmTextMetrics
7367 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
7369 TM.tmHeight = winfnt_header.pixel_height;
7370 TM.tmAscent = winfnt_header.ascent;
7371 TM.tmDescent = TM.tmHeight - TM.tmAscent;
7372 TM.tmInternalLeading = winfnt_header.internal_leading;
7373 TM.tmExternalLeading = winfnt_header.external_leading;
7374 TM.tmAveCharWidth = winfnt_header.avg_width;
7375 TM.tmMaxCharWidth = winfnt_header.max_width;
7376 TM.tmWeight = winfnt_header.weight;
7377 TM.tmOverhang = 0;
7378 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
7379 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
7380 TM.tmFirstChar = winfnt_header.first_char;
7381 TM.tmLastChar = winfnt_header.last_char;
7382 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
7383 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
7384 TM.tmItalic = winfnt_header.italic;
7385 TM.tmUnderlined = font->underline;
7386 TM.tmStruckOut = font->strikeout;
7387 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
7388 TM.tmCharSet = winfnt_header.charset;
7390 else
7392 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
7393 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
7394 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7395 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
7396 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
7397 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
7398 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
7399 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
7400 TM.tmOverhang = 0;
7401 TM.tmDigitizedAspectX = 96; /* FIXME */
7402 TM.tmDigitizedAspectY = 96; /* FIXME */
7403 TM.tmFirstChar = 1;
7404 TM.tmLastChar = 255;
7405 TM.tmDefaultChar = 32;
7406 TM.tmBreakChar = 32;
7407 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
7408 TM.tmUnderlined = font->underline;
7409 TM.tmStruckOut = font->strikeout;
7410 /* NB inverted meaning of TMPF_FIXED_PITCH */
7411 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
7412 TM.tmCharSet = font->charset;
7414 #undef TM
7416 return TRUE;
7420 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
7422 double scale_x, scale_y;
7424 if (font->aveWidth)
7426 scale_x = (double)font->aveWidth;
7427 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7429 else
7430 scale_x = font->scale_y;
7432 scale_x *= fabs(font->font_desc.matrix.eM11);
7433 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7435 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7436 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7438 SCALE_Y(ptm->tmHeight);
7439 SCALE_Y(ptm->tmAscent);
7440 SCALE_Y(ptm->tmDescent);
7441 SCALE_Y(ptm->tmInternalLeading);
7442 SCALE_Y(ptm->tmExternalLeading);
7443 SCALE_Y(ptm->tmOverhang);
7445 SCALE_X(ptm->tmAveCharWidth);
7446 SCALE_X(ptm->tmMaxCharWidth);
7448 #undef SCALE_X
7449 #undef SCALE_Y
7452 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
7454 double scale_x, scale_y;
7456 if (font->aveWidth)
7458 scale_x = (double)font->aveWidth;
7459 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7461 else
7462 scale_x = font->scale_y;
7464 scale_x *= fabs(font->font_desc.matrix.eM11);
7465 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7467 scale_font_metrics(font, &potm->otmTextMetrics);
7469 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7470 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7472 SCALE_Y(potm->otmAscent);
7473 SCALE_Y(potm->otmDescent);
7474 SCALE_Y(potm->otmLineGap);
7475 SCALE_Y(potm->otmsCapEmHeight);
7476 SCALE_Y(potm->otmsXHeight);
7477 SCALE_Y(potm->otmrcFontBox.top);
7478 SCALE_Y(potm->otmrcFontBox.bottom);
7479 SCALE_X(potm->otmrcFontBox.left);
7480 SCALE_X(potm->otmrcFontBox.right);
7481 SCALE_Y(potm->otmMacAscent);
7482 SCALE_Y(potm->otmMacDescent);
7483 SCALE_Y(potm->otmMacLineGap);
7484 SCALE_X(potm->otmptSubscriptSize.x);
7485 SCALE_Y(potm->otmptSubscriptSize.y);
7486 SCALE_X(potm->otmptSubscriptOffset.x);
7487 SCALE_Y(potm->otmptSubscriptOffset.y);
7488 SCALE_X(potm->otmptSuperscriptSize.x);
7489 SCALE_Y(potm->otmptSuperscriptSize.y);
7490 SCALE_X(potm->otmptSuperscriptOffset.x);
7491 SCALE_Y(potm->otmptSuperscriptOffset.y);
7492 SCALE_Y(potm->otmsStrikeoutSize);
7493 SCALE_Y(potm->otmsStrikeoutPosition);
7494 SCALE_Y(potm->otmsUnderscoreSize);
7495 SCALE_Y(potm->otmsUnderscorePosition);
7497 #undef SCALE_X
7498 #undef SCALE_Y
7501 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
7503 if(!font->potm)
7505 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
7507 /* Make sure that the font has sane width/height ratio */
7508 if (font->aveWidth)
7510 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
7512 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
7513 font->aveWidth = 0;
7517 *ptm = font->potm->otmTextMetrics;
7518 scale_font_metrics(font, ptm);
7519 return TRUE;
7522 static BOOL face_has_symbol_charmap(FT_Face ft_face)
7524 int i;
7526 for(i = 0; i < ft_face->num_charmaps; i++)
7528 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
7529 return TRUE;
7531 return FALSE;
7534 static BOOL get_outline_text_metrics(GdiFont *font)
7536 BOOL ret = FALSE;
7537 FT_Face ft_face = font->ft_face;
7538 UINT needed, lenfam, lensty, lenface, lenfull;
7539 TT_OS2 *pOS2;
7540 TT_HoriHeader *pHori;
7541 TT_Postscript *pPost;
7542 FT_Fixed em_scale;
7543 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
7544 char *cp;
7545 INT ascent, descent;
7546 USHORT windescent;
7548 TRACE("font=%p\n", font);
7550 if(!FT_IS_SCALABLE(ft_face))
7551 return FALSE;
7553 needed = sizeof(*font->potm);
7555 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
7556 family_nameW = strdupW(font->name);
7558 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
7559 if (!style_nameW)
7561 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
7562 style_nameW = towstr( CP_ACP, ft_face->style_name );
7564 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
7566 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
7567 if (!face_nameW)
7569 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
7570 face_nameW = strdupW(font->name);
7572 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
7573 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
7575 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
7576 if (!full_nameW)
7578 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
7579 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
7580 full_nameW = strdupW(fake_nameW);
7582 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
7584 /* These names should be read from the TT name table */
7586 /* length of otmpFamilyName */
7587 needed += lenfam;
7589 /* length of otmpFaceName */
7590 needed += lenface;
7592 /* length of otmpStyleName */
7593 needed += lensty;
7595 /* length of otmpFullName */
7596 needed += lenfull;
7599 em_scale = (FT_Fixed)MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
7601 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
7602 if(!pOS2) {
7603 FIXME("Can't find OS/2 table - not TT font?\n");
7604 goto end;
7607 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
7608 if(!pHori) {
7609 FIXME("Can't find HHEA table - not TT font?\n");
7610 goto end;
7613 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
7615 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",
7616 pOS2->usWinAscent, pOS2->usWinDescent,
7617 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
7618 pOS2->xAvgCharWidth,
7619 ft_face->ascender, ft_face->descender, ft_face->height,
7620 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
7621 ft_face->bbox.yMax, ft_face->bbox.yMin);
7623 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
7624 font->potm->otmSize = needed;
7626 #define TM font->potm->otmTextMetrics
7628 windescent = get_fixed_windescent(pOS2->usWinDescent);
7629 if(pOS2->usWinAscent + windescent == 0) {
7630 ascent = pHori->Ascender;
7631 descent = -pHori->Descender;
7632 } else {
7633 ascent = pOS2->usWinAscent;
7634 descent = windescent;
7637 font->ntmCellHeight = ascent + descent;
7638 font->ntmAvgWidth = pOS2->xAvgCharWidth;
7640 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7641 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7643 if(font->yMax) {
7644 TM.tmAscent = font->yMax;
7645 TM.tmDescent = -font->yMin;
7646 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
7647 } else {
7648 TM.tmAscent = SCALE_Y(ascent);
7649 TM.tmDescent = SCALE_Y(descent);
7650 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
7653 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7655 /* MSDN says:
7656 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7658 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
7659 ((ascent + descent) -
7660 (pHori->Ascender - pHori->Descender))));
7662 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
7663 if (TM.tmAveCharWidth == 0) {
7664 TM.tmAveCharWidth = 1;
7666 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
7667 TM.tmWeight = FW_REGULAR;
7668 if (font->fake_bold) {
7669 TM.tmAveCharWidth++;
7670 TM.tmMaxCharWidth++;
7671 TM.tmWeight = FW_BOLD;
7673 else
7675 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
7677 if (pOS2->usWeightClass > FW_MEDIUM)
7678 TM.tmWeight = pOS2->usWeightClass;
7680 else if (pOS2->usWeightClass <= FW_MEDIUM)
7681 TM.tmWeight = pOS2->usWeightClass;
7683 TM.tmOverhang = 0;
7684 TM.tmDigitizedAspectX = 96; /* FIXME */
7685 TM.tmDigitizedAspectY = 96; /* FIXME */
7686 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7687 * symbol range to 0 - f0ff
7690 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
7692 TM.tmFirstChar = 0;
7693 switch(GetACP())
7695 case 1255: /* Hebrew */
7696 TM.tmLastChar = 0xf896;
7697 break;
7698 case 1257: /* Baltic */
7699 TM.tmLastChar = 0xf8fd;
7700 break;
7701 default:
7702 TM.tmLastChar = 0xf0ff;
7704 TM.tmBreakChar = 0x20;
7705 TM.tmDefaultChar = 0x1f;
7707 else
7709 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
7710 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
7712 if(pOS2->usFirstCharIndex <= 1)
7713 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
7714 else if (pOS2->usFirstCharIndex > 0xff)
7715 TM.tmBreakChar = 0x20;
7716 else
7717 TM.tmBreakChar = pOS2->usFirstCharIndex;
7718 TM.tmDefaultChar = TM.tmBreakChar - 1;
7720 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
7721 TM.tmUnderlined = font->underline;
7722 TM.tmStruckOut = font->strikeout;
7724 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7725 if(!FT_IS_FIXED_WIDTH(ft_face) &&
7726 (pOS2->version == 0xFFFFU ||
7727 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
7728 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
7729 else
7730 TM.tmPitchAndFamily = 0;
7732 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
7734 case PAN_FAMILY_SCRIPT:
7735 TM.tmPitchAndFamily |= FF_SCRIPT;
7736 break;
7738 case PAN_FAMILY_DECORATIVE:
7739 TM.tmPitchAndFamily |= FF_DECORATIVE;
7740 break;
7742 case PAN_ANY:
7743 case PAN_NO_FIT:
7744 case PAN_FAMILY_TEXT_DISPLAY:
7745 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
7746 /* which is clearly not what the panose spec says. */
7747 default:
7748 if(TM.tmPitchAndFamily == 0 || /* fixed */
7749 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
7750 TM.tmPitchAndFamily = FF_MODERN;
7751 else
7753 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
7755 case PAN_ANY:
7756 case PAN_NO_FIT:
7757 default:
7758 TM.tmPitchAndFamily |= FF_DONTCARE;
7759 break;
7761 case PAN_SERIF_COVE:
7762 case PAN_SERIF_OBTUSE_COVE:
7763 case PAN_SERIF_SQUARE_COVE:
7764 case PAN_SERIF_OBTUSE_SQUARE_COVE:
7765 case PAN_SERIF_SQUARE:
7766 case PAN_SERIF_THIN:
7767 case PAN_SERIF_BONE:
7768 case PAN_SERIF_EXAGGERATED:
7769 case PAN_SERIF_TRIANGLE:
7770 TM.tmPitchAndFamily |= FF_ROMAN;
7771 break;
7773 case PAN_SERIF_NORMAL_SANS:
7774 case PAN_SERIF_OBTUSE_SANS:
7775 case PAN_SERIF_PERP_SANS:
7776 case PAN_SERIF_FLARED:
7777 case PAN_SERIF_ROUNDED:
7778 TM.tmPitchAndFamily |= FF_SWISS;
7779 break;
7782 break;
7785 if(FT_IS_SCALABLE(ft_face))
7786 TM.tmPitchAndFamily |= TMPF_VECTOR;
7788 if(FT_IS_SFNT(ft_face))
7790 if (font->ntmFlags & NTM_PS_OPENTYPE)
7791 TM.tmPitchAndFamily |= TMPF_DEVICE;
7792 else
7793 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
7796 TM.tmCharSet = font->charset;
7798 font->potm->otmFiller = 0;
7799 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
7800 font->potm->otmfsSelection = pOS2->fsSelection;
7801 font->potm->otmfsType = pOS2->fsType;
7802 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
7803 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
7804 font->potm->otmItalicAngle = 0; /* POST table */
7805 font->potm->otmEMSquare = ft_face->units_per_EM;
7806 font->potm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
7807 font->potm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
7808 font->potm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
7809 font->potm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
7810 font->potm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
7811 font->potm->otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
7812 font->potm->otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
7813 font->potm->otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
7814 font->potm->otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
7815 font->potm->otmMacAscent = TM.tmAscent;
7816 font->potm->otmMacDescent = -TM.tmDescent;
7817 font->potm->otmMacLineGap = font->potm->otmLineGap;
7818 font->potm->otmusMinimumPPEM = 0; /* TT Header */
7819 font->potm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
7820 font->potm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
7821 font->potm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
7822 font->potm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
7823 font->potm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
7824 font->potm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
7825 font->potm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
7826 font->potm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
7827 font->potm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
7828 font->potm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
7829 if(!pPost) {
7830 font->potm->otmsUnderscoreSize = 0;
7831 font->potm->otmsUnderscorePosition = 0;
7832 } else {
7833 font->potm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
7834 font->potm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
7836 #undef SCALE_X
7837 #undef SCALE_Y
7838 #undef TM
7840 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7841 cp = (char*)font->potm + sizeof(*font->potm);
7842 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
7843 strcpyW((WCHAR*)cp, family_nameW);
7844 cp += lenfam;
7845 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
7846 strcpyW((WCHAR*)cp, style_nameW);
7847 cp += lensty;
7848 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7849 strcpyW((WCHAR*)cp, face_nameW);
7850 cp += lenface;
7851 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
7852 strcpyW((WCHAR*)cp, full_nameW);
7853 ret = TRUE;
7855 end:
7856 HeapFree(GetProcessHeap(), 0, style_nameW);
7857 HeapFree(GetProcessHeap(), 0, family_nameW);
7858 HeapFree(GetProcessHeap(), 0, face_nameW);
7859 HeapFree(GetProcessHeap(), 0, full_nameW);
7860 return ret;
7863 /*************************************************************
7864 * freetype_GetGlyphOutline
7866 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
7867 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7869 struct freetype_physdev *physdev = get_freetype_dev( dev );
7870 DWORD ret;
7871 ABC abc;
7873 if (!physdev->font)
7875 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
7876 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
7879 GDI_CheckNotLock();
7880 EnterCriticalSection( &freetype_cs );
7881 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
7882 LeaveCriticalSection( &freetype_cs );
7883 return ret;
7886 /*************************************************************
7887 * freetype_GetTextMetrics
7889 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
7891 struct freetype_physdev *physdev = get_freetype_dev( dev );
7892 BOOL ret;
7894 if (!physdev->font)
7896 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
7897 return dev->funcs->pGetTextMetrics( dev, metrics );
7900 GDI_CheckNotLock();
7901 EnterCriticalSection( &freetype_cs );
7902 ret = get_text_metrics( physdev->font, metrics );
7903 LeaveCriticalSection( &freetype_cs );
7904 return ret;
7907 /*************************************************************
7908 * freetype_GetOutlineTextMetrics
7910 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
7912 struct freetype_physdev *physdev = get_freetype_dev( dev );
7913 UINT ret = 0;
7915 if (!physdev->font)
7917 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
7918 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
7921 TRACE("font=%p\n", physdev->font);
7923 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
7925 GDI_CheckNotLock();
7926 EnterCriticalSection( &freetype_cs );
7928 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
7930 if(potm && cbSize >= physdev->font->potm->otmSize)
7932 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
7933 scale_outline_font_metrics(physdev->font, potm);
7935 ret = physdev->font->potm->otmSize;
7937 LeaveCriticalSection( &freetype_cs );
7938 return ret;
7941 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
7943 child->font = alloc_font();
7944 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
7945 if(!child->font->ft_face)
7947 free_font(child->font);
7948 child->font = NULL;
7949 return FALSE;
7952 child->font->font_desc = font->font_desc;
7953 child->font->ntmFlags = child->face->ntmFlags;
7954 child->font->orientation = font->orientation;
7955 child->font->scale_y = font->scale_y;
7956 child->font->name = strdupW(child->face->family->FamilyName);
7957 child->font->base_font = font;
7958 TRACE("created child font %p for base %p\n", child->font, font);
7959 return TRUE;
7962 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL* vert)
7964 FT_UInt g,o;
7965 CHILD_FONT *child_font;
7967 if(font->base_font)
7968 font = font->base_font;
7970 *linked_font = font;
7972 if((*glyph = get_glyph_index(font, c)))
7974 o = *glyph;
7975 *glyph = get_GSUB_vert_glyph(font, *glyph);
7976 *vert = (o != *glyph);
7977 return TRUE;
7980 if (c < 32) goto done; /* don't check linked fonts for control characters */
7982 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7984 if(!child_font->font)
7985 if(!load_child_font(font, child_font))
7986 continue;
7988 if(!child_font->font->ft_face)
7989 continue;
7990 g = get_glyph_index(child_font->font, c);
7991 o = g;
7992 g = get_GSUB_vert_glyph(child_font->font, g);
7993 if(g)
7995 *glyph = g;
7996 *linked_font = child_font->font;
7997 *vert = (o != g);
7998 return TRUE;
8002 done:
8003 *vert = FALSE;
8004 return FALSE;
8007 /*************************************************************
8008 * freetype_GetCharWidth
8010 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
8012 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8013 UINT c;
8014 GLYPHMETRICS gm;
8015 ABC abc;
8016 struct freetype_physdev *physdev = get_freetype_dev( dev );
8018 if (!physdev->font)
8020 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
8021 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
8024 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
8026 GDI_CheckNotLock();
8027 EnterCriticalSection( &freetype_cs );
8028 for(c = firstChar; c <= lastChar; c++) {
8029 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
8030 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
8032 LeaveCriticalSection( &freetype_cs );
8033 return TRUE;
8036 /*************************************************************
8037 * freetype_GetCharABCWidths
8039 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
8041 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8042 UINT c;
8043 GLYPHMETRICS gm;
8044 struct freetype_physdev *physdev = get_freetype_dev( dev );
8046 if (!physdev->font)
8048 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
8049 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
8052 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
8054 GDI_CheckNotLock();
8055 EnterCriticalSection( &freetype_cs );
8057 for(c = firstChar; c <= lastChar; c++, buffer++)
8058 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
8060 LeaveCriticalSection( &freetype_cs );
8061 return TRUE;
8064 /*************************************************************
8065 * freetype_GetCharABCWidthsI
8067 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
8069 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8070 UINT c;
8071 GLYPHMETRICS gm;
8072 struct freetype_physdev *physdev = get_freetype_dev( dev );
8074 if (!physdev->font)
8076 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
8077 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
8080 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
8081 return FALSE;
8083 GDI_CheckNotLock();
8084 EnterCriticalSection( &freetype_cs );
8086 for(c = 0; c < count; c++, buffer++)
8087 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
8088 &gm, buffer, 0, NULL, &identity );
8090 LeaveCriticalSection( &freetype_cs );
8091 return TRUE;
8094 /*************************************************************
8095 * freetype_GetTextExtentExPoint
8097 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
8099 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8100 INT idx, pos;
8101 ABC abc;
8102 GLYPHMETRICS gm;
8103 struct freetype_physdev *physdev = get_freetype_dev( dev );
8105 if (!physdev->font)
8107 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
8108 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
8111 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
8113 GDI_CheckNotLock();
8114 EnterCriticalSection( &freetype_cs );
8116 for (idx = pos = 0; idx < count; idx++)
8118 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
8119 pos += abc.abcA + abc.abcB + abc.abcC;
8120 dxs[idx] = pos;
8123 LeaveCriticalSection( &freetype_cs );
8124 return TRUE;
8127 /*************************************************************
8128 * freetype_GetTextExtentExPointI
8130 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
8132 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8133 INT idx, pos;
8134 ABC abc;
8135 GLYPHMETRICS gm;
8136 struct freetype_physdev *physdev = get_freetype_dev( dev );
8138 if (!physdev->font)
8140 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
8141 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
8144 TRACE("%p, %p, %d\n", physdev->font, indices, count);
8146 GDI_CheckNotLock();
8147 EnterCriticalSection( &freetype_cs );
8149 for (idx = pos = 0; idx < count; idx++)
8151 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
8152 &gm, &abc, 0, NULL, &identity );
8153 pos += abc.abcA + abc.abcB + abc.abcC;
8154 dxs[idx] = pos;
8157 LeaveCriticalSection( &freetype_cs );
8158 return TRUE;
8161 /*************************************************************
8162 * freetype_GetFontData
8164 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
8166 struct freetype_physdev *physdev = get_freetype_dev( dev );
8168 if (!physdev->font)
8170 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
8171 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
8174 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
8175 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
8176 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
8178 return get_font_data( physdev->font, table, offset, buf, cbData );
8181 /*************************************************************
8182 * freetype_GetTextFace
8184 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
8186 INT n;
8187 struct freetype_physdev *physdev = get_freetype_dev( dev );
8189 if (!physdev->font)
8191 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
8192 return dev->funcs->pGetTextFace( dev, count, str );
8195 n = strlenW(physdev->font->name) + 1;
8196 if (str)
8198 lstrcpynW(str, physdev->font->name, count);
8199 n = min(count, n);
8201 return n;
8204 /*************************************************************
8205 * freetype_GetTextCharsetInfo
8207 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
8209 struct freetype_physdev *physdev = get_freetype_dev( dev );
8211 if (!physdev->font)
8213 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
8214 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
8216 if (fs) *fs = physdev->font->fs;
8217 return physdev->font->charset;
8220 /* Retrieve a list of supported Unicode ranges for a given font.
8221 * Can be called with NULL gs to calculate the buffer size. Returns
8222 * the number of ranges found.
8224 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
8226 DWORD num_ranges = 0;
8228 if (face->charmap->encoding == FT_ENCODING_UNICODE)
8230 FT_UInt glyph_code;
8231 FT_ULong char_code, char_code_prev;
8233 glyph_code = 0;
8234 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
8236 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
8237 face->num_glyphs, glyph_code, char_code);
8239 if (!glyph_code) return 0;
8241 if (gs)
8243 gs->ranges[0].wcLow = (USHORT)char_code;
8244 gs->ranges[0].cGlyphs = 0;
8245 gs->cGlyphsSupported = 0;
8248 num_ranges = 1;
8249 while (glyph_code)
8251 if (char_code < char_code_prev)
8253 ERR("expected increasing char code from FT_Get_Next_Char\n");
8254 return 0;
8256 if (char_code - char_code_prev > 1)
8258 num_ranges++;
8259 if (gs)
8261 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
8262 gs->ranges[num_ranges - 1].cGlyphs = 1;
8263 gs->cGlyphsSupported++;
8266 else if (gs)
8268 gs->ranges[num_ranges - 1].cGlyphs++;
8269 gs->cGlyphsSupported++;
8271 char_code_prev = char_code;
8272 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
8275 else
8276 FIXME("encoding %u not supported\n", face->charmap->encoding);
8278 return num_ranges;
8281 /*************************************************************
8282 * freetype_GetFontUnicodeRanges
8284 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
8286 struct freetype_physdev *physdev = get_freetype_dev( dev );
8287 DWORD size, num_ranges;
8289 if (!physdev->font)
8291 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
8292 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
8295 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
8296 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
8297 if (glyphset)
8299 glyphset->cbThis = size;
8300 glyphset->cRanges = num_ranges;
8301 glyphset->flAccel = 0;
8303 return size;
8306 /*************************************************************
8307 * freetype_FontIsLinked
8309 static BOOL freetype_FontIsLinked( PHYSDEV dev )
8311 struct freetype_physdev *physdev = get_freetype_dev( dev );
8312 BOOL ret;
8314 if (!physdev->font)
8316 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
8317 return dev->funcs->pFontIsLinked( dev );
8320 GDI_CheckNotLock();
8321 EnterCriticalSection( &freetype_cs );
8322 ret = !list_empty(&physdev->font->child_fonts);
8323 LeaveCriticalSection( &freetype_cs );
8324 return ret;
8327 /*************************************************************************
8328 * GetRasterizerCaps (GDI32.@)
8330 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8332 lprs->nSize = sizeof(RASTERIZER_STATUS);
8333 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
8334 lprs->nLanguageID = 0;
8335 return TRUE;
8338 /*************************************************************
8339 * freetype_GetFontRealizationInfo
8341 static BOOL freetype_GetFontRealizationInfo( PHYSDEV dev, void *ptr )
8343 struct freetype_physdev *physdev = get_freetype_dev( dev );
8344 struct font_realization_info *info = ptr;
8346 if (!physdev->font)
8348 dev = GET_NEXT_PHYSDEV( dev, pGetFontRealizationInfo );
8349 return dev->funcs->pGetFontRealizationInfo( dev, ptr );
8352 TRACE("(%p, %p)\n", physdev->font, info);
8354 info->flags = 1;
8355 if(FT_IS_SCALABLE(physdev->font->ft_face))
8356 info->flags |= 2;
8358 info->cache_num = physdev->font->cache_num;
8359 info->instance_id = physdev->font->instance_id;
8360 if (info->size == sizeof(*info))
8362 info->unk = 0;
8363 info->face_index = physdev->font->ft_face->face_index;
8364 info->simulations = 0;
8365 if (physdev->font->fake_bold)
8366 info->simulations |= 0x1;
8367 if (physdev->font->fake_italic)
8368 info->simulations |= 0x2;
8371 return TRUE;
8374 /*************************************************************************
8375 * GetFontFileInfo (GDI32.@)
8377 BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_fileinfo *info, DWORD size, DWORD *needed )
8379 struct font_handle_entry *entry = handle_entry( instance_id );
8380 const GdiFont *font;
8382 if (!entry)
8384 SetLastError(ERROR_INVALID_PARAMETER);
8385 return FALSE;
8388 font = entry->obj;
8389 *needed = sizeof(*info) + strlenW(font->fileinfo->path) * sizeof(WCHAR);
8390 if (*needed > size)
8392 SetLastError(ERROR_INSUFFICIENT_BUFFER);
8393 return FALSE;
8396 /* path is included too */
8397 memcpy(info, font->fileinfo, *needed);
8398 return TRUE;
8401 /*************************************************************************
8402 * Kerning support for TrueType fonts
8404 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
8406 struct TT_kern_table
8408 USHORT version;
8409 USHORT nTables;
8412 struct TT_kern_subtable
8414 USHORT version;
8415 USHORT length;
8416 union
8418 USHORT word;
8419 struct
8421 USHORT horizontal : 1;
8422 USHORT minimum : 1;
8423 USHORT cross_stream: 1;
8424 USHORT override : 1;
8425 USHORT reserved1 : 4;
8426 USHORT format : 8;
8427 } bits;
8428 } coverage;
8431 struct TT_format0_kern_subtable
8433 USHORT nPairs;
8434 USHORT searchRange;
8435 USHORT entrySelector;
8436 USHORT rangeShift;
8439 struct TT_kern_pair
8441 USHORT left;
8442 USHORT right;
8443 short value;
8446 static DWORD parse_format0_kern_subtable(GdiFont *font,
8447 const struct TT_format0_kern_subtable *tt_f0_ks,
8448 const USHORT *glyph_to_char,
8449 KERNINGPAIR *kern_pair, DWORD cPairs)
8451 USHORT i, nPairs;
8452 const struct TT_kern_pair *tt_kern_pair;
8454 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
8456 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
8458 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8459 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
8460 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
8462 if (!kern_pair || !cPairs)
8463 return nPairs;
8465 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
8467 nPairs = min(nPairs, cPairs);
8469 for (i = 0; i < nPairs; i++)
8471 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
8472 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
8473 /* this algorithm appears to better match what Windows does */
8474 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
8475 if (kern_pair->iKernAmount < 0)
8477 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
8478 kern_pair->iKernAmount -= font->ppem;
8480 else if (kern_pair->iKernAmount > 0)
8482 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
8483 kern_pair->iKernAmount += font->ppem;
8485 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
8487 TRACE("left %u right %u value %d\n",
8488 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
8490 kern_pair++;
8492 TRACE("copied %u entries\n", nPairs);
8493 return nPairs;
8496 /*************************************************************
8497 * freetype_GetKerningPairs
8499 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
8501 DWORD length;
8502 void *buf;
8503 const struct TT_kern_table *tt_kern_table;
8504 const struct TT_kern_subtable *tt_kern_subtable;
8505 USHORT i, nTables;
8506 USHORT *glyph_to_char;
8507 GdiFont *font;
8508 struct freetype_physdev *physdev = get_freetype_dev( dev );
8510 if (!(font = physdev->font))
8512 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
8513 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
8516 GDI_CheckNotLock();
8517 EnterCriticalSection( &freetype_cs );
8518 if (font->total_kern_pairs != (DWORD)-1)
8520 if (cPairs && kern_pair)
8522 cPairs = min(cPairs, font->total_kern_pairs);
8523 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8525 else cPairs = font->total_kern_pairs;
8527 LeaveCriticalSection( &freetype_cs );
8528 return cPairs;
8531 font->total_kern_pairs = 0;
8533 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
8535 if (length == GDI_ERROR)
8537 TRACE("no kerning data in the font\n");
8538 LeaveCriticalSection( &freetype_cs );
8539 return 0;
8542 buf = HeapAlloc(GetProcessHeap(), 0, length);
8543 if (!buf)
8545 WARN("Out of memory\n");
8546 LeaveCriticalSection( &freetype_cs );
8547 return 0;
8550 get_font_data(font, MS_KERN_TAG, 0, buf, length);
8552 /* build a glyph index to char code map */
8553 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
8554 if (!glyph_to_char)
8556 WARN("Out of memory allocating a glyph index to char code map\n");
8557 HeapFree(GetProcessHeap(), 0, buf);
8558 LeaveCriticalSection( &freetype_cs );
8559 return 0;
8562 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
8564 FT_UInt glyph_code;
8565 FT_ULong char_code;
8567 glyph_code = 0;
8568 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
8570 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
8571 font->ft_face->num_glyphs, glyph_code, char_code);
8573 while (glyph_code)
8575 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
8577 /* FIXME: This doesn't match what Windows does: it does some fancy
8578 * things with duplicate glyph index to char code mappings, while
8579 * we just avoid overriding existing entries.
8581 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
8582 glyph_to_char[glyph_code] = (USHORT)char_code;
8584 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
8587 else
8589 ULONG n;
8591 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
8592 for (n = 0; n <= 65535; n++)
8593 glyph_to_char[n] = (USHORT)n;
8596 tt_kern_table = buf;
8597 nTables = GET_BE_WORD(tt_kern_table->nTables);
8598 TRACE("version %u, nTables %u\n",
8599 GET_BE_WORD(tt_kern_table->version), nTables);
8601 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
8603 for (i = 0; i < nTables; i++)
8605 struct TT_kern_subtable tt_kern_subtable_copy;
8607 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
8608 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
8609 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
8611 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8612 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
8613 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
8615 /* According to the TrueType specification this is the only format
8616 * that will be properly interpreted by Windows and OS/2
8618 if (tt_kern_subtable_copy.coverage.bits.format == 0)
8620 DWORD new_chunk, old_total = font->total_kern_pairs;
8622 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8623 glyph_to_char, NULL, 0);
8624 font->total_kern_pairs += new_chunk;
8626 if (!font->kern_pairs)
8627 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
8628 font->total_kern_pairs * sizeof(*font->kern_pairs));
8629 else
8630 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
8631 font->total_kern_pairs * sizeof(*font->kern_pairs));
8633 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8634 glyph_to_char, font->kern_pairs + old_total, new_chunk);
8636 else
8637 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
8639 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
8642 HeapFree(GetProcessHeap(), 0, glyph_to_char);
8643 HeapFree(GetProcessHeap(), 0, buf);
8645 if (cPairs && kern_pair)
8647 cPairs = min(cPairs, font->total_kern_pairs);
8648 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8650 else cPairs = font->total_kern_pairs;
8652 LeaveCriticalSection( &freetype_cs );
8653 return cPairs;
8656 static const struct gdi_dc_funcs freetype_funcs =
8658 NULL, /* pAbortDoc */
8659 NULL, /* pAbortPath */
8660 NULL, /* pAlphaBlend */
8661 NULL, /* pAngleArc */
8662 NULL, /* pArc */
8663 NULL, /* pArcTo */
8664 NULL, /* pBeginPath */
8665 NULL, /* pBlendImage */
8666 NULL, /* pChord */
8667 NULL, /* pCloseFigure */
8668 NULL, /* pCreateCompatibleDC */
8669 freetype_CreateDC, /* pCreateDC */
8670 freetype_DeleteDC, /* pDeleteDC */
8671 NULL, /* pDeleteObject */
8672 NULL, /* pDeviceCapabilities */
8673 NULL, /* pEllipse */
8674 NULL, /* pEndDoc */
8675 NULL, /* pEndPage */
8676 NULL, /* pEndPath */
8677 freetype_EnumFonts, /* pEnumFonts */
8678 NULL, /* pEnumICMProfiles */
8679 NULL, /* pExcludeClipRect */
8680 NULL, /* pExtDeviceMode */
8681 NULL, /* pExtEscape */
8682 NULL, /* pExtFloodFill */
8683 NULL, /* pExtSelectClipRgn */
8684 NULL, /* pExtTextOut */
8685 NULL, /* pFillPath */
8686 NULL, /* pFillRgn */
8687 NULL, /* pFlattenPath */
8688 freetype_FontIsLinked, /* pFontIsLinked */
8689 NULL, /* pFrameRgn */
8690 NULL, /* pGdiComment */
8691 NULL, /* pGetBoundsRect */
8692 freetype_GetCharABCWidths, /* pGetCharABCWidths */
8693 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
8694 freetype_GetCharWidth, /* pGetCharWidth */
8695 NULL, /* pGetDeviceCaps */
8696 NULL, /* pGetDeviceGammaRamp */
8697 freetype_GetFontData, /* pGetFontData */
8698 freetype_GetFontRealizationInfo, /* pGetFontRealizationInfo */
8699 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
8700 freetype_GetGlyphIndices, /* pGetGlyphIndices */
8701 freetype_GetGlyphOutline, /* pGetGlyphOutline */
8702 NULL, /* pGetICMProfile */
8703 NULL, /* pGetImage */
8704 freetype_GetKerningPairs, /* pGetKerningPairs */
8705 NULL, /* pGetNearestColor */
8706 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
8707 NULL, /* pGetPixel */
8708 NULL, /* pGetSystemPaletteEntries */
8709 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
8710 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
8711 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
8712 freetype_GetTextFace, /* pGetTextFace */
8713 freetype_GetTextMetrics, /* pGetTextMetrics */
8714 NULL, /* pGradientFill */
8715 NULL, /* pIntersectClipRect */
8716 NULL, /* pInvertRgn */
8717 NULL, /* pLineTo */
8718 NULL, /* pModifyWorldTransform */
8719 NULL, /* pMoveTo */
8720 NULL, /* pOffsetClipRgn */
8721 NULL, /* pOffsetViewportOrg */
8722 NULL, /* pOffsetWindowOrg */
8723 NULL, /* pPaintRgn */
8724 NULL, /* pPatBlt */
8725 NULL, /* pPie */
8726 NULL, /* pPolyBezier */
8727 NULL, /* pPolyBezierTo */
8728 NULL, /* pPolyDraw */
8729 NULL, /* pPolyPolygon */
8730 NULL, /* pPolyPolyline */
8731 NULL, /* pPolygon */
8732 NULL, /* pPolyline */
8733 NULL, /* pPolylineTo */
8734 NULL, /* pPutImage */
8735 NULL, /* pRealizeDefaultPalette */
8736 NULL, /* pRealizePalette */
8737 NULL, /* pRectangle */
8738 NULL, /* pResetDC */
8739 NULL, /* pRestoreDC */
8740 NULL, /* pRoundRect */
8741 NULL, /* pSaveDC */
8742 NULL, /* pScaleViewportExt */
8743 NULL, /* pScaleWindowExt */
8744 NULL, /* pSelectBitmap */
8745 NULL, /* pSelectBrush */
8746 NULL, /* pSelectClipPath */
8747 freetype_SelectFont, /* pSelectFont */
8748 NULL, /* pSelectPalette */
8749 NULL, /* pSelectPen */
8750 NULL, /* pSetArcDirection */
8751 NULL, /* pSetBkColor */
8752 NULL, /* pSetBkMode */
8753 NULL, /* pSetDCBrushColor */
8754 NULL, /* pSetDCPenColor */
8755 NULL, /* pSetDIBColorTable */
8756 NULL, /* pSetDIBitsToDevice */
8757 NULL, /* pSetDeviceClipping */
8758 NULL, /* pSetDeviceGammaRamp */
8759 NULL, /* pSetLayout */
8760 NULL, /* pSetMapMode */
8761 NULL, /* pSetMapperFlags */
8762 NULL, /* pSetPixel */
8763 NULL, /* pSetPolyFillMode */
8764 NULL, /* pSetROP2 */
8765 NULL, /* pSetRelAbs */
8766 NULL, /* pSetStretchBltMode */
8767 NULL, /* pSetTextAlign */
8768 NULL, /* pSetTextCharacterExtra */
8769 NULL, /* pSetTextColor */
8770 NULL, /* pSetTextJustification */
8771 NULL, /* pSetViewportExt */
8772 NULL, /* pSetViewportOrg */
8773 NULL, /* pSetWindowExt */
8774 NULL, /* pSetWindowOrg */
8775 NULL, /* pSetWorldTransform */
8776 NULL, /* pStartDoc */
8777 NULL, /* pStartPage */
8778 NULL, /* pStretchBlt */
8779 NULL, /* pStretchDIBits */
8780 NULL, /* pStrokeAndFillPath */
8781 NULL, /* pStrokePath */
8782 NULL, /* pUnrealizePalette */
8783 NULL, /* pWidenPath */
8784 NULL, /* wine_get_wgl_driver */
8785 GDI_PRIORITY_FONT_DRV /* priority */
8788 #else /* HAVE_FREETYPE */
8790 struct font_fileinfo;
8792 /*************************************************************************/
8794 BOOL WineEngInit(void)
8796 return FALSE;
8799 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8801 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8802 return 1;
8805 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8807 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8808 return TRUE;
8811 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
8813 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
8814 return NULL;
8817 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
8818 LPCWSTR font_file, LPCWSTR font_path )
8820 FIXME("stub\n");
8821 return FALSE;
8824 /*************************************************************************
8825 * GetRasterizerCaps (GDI32.@)
8827 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8829 lprs->nSize = sizeof(RASTERIZER_STATUS);
8830 lprs->wFlags = 0;
8831 lprs->nLanguageID = 0;
8832 return TRUE;
8835 /*************************************************************************
8836 * GetFontFileInfo (GDI32.@)
8838 BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_fileinfo *info, DWORD size, DWORD *needed)
8840 *needed = 0;
8841 return FALSE;
8844 #endif /* HAVE_FREETYPE */