gdi32: Fixup the internal ntmFlags for bitmap fonts.
[wine.git] / dlls / gdi32 / freetype.c
blobf7cd0eea2694ab70398ff66e66794edcc7d054a5
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;
1945 FT_WinFNT_HeaderRec winfnt_header;
1947 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1948 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1950 /* fixup the flag for our fake-bold implementation. */
1951 if (!FT_IS_SCALABLE( ft_face ) &&
1952 !pFT_Get_WinFNT_Header( ft_face, &winfnt_header ) &&
1953 winfnt_header.weight > FW_NORMAL )
1954 flags |= NTM_BOLD;
1956 if (flags == 0) flags = NTM_REGULAR;
1958 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1959 flags |= NTM_PS_OPENTYPE;
1961 return flags;
1964 static inline void get_bitmap_size( FT_Face ft_face, Bitmap_Size *face_size )
1966 My_FT_Bitmap_Size *size;
1967 FT_WinFNT_HeaderRec winfnt_header;
1969 size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1970 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1971 size->height, size->width, size->size >> 6,
1972 size->x_ppem >> 6, size->y_ppem >> 6);
1973 face_size->height = size->height;
1974 face_size->width = size->width;
1975 face_size->size = size->size;
1976 face_size->x_ppem = size->x_ppem;
1977 face_size->y_ppem = size->y_ppem;
1979 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header )) {
1980 face_size->internal_leading = winfnt_header.internal_leading;
1981 if (winfnt_header.external_leading > 0 &&
1982 (face_size->height ==
1983 winfnt_header.pixel_height + winfnt_header.external_leading))
1984 face_size->height = winfnt_header.pixel_height;
1988 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1990 TT_OS2 *os2;
1991 FT_UInt dummy;
1992 CHARSETINFO csi;
1993 FT_WinFNT_HeaderRec winfnt_header;
1994 int i;
1996 memset( fs, 0, sizeof(*fs) );
1998 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1999 if (os2)
2001 fs->fsUsb[0] = os2->ulUnicodeRange1;
2002 fs->fsUsb[1] = os2->ulUnicodeRange2;
2003 fs->fsUsb[2] = os2->ulUnicodeRange3;
2004 fs->fsUsb[3] = os2->ulUnicodeRange4;
2006 if (os2->version == 0)
2008 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
2009 fs->fsCsb[0] = FS_LATIN1;
2010 else
2011 fs->fsCsb[0] = FS_SYMBOL;
2013 else
2015 fs->fsCsb[0] = os2->ulCodePageRange1;
2016 fs->fsCsb[1] = os2->ulCodePageRange2;
2019 else
2021 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
2023 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
2024 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
2025 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
2026 *fs = csi.fs;
2030 if (fs->fsCsb[0] == 0)
2032 /* let's see if we can find any interesting cmaps */
2033 for (i = 0; i < ft_face->num_charmaps; i++)
2035 switch (ft_face->charmaps[i]->encoding)
2037 case FT_ENCODING_UNICODE:
2038 case FT_ENCODING_APPLE_ROMAN:
2039 fs->fsCsb[0] |= FS_LATIN1;
2040 break;
2041 case FT_ENCODING_MS_SYMBOL:
2042 fs->fsCsb[0] |= FS_SYMBOL;
2043 break;
2044 default:
2045 break;
2051 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
2052 DWORD flags )
2054 struct stat st;
2055 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
2057 face->refcount = 1;
2058 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
2059 if (!face->StyleName) face->StyleName = towstr( CP_ACP, ft_face->style_name );
2061 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
2062 if (flags & ADDFONT_VERTICAL_FONT)
2063 face->FullName = prepend_at( face->FullName );
2065 face->dev = 0;
2066 face->ino = 0;
2067 if (file)
2069 face->file = towstr( CP_UNIXCP, file );
2070 face->font_data_ptr = NULL;
2071 face->font_data_size = 0;
2072 if (!stat( file, &st ))
2074 face->dev = st.st_dev;
2075 face->ino = st.st_ino;
2078 else
2080 face->file = NULL;
2081 face->font_data_ptr = font_data_ptr;
2082 face->font_data_size = font_data_size;
2085 face->face_index = face_index;
2086 get_fontsig( ft_face, &face->fs );
2087 face->ntmFlags = get_ntm_flags( ft_face );
2088 face->font_version = get_font_version( ft_face );
2090 if (FT_IS_SCALABLE( ft_face ))
2092 memset( &face->size, 0, sizeof(face->size) );
2093 face->scalable = TRUE;
2095 else
2097 get_bitmap_size( ft_face, &face->size );
2098 face->scalable = FALSE;
2101 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
2102 face->flags = flags;
2103 face->family = NULL;
2104 face->cached_enum_data = NULL;
2106 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
2107 face->fs.fsCsb[0], face->fs.fsCsb[1],
2108 face->fs.fsUsb[0], face->fs.fsUsb[1],
2109 face->fs.fsUsb[2], face->fs.fsUsb[3]);
2111 return face;
2114 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
2115 FT_Long face_index, DWORD flags )
2117 Face *face;
2118 Family *family;
2120 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags );
2121 family = get_family( ft_face, flags & ADDFONT_VERTICAL_FONT );
2122 if (strlenW(family->FamilyName) >= LF_FACESIZE)
2124 WARN("Ignoring %s because name is too long\n", debugstr_w(family->FamilyName));
2125 release_face( face );
2126 release_family( family );
2127 return;
2130 if (insert_face_in_family_list( face, family ))
2132 if (flags & ADDFONT_ADD_TO_CACHE)
2133 add_face_to_cache( face );
2135 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
2136 debugstr_w(face->StyleName));
2138 release_face( face );
2139 release_family( family );
2142 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
2143 FT_Long face_index, BOOL allow_bitmap )
2145 FT_Error err;
2146 TT_OS2 *pOS2;
2147 FT_Face ft_face;
2149 if (file)
2151 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
2152 err = pFT_New_Face(library, file, face_index, &ft_face);
2154 else
2156 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
2157 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
2160 if (err != 0)
2162 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
2163 return NULL;
2166 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
2167 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
2169 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
2170 goto fail;
2173 if (!FT_IS_SFNT( ft_face ))
2175 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
2177 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
2178 goto fail;
2181 else
2183 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
2184 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
2185 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
2187 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
2188 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
2189 goto fail;
2192 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
2193 we don't want to load these. */
2194 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
2196 FT_ULong len = 0;
2198 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
2200 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
2201 goto fail;
2206 if (!ft_face->family_name || !ft_face->style_name)
2208 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
2209 goto fail;
2212 return ft_face;
2213 fail:
2214 pFT_Done_Face( ft_face );
2215 return NULL;
2218 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
2220 FT_Face ft_face;
2221 FT_Long face_index = 0, num_faces;
2222 INT ret = 0;
2224 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
2225 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
2227 #ifdef HAVE_CARBON_CARBON_H
2228 if(file)
2230 char **mac_list = expand_mac_font(file);
2231 if(mac_list)
2233 BOOL had_one = FALSE;
2234 char **cursor;
2235 for(cursor = mac_list; *cursor; cursor++)
2237 had_one = TRUE;
2238 AddFontToList(*cursor, NULL, 0, flags);
2239 HeapFree(GetProcessHeap(), 0, *cursor);
2241 HeapFree(GetProcessHeap(), 0, mac_list);
2242 if(had_one)
2243 return 1;
2246 #endif /* HAVE_CARBON_CARBON_H */
2248 do {
2249 const DWORD FS_DBCS_MASK = FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB;
2250 FONTSIGNATURE fs;
2252 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_ALLOW_BITMAP );
2253 if (!ft_face) return 0;
2255 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
2257 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
2258 pFT_Done_Face(ft_face);
2259 return 0;
2262 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags);
2263 ++ret;
2265 get_fontsig(ft_face, &fs);
2266 if (fs.fsCsb[0] & FS_DBCS_MASK)
2268 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index,
2269 flags | ADDFONT_VERTICAL_FONT);
2270 ++ret;
2273 num_faces = ft_face->num_faces;
2274 pFT_Done_Face(ft_face);
2275 } while(num_faces > ++face_index);
2276 return ret;
2279 static int remove_font_resource( const char *file, DWORD flags )
2281 Family *family, *family_next;
2282 Face *face, *face_next;
2283 struct stat st;
2284 int count = 0;
2286 if (stat( file, &st ) == -1) return 0;
2287 LIST_FOR_EACH_ENTRY_SAFE( family, family_next, &font_list, Family, entry )
2289 family->refcount++;
2290 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, Face, entry )
2292 if (!face->file) continue;
2293 if (LOWORD(face->flags) != LOWORD(flags)) continue;
2294 if (st.st_dev == face->dev && st.st_ino == face->ino)
2296 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount );
2297 release_face( face );
2298 count++;
2301 release_family( family );
2303 return count;
2306 static void DumpFontList(void)
2308 Family *family;
2309 Face *face;
2311 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2312 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
2313 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2314 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
2315 if(!face->scalable)
2316 TRACE(" %d", face->size.height);
2317 TRACE("\n");
2322 static BOOL map_font_family(const WCHAR *orig, const WCHAR *repl)
2324 Family *family = find_family_from_any_name(repl);
2325 if (family != NULL)
2327 Family *new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2328 if (new_family != NULL)
2330 TRACE("mapping %s to %s\n", debugstr_w(repl), debugstr_w(orig));
2331 new_family->FamilyName = strdupW(orig);
2332 new_family->EnglishName = NULL;
2333 list_init(&new_family->faces);
2334 new_family->replacement = &family->faces;
2335 list_add_tail(&font_list, &new_family->entry);
2336 return TRUE;
2339 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(repl));
2340 return FALSE;
2343 /***********************************************************
2344 * The replacement list is a way to map an entire font
2345 * family onto another family. For example adding
2347 * [HKCU\Software\Wine\Fonts\Replacements]
2348 * "Wingdings"="Winedings"
2350 * would enumerate the Winedings font both as Winedings and
2351 * Wingdings. However if a real Wingdings font is present the
2352 * replacement does not take place.
2355 static void LoadReplaceList(void)
2357 HKEY hkey;
2358 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2359 LPWSTR value;
2360 LPVOID data;
2362 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2363 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
2365 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2366 &valuelen, &datalen, NULL, NULL);
2368 valuelen++; /* returned value doesn't include room for '\0' */
2369 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2370 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2372 dlen = datalen;
2373 vlen = valuelen;
2374 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data, &dlen) == ERROR_SUCCESS)
2376 /* "NewName"="Oldname" */
2377 if(!find_family_from_any_name(value))
2379 if (type == REG_MULTI_SZ)
2381 WCHAR *replace = data;
2382 while(*replace)
2384 if (map_font_family(value, replace))
2385 break;
2386 replace += strlenW(replace) + 1;
2389 else
2390 map_font_family(value, data);
2392 else
2393 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2395 /* reset dlen and vlen */
2396 dlen = datalen;
2397 vlen = valuelen;
2399 HeapFree(GetProcessHeap(), 0, data);
2400 HeapFree(GetProcessHeap(), 0, value);
2401 RegCloseKey(hkey);
2405 static const WCHAR *font_links_list[] =
2407 Lucida_Sans_Unicode,
2408 Microsoft_Sans_Serif,
2409 Tahoma
2412 static const struct font_links_defaults_list
2414 /* Keyed off substitution for "MS Shell Dlg" */
2415 const WCHAR *shelldlg;
2416 /* Maximum of four substitutes, plus terminating NULL pointer */
2417 const WCHAR *substitutes[5];
2418 } font_links_defaults_list[] =
2420 /* Non East-Asian */
2421 { Tahoma, /* FIXME unverified ordering */
2422 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2424 /* Below lists are courtesy of
2425 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2427 /* Japanese */
2428 { MS_UI_Gothic,
2429 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2431 /* Chinese Simplified */
2432 { SimSun,
2433 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2435 /* Korean */
2436 { Gulim,
2437 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2439 /* Chinese Traditional */
2440 { PMingLiU,
2441 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2446 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2448 SYSTEM_LINKS *font_link;
2450 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2452 if(!strcmpiW(font_link->font_name, name))
2453 return font_link;
2456 return NULL;
2459 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2461 const WCHAR *value;
2462 int i;
2463 FontSubst *psub;
2464 Family *family;
2465 Face *face;
2466 const WCHAR *file;
2468 if (values)
2470 SYSTEM_LINKS *font_link;
2472 psub = get_font_subst(&font_subst_list, name, -1);
2473 /* Don't store fonts that are only substitutes for other fonts */
2474 if(psub)
2476 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2477 return;
2480 font_link = find_font_link(name);
2481 if (font_link == NULL)
2483 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2484 font_link->font_name = strdupW(name);
2485 list_init(&font_link->links);
2486 list_add_tail(&system_links, &font_link->entry);
2489 memset(&font_link->fs, 0, sizeof font_link->fs);
2490 for (i = 0; values[i] != NULL; i++)
2492 const struct list *face_list;
2493 CHILD_FONT *child_font;
2495 value = values[i];
2496 if (!strcmpiW(name,value))
2497 continue;
2498 psub = get_font_subst(&font_subst_list, value, -1);
2499 if(psub)
2500 value = psub->to.name;
2501 family = find_family_from_name(value);
2502 if (!family)
2503 continue;
2504 file = NULL;
2505 /* Use first extant filename for this Family */
2506 face_list = get_face_list_from_family(family);
2507 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2509 if (!face->file)
2510 continue;
2511 file = strrchrW(face->file, '/');
2512 if (!file)
2513 file = face->file;
2514 else
2515 file++;
2516 break;
2518 if (!file)
2519 continue;
2520 face = find_face_from_filename(file, value);
2521 if(!face)
2523 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2524 continue;
2527 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2528 child_font->face = face;
2529 child_font->font = NULL;
2530 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2531 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2532 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2533 child_font->face->face_index);
2534 list_add_tail(&font_link->links, &child_font->entry);
2536 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2542 /*************************************************************
2543 * init_system_links
2545 static BOOL init_system_links(void)
2547 HKEY hkey;
2548 BOOL ret = FALSE;
2549 DWORD type, max_val, max_data, val_len, data_len, index;
2550 WCHAR *value, *data;
2551 WCHAR *entry, *next;
2552 SYSTEM_LINKS *font_link, *system_font_link;
2553 CHILD_FONT *child_font;
2554 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2555 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2556 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2557 Face *face;
2558 FontSubst *psub;
2559 UINT i, j;
2561 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2563 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2564 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2565 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2566 val_len = max_val + 1;
2567 data_len = max_data;
2568 index = 0;
2569 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2571 psub = get_font_subst(&font_subst_list, value, -1);
2572 /* Don't store fonts that are only substitutes for other fonts */
2573 if(psub)
2575 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2576 goto next;
2578 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2579 font_link->font_name = strdupW(value);
2580 memset(&font_link->fs, 0, sizeof font_link->fs);
2581 list_init(&font_link->links);
2582 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2584 WCHAR *face_name;
2585 CHILD_FONT *child_font;
2587 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2589 next = entry + strlenW(entry) + 1;
2591 face_name = strchrW(entry, ',');
2592 if(face_name)
2594 *face_name++ = 0;
2595 while(isspaceW(*face_name))
2596 face_name++;
2598 psub = get_font_subst(&font_subst_list, face_name, -1);
2599 if(psub)
2600 face_name = psub->to.name;
2602 face = find_face_from_filename(entry, face_name);
2603 if(!face)
2605 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2606 continue;
2609 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2610 child_font->face = face;
2611 child_font->font = NULL;
2612 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2613 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2614 TRACE("Adding file %s index %ld\n",
2615 debugstr_w(child_font->face->file), child_font->face->face_index);
2616 list_add_tail(&font_link->links, &child_font->entry);
2618 list_add_tail(&system_links, &font_link->entry);
2619 next:
2620 val_len = max_val + 1;
2621 data_len = max_data;
2624 HeapFree(GetProcessHeap(), 0, value);
2625 HeapFree(GetProcessHeap(), 0, data);
2626 RegCloseKey(hkey);
2630 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2631 if (!psub) {
2632 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2633 goto skip_internal;
2636 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2638 const FontSubst *psub2;
2639 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2641 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2643 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2644 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2646 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2647 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2649 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2651 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2655 skip_internal:
2657 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2658 that Tahoma has */
2660 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2661 system_font_link->font_name = strdupW(System);
2662 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2663 list_init(&system_font_link->links);
2665 face = find_face_from_filename(tahoma_ttf, Tahoma);
2666 if(face)
2668 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2669 child_font->face = face;
2670 child_font->font = NULL;
2671 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2672 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2673 TRACE("Found Tahoma in %s index %ld\n",
2674 debugstr_w(child_font->face->file), child_font->face->face_index);
2675 list_add_tail(&system_font_link->links, &child_font->entry);
2677 font_link = find_font_link(Tahoma);
2678 if (font_link != NULL)
2680 CHILD_FONT *font_link_entry;
2681 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2683 CHILD_FONT *new_child;
2684 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2685 new_child->face = font_link_entry->face;
2686 new_child->font = NULL;
2687 new_child->face->refcount++;
2688 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2689 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2690 list_add_tail(&system_font_link->links, &new_child->entry);
2693 list_add_tail(&system_links, &system_font_link->entry);
2694 return ret;
2697 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2699 DIR *dir;
2700 struct dirent *dent;
2701 char path[MAX_PATH];
2703 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2705 dir = opendir(dirname);
2706 if(!dir) {
2707 WARN("Can't open directory %s\n", debugstr_a(dirname));
2708 return FALSE;
2710 while((dent = readdir(dir)) != NULL) {
2711 struct stat statbuf;
2713 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2714 continue;
2716 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2718 sprintf(path, "%s/%s", dirname, dent->d_name);
2720 if(stat(path, &statbuf) == -1)
2722 WARN("Can't stat %s\n", debugstr_a(path));
2723 continue;
2725 if(S_ISDIR(statbuf.st_mode))
2726 ReadFontDir(path, external_fonts);
2727 else
2729 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2730 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2731 AddFontToList(path, NULL, 0, addfont_flags);
2734 closedir(dir);
2735 return TRUE;
2738 #ifdef SONAME_LIBFONTCONFIG
2740 static BOOL fontconfig_enabled;
2742 static UINT parse_aa_pattern( FcPattern *pattern )
2744 FcBool antialias;
2745 int rgba;
2746 UINT aa_flags = 0;
2748 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2749 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2751 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2753 switch (rgba)
2755 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2756 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2757 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2758 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2759 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2762 return aa_flags;
2765 static void init_fontconfig(void)
2767 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2769 if (!fc_handle)
2771 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2772 return;
2775 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2776 LOAD_FUNCPTR(FcConfigSubstitute);
2777 LOAD_FUNCPTR(FcFontList);
2778 LOAD_FUNCPTR(FcFontSetDestroy);
2779 LOAD_FUNCPTR(FcInit);
2780 LOAD_FUNCPTR(FcObjectSetAdd);
2781 LOAD_FUNCPTR(FcObjectSetCreate);
2782 LOAD_FUNCPTR(FcObjectSetDestroy);
2783 LOAD_FUNCPTR(FcPatternCreate);
2784 LOAD_FUNCPTR(FcPatternDestroy);
2785 LOAD_FUNCPTR(FcPatternGetBool);
2786 LOAD_FUNCPTR(FcPatternGetInteger);
2787 LOAD_FUNCPTR(FcPatternGetString);
2788 #undef LOAD_FUNCPTR
2790 if (pFcInit())
2792 FcPattern *pattern = pFcPatternCreate();
2793 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2794 default_aa_flags = parse_aa_pattern( pattern );
2795 pFcPatternDestroy( pattern );
2796 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2797 fontconfig_enabled = TRUE;
2801 static void load_fontconfig_fonts(void)
2803 FcPattern *pat;
2804 FcObjectSet *os;
2805 FcFontSet *fontset;
2806 int i, len;
2807 char *file;
2808 const char *ext;
2810 if (!fontconfig_enabled) return;
2812 pat = pFcPatternCreate();
2813 os = pFcObjectSetCreate();
2814 pFcObjectSetAdd(os, FC_FILE);
2815 pFcObjectSetAdd(os, FC_SCALABLE);
2816 pFcObjectSetAdd(os, FC_ANTIALIAS);
2817 pFcObjectSetAdd(os, FC_RGBA);
2818 fontset = pFcFontList(NULL, pat, os);
2819 if(!fontset) return;
2820 for(i = 0; i < fontset->nfont; i++) {
2821 FcBool scalable;
2822 DWORD aa_flags;
2824 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2825 continue;
2827 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2829 /* We're just interested in OT/TT fonts for now, so this hack just
2830 picks up the scalable fonts without extensions .pf[ab] to save time
2831 loading every other font */
2833 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2835 TRACE("not scalable\n");
2836 continue;
2839 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2840 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2842 len = strlen( file );
2843 if(len < 4) continue;
2844 ext = &file[ len - 3 ];
2845 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2846 AddFontToList(file, NULL, 0,
2847 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2849 pFcFontSetDestroy(fontset);
2850 pFcObjectSetDestroy(os);
2851 pFcPatternDestroy(pat);
2854 #elif defined(HAVE_CARBON_CARBON_H)
2856 static void load_mac_font_callback(const void *value, void *context)
2858 CFStringRef pathStr = value;
2859 CFIndex len;
2860 char* path;
2862 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2863 path = HeapAlloc(GetProcessHeap(), 0, len);
2864 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2866 TRACE("font file %s\n", path);
2867 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2869 HeapFree(GetProcessHeap(), 0, path);
2872 static void load_mac_fonts(void)
2874 CFStringRef removeDupesKey;
2875 CFBooleanRef removeDupesValue;
2876 CFDictionaryRef options;
2877 CTFontCollectionRef col;
2878 CFArrayRef descs;
2879 CFMutableSetRef paths;
2880 CFIndex i;
2882 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2883 removeDupesValue = kCFBooleanTrue;
2884 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2885 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2886 col = CTFontCollectionCreateFromAvailableFonts(options);
2887 if (options) CFRelease(options);
2888 if (!col)
2890 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2891 return;
2894 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2895 CFRelease(col);
2896 if (!descs)
2898 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2899 return;
2902 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2903 if (!paths)
2905 WARN("CFSetCreateMutable failed\n");
2906 CFRelease(descs);
2907 return;
2910 for (i = 0; i < CFArrayGetCount(descs); i++)
2912 CTFontDescriptorRef desc;
2913 CTFontRef font;
2914 ATSFontRef atsFont;
2915 OSStatus status;
2916 FSRef fsref;
2917 CFURLRef url;
2918 CFStringRef ext;
2919 CFStringRef path;
2921 desc = CFArrayGetValueAtIndex(descs, i);
2923 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2924 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2925 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2926 if (!font) continue;
2928 atsFont = CTFontGetPlatformFont(font, NULL);
2929 if (!atsFont)
2931 CFRelease(font);
2932 continue;
2935 status = ATSFontGetFileReference(atsFont, &fsref);
2936 CFRelease(font);
2937 if (status != noErr) continue;
2939 url = CFURLCreateFromFSRef(NULL, &fsref);
2940 if (!url) continue;
2942 ext = CFURLCopyPathExtension(url);
2943 if (ext)
2945 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2946 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2947 CFRelease(ext);
2948 if (skip)
2950 CFRelease(url);
2951 continue;
2955 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2956 CFRelease(url);
2957 if (!path) continue;
2959 CFSetAddValue(paths, path);
2960 CFRelease(path);
2963 CFRelease(descs);
2965 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2966 CFRelease(paths);
2969 #endif
2971 static char *get_data_dir_path( LPCWSTR file )
2973 char *unix_name = NULL;
2974 const char *data_dir = wine_get_data_dir();
2976 if (!data_dir) data_dir = wine_get_build_dir();
2978 if (data_dir)
2980 INT len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2982 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2983 strcpy(unix_name, data_dir);
2984 strcat(unix_name, "/fonts/");
2986 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2988 return unix_name;
2991 static BOOL load_font_from_data_dir(LPCWSTR file)
2993 BOOL ret = FALSE;
2994 char *unix_name = get_data_dir_path( file );
2996 if (unix_name)
2998 EnterCriticalSection( &freetype_cs );
2999 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3000 LeaveCriticalSection( &freetype_cs );
3001 HeapFree(GetProcessHeap(), 0, unix_name);
3003 return ret;
3006 static char *get_winfonts_dir_path(LPCWSTR file)
3008 static const WCHAR slashW[] = {'\\','\0'};
3009 WCHAR windowsdir[MAX_PATH];
3011 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3012 strcatW(windowsdir, fontsW);
3013 strcatW(windowsdir, slashW);
3014 strcatW(windowsdir, file);
3015 return wine_get_unix_file_name( windowsdir );
3018 static void load_system_fonts(void)
3020 HKEY hkey;
3021 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
3022 const WCHAR * const *value;
3023 DWORD dlen, type;
3024 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3025 char *unixname;
3027 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
3028 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3029 strcatW(windowsdir, fontsW);
3030 for(value = SystemFontValues; *value; value++) {
3031 dlen = sizeof(data);
3032 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
3033 type == REG_SZ) {
3034 BOOL added = FALSE;
3036 sprintfW(pathW, fmtW, windowsdir, data);
3037 if((unixname = wine_get_unix_file_name(pathW))) {
3038 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3039 HeapFree(GetProcessHeap(), 0, unixname);
3041 if (!added)
3042 load_font_from_data_dir(data);
3045 RegCloseKey(hkey);
3049 /*************************************************************
3051 * This adds registry entries for any externally loaded fonts
3052 * (fonts from fontconfig or FontDirs). It also deletes entries
3053 * of no longer existing fonts.
3056 static void update_reg_entries(void)
3058 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
3059 LPWSTR valueW;
3060 DWORD len;
3061 Family *family;
3062 Face *face;
3063 WCHAR *file, *path;
3064 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
3066 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
3067 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
3068 ERR("Can't create Windows font reg key\n");
3069 goto end;
3072 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
3073 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
3074 ERR("Can't create Windows font reg key\n");
3075 goto end;
3078 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
3079 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
3080 ERR("Can't create external font reg key\n");
3081 goto end;
3084 /* enumerate the fonts and add external ones to the two keys */
3086 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
3087 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
3088 char *buffer;
3089 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
3091 if(face->FullName)
3093 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
3094 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3095 strcpyW(valueW, face->FullName);
3097 else
3099 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
3100 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3101 strcpyW(valueW, family->FamilyName);
3104 buffer = strWtoA( CP_UNIXCP, face->file );
3105 path = wine_get_dos_file_name( buffer );
3106 HeapFree( GetProcessHeap(), 0, buffer );
3108 if (path)
3109 file = path;
3110 else if ((file = strrchrW(face->file, '/')))
3111 file++;
3112 else
3113 file = face->file;
3115 len = strlenW(file) + 1;
3116 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3117 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3118 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3120 HeapFree(GetProcessHeap(), 0, path);
3121 HeapFree(GetProcessHeap(), 0, valueW);
3124 end:
3125 if(external_key) RegCloseKey(external_key);
3126 if(win9x_key) RegCloseKey(win9x_key);
3127 if(winnt_key) RegCloseKey(winnt_key);
3130 static void delete_external_font_keys(void)
3132 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
3133 DWORD dlen, vlen, datalen, valuelen, i, type;
3134 LPWSTR valueW;
3135 LPVOID data;
3137 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
3138 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
3139 ERR("Can't create Windows font reg key\n");
3140 goto end;
3143 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
3144 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
3145 ERR("Can't create Windows font reg key\n");
3146 goto end;
3149 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
3150 ERR("Can't create external font reg key\n");
3151 goto end;
3154 /* Delete all external fonts added last time */
3156 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3157 &valuelen, &datalen, NULL, NULL);
3158 valuelen++; /* returned value doesn't include room for '\0' */
3159 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3160 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3162 dlen = datalen * sizeof(WCHAR);
3163 vlen = valuelen;
3164 i = 0;
3165 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
3166 &dlen) == ERROR_SUCCESS) {
3168 RegDeleteValueW(winnt_key, valueW);
3169 RegDeleteValueW(win9x_key, valueW);
3170 /* reset dlen and vlen */
3171 dlen = datalen;
3172 vlen = valuelen;
3174 HeapFree(GetProcessHeap(), 0, data);
3175 HeapFree(GetProcessHeap(), 0, valueW);
3177 /* Delete the old external fonts key */
3178 RegCloseKey(external_key);
3179 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
3181 end:
3182 if(win9x_key) RegCloseKey(win9x_key);
3183 if(winnt_key) RegCloseKey(winnt_key);
3186 /*************************************************************
3187 * WineEngAddFontResourceEx
3190 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3192 INT ret = 0;
3194 GDI_CheckNotLock();
3196 if (ft_handle) /* do it only if we have freetype up and running */
3198 char *unixname;
3200 EnterCriticalSection( &freetype_cs );
3202 if((unixname = wine_get_unix_file_name(file)))
3204 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3206 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3207 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
3208 HeapFree(GetProcessHeap(), 0, unixname);
3210 if (!ret && !strchrW(file, '\\')) {
3211 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
3212 if ((unixname = get_winfonts_dir_path( file )))
3214 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3215 HeapFree(GetProcessHeap(), 0, unixname);
3217 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
3218 if (!ret && (unixname = get_data_dir_path( file )))
3220 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3221 HeapFree(GetProcessHeap(), 0, unixname);
3225 LeaveCriticalSection( &freetype_cs );
3227 return ret;
3230 /*************************************************************
3231 * WineEngAddFontMemResourceEx
3234 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3236 GDI_CheckNotLock();
3238 if (ft_handle) /* do it only if we have freetype up and running */
3240 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
3242 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
3243 memcpy(pFontCopy, pbFont, cbFont);
3245 EnterCriticalSection( &freetype_cs );
3246 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3247 LeaveCriticalSection( &freetype_cs );
3249 if (*pcFonts == 0)
3251 TRACE("AddFontToList failed\n");
3252 HeapFree(GetProcessHeap(), 0, pFontCopy);
3253 return 0;
3255 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
3256 * For now return something unique but quite random
3258 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
3259 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
3262 *pcFonts = 0;
3263 return 0;
3266 /*************************************************************
3267 * WineEngRemoveFontResourceEx
3270 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3272 INT ret = 0;
3274 GDI_CheckNotLock();
3276 if (ft_handle) /* do it only if we have freetype up and running */
3278 char *unixname;
3280 EnterCriticalSection( &freetype_cs );
3282 if ((unixname = wine_get_unix_file_name(file)))
3284 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3286 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3287 ret = remove_font_resource( unixname, addfont_flags );
3288 HeapFree(GetProcessHeap(), 0, unixname);
3290 if (!ret && !strchrW(file, '\\'))
3292 if ((unixname = get_winfonts_dir_path( file )))
3294 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3295 HeapFree(GetProcessHeap(), 0, unixname);
3297 if (!ret && (unixname = get_data_dir_path( file )))
3299 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3300 HeapFree(GetProcessHeap(), 0, unixname);
3304 LeaveCriticalSection( &freetype_cs );
3306 return ret;
3309 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
3311 WCHAR *fullname;
3312 char *unix_name;
3313 int file_len;
3315 if (!font_file) return NULL;
3317 file_len = strlenW( font_file );
3319 if (font_path && font_path[0])
3321 int path_len = strlenW( font_path );
3322 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
3323 if (!fullname) return NULL;
3324 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
3325 fullname[path_len] = '\\';
3326 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
3328 else
3330 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
3331 if (!len) return NULL;
3332 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3333 if (!fullname) return NULL;
3334 GetFullPathNameW( font_file, len, fullname, NULL );
3337 unix_name = wine_get_unix_file_name( fullname );
3338 HeapFree( GetProcessHeap(), 0, fullname );
3339 return unix_name;
3342 #include <pshpack1.h>
3343 struct fontdir
3345 WORD num_of_resources;
3346 WORD res_id;
3347 WORD dfVersion;
3348 DWORD dfSize;
3349 CHAR dfCopyright[60];
3350 WORD dfType;
3351 WORD dfPoints;
3352 WORD dfVertRes;
3353 WORD dfHorizRes;
3354 WORD dfAscent;
3355 WORD dfInternalLeading;
3356 WORD dfExternalLeading;
3357 BYTE dfItalic;
3358 BYTE dfUnderline;
3359 BYTE dfStrikeOut;
3360 WORD dfWeight;
3361 BYTE dfCharSet;
3362 WORD dfPixWidth;
3363 WORD dfPixHeight;
3364 BYTE dfPitchAndFamily;
3365 WORD dfAvgWidth;
3366 WORD dfMaxWidth;
3367 BYTE dfFirstChar;
3368 BYTE dfLastChar;
3369 BYTE dfDefaultChar;
3370 BYTE dfBreakChar;
3371 WORD dfWidthBytes;
3372 DWORD dfDevice;
3373 DWORD dfFace;
3374 DWORD dfReserved;
3375 CHAR szFaceName[LF_FACESIZE];
3378 #include <poppack.h>
3380 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
3381 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
3383 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
3385 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3386 Face *face;
3387 WCHAR *name, *english_name;
3388 ENUMLOGFONTEXW elf;
3389 NEWTEXTMETRICEXW ntm;
3390 DWORD type;
3392 if (!ft_face) return FALSE;
3393 face = create_face( ft_face, 0, unix_name, NULL, 0, 0 );
3394 get_family_names( ft_face, &name, &english_name, FALSE );
3395 pFT_Done_Face( ft_face );
3397 GetEnumStructs( face, name, &elf, &ntm, &type );
3398 release_face( face );
3399 HeapFree( GetProcessHeap(), 0, name );
3400 HeapFree( GetProcessHeap(), 0, english_name );
3402 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3404 memset( fd, 0, sizeof(*fd) );
3406 fd->num_of_resources = 1;
3407 fd->res_id = 0;
3408 fd->dfVersion = 0x200;
3409 fd->dfSize = sizeof(*fd);
3410 strcpy( fd->dfCopyright, "Wine fontdir" );
3411 fd->dfType = 0x4003; /* 0x0080 set if private */
3412 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3413 fd->dfVertRes = 72;
3414 fd->dfHorizRes = 72;
3415 fd->dfAscent = ntm.ntmTm.tmAscent;
3416 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3417 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3418 fd->dfItalic = ntm.ntmTm.tmItalic;
3419 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3420 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3421 fd->dfWeight = ntm.ntmTm.tmWeight;
3422 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3423 fd->dfPixWidth = 0;
3424 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3425 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3426 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3427 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3428 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3429 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3430 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3431 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3432 fd->dfWidthBytes = 0;
3433 fd->dfDevice = 0;
3434 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3435 fd->dfReserved = 0;
3436 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3438 return TRUE;
3441 #define NE_FFLAGS_LIBMODULE 0x8000
3442 #define NE_OSFLAGS_WINDOWS 0x02
3444 static const char dos_string[0x40] = "This is a TrueType resource file";
3445 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3447 #include <pshpack2.h>
3449 struct ne_typeinfo
3451 WORD type_id;
3452 WORD count;
3453 DWORD res;
3456 struct ne_nameinfo
3458 WORD off;
3459 WORD len;
3460 WORD flags;
3461 WORD id;
3462 DWORD res;
3465 struct rsrc_tab
3467 WORD align;
3468 struct ne_typeinfo fontdir_type;
3469 struct ne_nameinfo fontdir_name;
3470 struct ne_typeinfo scalable_type;
3471 struct ne_nameinfo scalable_name;
3472 WORD end_of_rsrc;
3473 BYTE fontdir_res_name[8];
3476 #include <poppack.h>
3478 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3480 BOOL ret = FALSE;
3481 HANDLE file;
3482 DWORD size, written;
3483 BYTE *ptr, *start;
3484 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3485 char *font_fileA, *last_part, *ext;
3486 IMAGE_DOS_HEADER dos;
3487 IMAGE_OS2_HEADER ne =
3489 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3490 0, 0, 0, 0, 0, 0,
3491 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3492 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3494 struct rsrc_tab rsrc_tab =
3497 { 0x8007, 1, 0 },
3498 { 0, 0, 0x0c50, 0x2c, 0 },
3499 { 0x80cc, 1, 0 },
3500 { 0, 0, 0x0c50, 0x8001, 0 },
3502 { 7,'F','O','N','T','D','I','R'}
3505 memset( &dos, 0, sizeof(dos) );
3506 dos.e_magic = IMAGE_DOS_SIGNATURE;
3507 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3509 /* import name is last part\0, resident name is last part without extension
3510 non-resident name is "FONTRES:" + lfFaceName */
3512 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3513 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3514 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3516 last_part = strrchr( font_fileA, '\\' );
3517 if (last_part) last_part++;
3518 else last_part = font_fileA;
3519 import_name_len = strlen( last_part ) + 1;
3521 ext = strchr( last_part, '.' );
3522 if (ext) res_name_len = ext - last_part;
3523 else res_name_len = import_name_len - 1;
3525 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3527 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3528 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3529 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3530 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3531 ne.ne_cbenttab = 2;
3532 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3534 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3535 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3536 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3537 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3539 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3540 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3542 if (!ptr)
3544 HeapFree( GetProcessHeap(), 0, font_fileA );
3545 return FALSE;
3548 memcpy( ptr, &dos, sizeof(dos) );
3549 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3550 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3552 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3553 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3555 ptr = start + dos.e_lfanew + ne.ne_restab;
3556 *ptr++ = res_name_len;
3557 memcpy( ptr, last_part, res_name_len );
3559 ptr = start + dos.e_lfanew + ne.ne_imptab;
3560 *ptr++ = import_name_len;
3561 memcpy( ptr, last_part, import_name_len );
3563 ptr = start + ne.ne_nrestab;
3564 *ptr++ = non_res_name_len;
3565 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3566 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3568 ptr = start + (rsrc_tab.scalable_name.off << 4);
3569 memcpy( ptr, font_fileA, font_file_len );
3571 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3572 memcpy( ptr, fontdir, fontdir->dfSize );
3574 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3575 if (file != INVALID_HANDLE_VALUE)
3577 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3578 ret = TRUE;
3579 CloseHandle( file );
3582 HeapFree( GetProcessHeap(), 0, start );
3583 HeapFree( GetProcessHeap(), 0, font_fileA );
3585 return ret;
3588 /*************************************************************
3589 * WineEngCreateScalableFontResource
3592 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3593 LPCWSTR font_file, LPCWSTR font_path )
3595 char *unix_name = get_ttf_file_name( font_file, font_path );
3596 struct fontdir fontdir;
3597 BOOL ret = FALSE;
3599 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3600 SetLastError( ERROR_INVALID_PARAMETER );
3601 else
3603 if (hidden) fontdir.dfType |= 0x80;
3604 ret = create_fot( resource, font_file, &fontdir );
3607 HeapFree( GetProcessHeap(), 0, unix_name );
3608 return ret;
3611 static const struct nls_update_font_list
3613 UINT ansi_cp, oem_cp;
3614 const char *oem, *fixed, *system;
3615 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3616 /* these are for font substitutes */
3617 const char *shelldlg, *tmsrmn;
3618 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3619 *helv_0, *tmsrmn_0;
3620 const struct subst
3622 const char *from, *to;
3623 } arial_0, courier_new_0, times_new_roman_0;
3624 } nls_update_font_list[] =
3626 /* Latin 1 (United States) */
3627 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3628 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3629 "Tahoma","Times New Roman",
3630 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3631 { 0 }, { 0 }, { 0 }
3633 /* Latin 1 (Multilingual) */
3634 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3635 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3636 "Tahoma","Times New Roman", /* FIXME unverified */
3637 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3638 { 0 }, { 0 }, { 0 }
3640 /* Eastern Europe */
3641 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3642 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3643 "Tahoma","Times New Roman", /* FIXME unverified */
3644 "Fixedsys,238", "System,238",
3645 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3646 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3647 { "Arial CE,0", "Arial,238" },
3648 { "Courier New CE,0", "Courier New,238" },
3649 { "Times New Roman CE,0", "Times New Roman,238" }
3651 /* Cyrillic */
3652 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3653 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3654 "Tahoma","Times New Roman", /* FIXME unverified */
3655 "Fixedsys,204", "System,204",
3656 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3657 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3658 { "Arial Cyr,0", "Arial,204" },
3659 { "Courier New Cyr,0", "Courier New,204" },
3660 { "Times New Roman Cyr,0", "Times New Roman,204" }
3662 /* Greek */
3663 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3664 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3665 "Tahoma","Times New Roman", /* FIXME unverified */
3666 "Fixedsys,161", "System,161",
3667 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3668 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3669 { "Arial Greek,0", "Arial,161" },
3670 { "Courier New Greek,0", "Courier New,161" },
3671 { "Times New Roman Greek,0", "Times New Roman,161" }
3673 /* Turkish */
3674 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3675 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3676 "Tahoma","Times New Roman", /* FIXME unverified */
3677 "Fixedsys,162", "System,162",
3678 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3679 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3680 { "Arial Tur,0", "Arial,162" },
3681 { "Courier New Tur,0", "Courier New,162" },
3682 { "Times New Roman Tur,0", "Times New Roman,162" }
3684 /* Hebrew */
3685 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3686 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3687 "Tahoma","Times New Roman", /* FIXME unverified */
3688 "Fixedsys,177", "System,177",
3689 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3690 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3691 { 0 }, { 0 }, { 0 }
3693 /* Arabic */
3694 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3695 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3696 "Microsoft Sans Serif","Times New Roman",
3697 "Fixedsys,178", "System,178",
3698 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3699 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3700 { 0 }, { 0 }, { 0 }
3702 /* Baltic */
3703 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3704 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3705 "Tahoma","Times New Roman", /* FIXME unverified */
3706 "Fixedsys,186", "System,186",
3707 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3708 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3709 { "Arial Baltic,0", "Arial,186" },
3710 { "Courier New Baltic,0", "Courier New,186" },
3711 { "Times New Roman Baltic,0", "Times New Roman,186" }
3713 /* Vietnamese */
3714 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3715 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3716 "Tahoma","Times New Roman", /* FIXME unverified */
3717 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3718 { 0 }, { 0 }, { 0 }
3720 /* Thai */
3721 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3722 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3723 "Tahoma","Times New Roman", /* FIXME unverified */
3724 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3725 { 0 }, { 0 }, { 0 }
3727 /* Japanese */
3728 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3729 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3730 "MS UI Gothic","MS Serif",
3731 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3732 { 0 }, { 0 }, { 0 }
3734 /* Chinese Simplified */
3735 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3736 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3737 "SimSun", "NSimSun",
3738 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3739 { 0 }, { 0 }, { 0 }
3741 /* Korean */
3742 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3743 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3744 "Gulim", "Batang",
3745 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3746 { 0 }, { 0 }, { 0 }
3748 /* Chinese Traditional */
3749 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3750 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3751 "PMingLiU", "MingLiU",
3752 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3753 { 0 }, { 0 }, { 0 }
3757 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3759 return ( ansi_cp == 932 /* CP932 for Japanese */
3760 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3761 || ansi_cp == 949 /* CP949 for Korean */
3762 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3765 static inline HKEY create_fonts_NT_registry_key(void)
3767 HKEY hkey = 0;
3769 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3770 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3771 return hkey;
3774 static inline HKEY create_fonts_9x_registry_key(void)
3776 HKEY hkey = 0;
3778 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3779 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3780 return hkey;
3783 static inline HKEY create_config_fonts_registry_key(void)
3785 HKEY hkey = 0;
3787 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3788 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3789 return hkey;
3792 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3794 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3796 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3797 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3798 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3799 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3802 static void set_value_key(HKEY hkey, const char *name, const char *value)
3804 if (value)
3805 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3806 else if (name)
3807 RegDeleteValueA(hkey, name);
3810 static void update_font_association_info(UINT current_ansi_codepage)
3812 static const char *font_assoc_reg_key = "System\\CurrentControlSet\\Control\\FontAssoc";
3813 static const char *assoc_charset_subkey = "Associated Charset";
3815 if (is_dbcs_ansi_cp(current_ansi_codepage))
3817 HKEY hkey;
3818 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, font_assoc_reg_key, &hkey) == ERROR_SUCCESS)
3820 HKEY hsubkey;
3821 if (RegCreateKeyA(hkey, assoc_charset_subkey, &hsubkey) == ERROR_SUCCESS)
3823 switch (current_ansi_codepage)
3825 case 932:
3826 set_value_key(hsubkey, "ANSI(00)", "NO");
3827 set_value_key(hsubkey, "OEM(FF)", "NO");
3828 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3829 break;
3830 case 936:
3831 case 949:
3832 case 950:
3833 set_value_key(hsubkey, "ANSI(00)", "YES");
3834 set_value_key(hsubkey, "OEM(FF)", "YES");
3835 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3836 break;
3838 RegCloseKey(hsubkey);
3841 /* TODO: Associated DefaultFonts */
3843 RegCloseKey(hkey);
3846 else
3847 RegDeleteTreeA(HKEY_LOCAL_MACHINE, font_assoc_reg_key);
3850 static void set_multi_value_key(HKEY hkey, const WCHAR *name, const WCHAR *value, DWORD len)
3852 if (value)
3853 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (const BYTE *)value, len);
3854 else if (name)
3855 RegDeleteValueW(hkey, name);
3858 static void update_font_system_link_info(UINT current_ansi_codepage)
3860 static const WCHAR system_link_simplified_chinese[] =
3861 {'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3862 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3863 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3864 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3865 '\0'};
3866 static const WCHAR system_link_traditional_chinese[] =
3867 {'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3868 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3869 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3870 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3871 '\0'};
3872 static const WCHAR system_link_japanese[] =
3873 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3874 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3875 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3876 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3877 '\0'};
3878 static const WCHAR system_link_korean[] =
3879 {'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3880 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3881 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3882 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3883 '\0'};
3884 static const WCHAR system_link_non_cjk[] =
3885 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3886 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3887 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3888 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3889 '\0'};
3890 HKEY hkey;
3892 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
3894 const WCHAR *link;
3895 DWORD len;
3897 switch (current_ansi_codepage)
3899 case 932:
3900 link = system_link_japanese;
3901 len = sizeof(system_link_japanese);
3902 break;
3903 case 936:
3904 link = system_link_simplified_chinese;
3905 len = sizeof(system_link_simplified_chinese);
3906 break;
3907 case 949:
3908 link = system_link_korean;
3909 len = sizeof(system_link_korean);
3910 break;
3911 case 950:
3912 link = system_link_traditional_chinese;
3913 len = sizeof(system_link_traditional_chinese);
3914 break;
3915 default:
3916 link = system_link_non_cjk;
3917 len = sizeof(system_link_non_cjk);
3919 set_multi_value_key(hkey, Lucida_Sans_Unicode, link, len);
3920 set_multi_value_key(hkey, Microsoft_Sans_Serif, link, len);
3921 set_multi_value_key(hkey, Tahoma, link, len);
3922 RegCloseKey(hkey);
3926 static void update_font_info(void)
3928 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3929 char buf[40], cpbuf[40];
3930 DWORD len, type;
3931 HKEY hkey = 0;
3932 UINT i, ansi_cp = 0, oem_cp = 0;
3933 DWORD screen_dpi = 96, font_dpi = 0;
3934 BOOL done = FALSE;
3936 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3937 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3938 &hkey) == ERROR_SUCCESS)
3940 reg_load_dword(hkey, logpixels, &screen_dpi);
3941 RegCloseKey(hkey);
3944 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3945 return;
3947 reg_load_dword(hkey, logpixels, &font_dpi);
3949 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3950 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3951 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3952 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3953 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3955 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3956 if (is_dbcs_ansi_cp(ansi_cp))
3957 use_default_fallback = TRUE;
3959 buf[0] = 0;
3960 len = sizeof(buf);
3961 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3963 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3965 RegCloseKey(hkey);
3966 return;
3968 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3969 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3971 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3972 ansi_cp, oem_cp, screen_dpi);
3974 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3975 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3976 RegCloseKey(hkey);
3978 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3980 HKEY hkey;
3982 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3983 nls_update_font_list[i].oem_cp == oem_cp)
3985 hkey = create_config_fonts_registry_key();
3986 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3987 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3988 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3989 RegCloseKey(hkey);
3991 hkey = create_fonts_NT_registry_key();
3992 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3993 RegCloseKey(hkey);
3995 hkey = create_fonts_9x_registry_key();
3996 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3997 RegCloseKey(hkey);
3999 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
4001 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
4002 strlen(nls_update_font_list[i].shelldlg)+1);
4003 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
4004 strlen(nls_update_font_list[i].tmsrmn)+1);
4006 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
4007 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
4008 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
4009 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
4010 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
4011 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
4012 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
4013 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
4015 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
4016 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
4017 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
4019 RegCloseKey(hkey);
4021 done = TRUE;
4023 else
4025 /* Delete the FontSubstitutes from other locales */
4026 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
4028 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
4029 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
4030 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
4031 RegCloseKey(hkey);
4035 if (!done)
4036 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
4038 /* update locale dependent font association info and font system link info in registry.
4039 update only when codepages changed, not logpixels. */
4040 if (strcmp(buf, cpbuf) != 0)
4042 update_font_association_info(ansi_cp);
4043 update_font_system_link_info(ansi_cp);
4047 static BOOL init_freetype(void)
4049 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
4050 if(!ft_handle) {
4051 WINE_MESSAGE(
4052 "Wine cannot find the FreeType font library. To enable Wine to\n"
4053 "use TrueType fonts please install a version of FreeType greater than\n"
4054 "or equal to 2.0.5.\n"
4055 "http://www.freetype.org\n");
4056 return FALSE;
4059 #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;}
4061 LOAD_FUNCPTR(FT_Done_Face)
4062 LOAD_FUNCPTR(FT_Get_Char_Index)
4063 LOAD_FUNCPTR(FT_Get_First_Char)
4064 LOAD_FUNCPTR(FT_Get_Next_Char)
4065 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
4066 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
4067 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
4068 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
4069 LOAD_FUNCPTR(FT_Init_FreeType)
4070 LOAD_FUNCPTR(FT_Library_Version)
4071 LOAD_FUNCPTR(FT_Load_Glyph)
4072 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
4073 LOAD_FUNCPTR(FT_Matrix_Multiply)
4074 #ifndef FT_MULFIX_INLINED
4075 LOAD_FUNCPTR(FT_MulFix)
4076 #endif
4077 LOAD_FUNCPTR(FT_New_Face)
4078 LOAD_FUNCPTR(FT_New_Memory_Face)
4079 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
4080 LOAD_FUNCPTR(FT_Outline_Get_CBox)
4081 LOAD_FUNCPTR(FT_Outline_Transform)
4082 LOAD_FUNCPTR(FT_Outline_Translate)
4083 LOAD_FUNCPTR(FT_Render_Glyph)
4084 LOAD_FUNCPTR(FT_Select_Charmap)
4085 LOAD_FUNCPTR(FT_Set_Charmap)
4086 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
4087 LOAD_FUNCPTR(FT_Vector_Transform)
4088 LOAD_FUNCPTR(FT_Vector_Unit)
4089 #undef LOAD_FUNCPTR
4090 /* Don't warn if these ones are missing */
4091 pFT_Outline_Embolden = wine_dlsym(ft_handle, "FT_Outline_Embolden", NULL, 0);
4092 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
4093 #ifdef FT_LCD_FILTER_H
4094 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
4095 #endif
4097 if(pFT_Init_FreeType(&library) != 0) {
4098 ERR("Can't init FreeType library\n");
4099 wine_dlclose(ft_handle, NULL, 0);
4100 ft_handle = NULL;
4101 return FALSE;
4103 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
4105 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
4106 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
4107 ((FT_Version.minor << 8) & 0x00ff00) |
4108 ((FT_Version.patch ) & 0x0000ff);
4110 font_driver = &freetype_funcs;
4111 return TRUE;
4113 sym_not_found:
4114 WINE_MESSAGE(
4115 "Wine cannot find certain functions that it needs inside the FreeType\n"
4116 "font library. To enable Wine to use TrueType fonts please upgrade\n"
4117 "FreeType to at least version 2.1.4.\n"
4118 "http://www.freetype.org\n");
4119 wine_dlclose(ft_handle, NULL, 0);
4120 ft_handle = NULL;
4121 return FALSE;
4124 static void init_font_list(void)
4126 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
4127 static const WCHAR pathW[] = {'P','a','t','h',0};
4128 HKEY hkey;
4129 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
4130 WCHAR windowsdir[MAX_PATH];
4131 char *unixname;
4132 const char *data_dir;
4134 delete_external_font_keys();
4136 /* load the system bitmap fonts */
4137 load_system_fonts();
4139 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
4140 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
4141 strcatW(windowsdir, fontsW);
4142 if((unixname = wine_get_unix_file_name(windowsdir)))
4144 ReadFontDir(unixname, FALSE);
4145 HeapFree(GetProcessHeap(), 0, unixname);
4148 /* load the system truetype fonts */
4149 data_dir = wine_get_data_dir();
4150 if (!data_dir) data_dir = wine_get_build_dir();
4151 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
4153 strcpy(unixname, data_dir);
4154 strcat(unixname, "/fonts/");
4155 ReadFontDir(unixname, TRUE);
4156 HeapFree(GetProcessHeap(), 0, unixname);
4159 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
4160 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
4161 full path as the entry. Also look for any .fon fonts, since ReadFontDir
4162 will skip these. */
4163 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
4164 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
4165 &hkey) == ERROR_SUCCESS)
4167 LPWSTR data, valueW;
4168 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
4169 &valuelen, &datalen, NULL, NULL);
4171 valuelen++; /* returned value doesn't include room for '\0' */
4172 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
4173 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
4174 if (valueW && data)
4176 dlen = datalen * sizeof(WCHAR);
4177 vlen = valuelen;
4178 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
4179 &dlen) == ERROR_SUCCESS)
4181 if(data[0] && (data[1] == ':'))
4183 if((unixname = wine_get_unix_file_name(data)))
4185 AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
4186 HeapFree(GetProcessHeap(), 0, unixname);
4189 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
4191 WCHAR pathW[MAX_PATH];
4192 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
4193 BOOL added = FALSE;
4195 sprintfW(pathW, fmtW, windowsdir, data);
4196 if((unixname = wine_get_unix_file_name(pathW)))
4198 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
4199 HeapFree(GetProcessHeap(), 0, unixname);
4201 if (!added)
4202 load_font_from_data_dir(data);
4204 /* reset dlen and vlen */
4205 dlen = datalen;
4206 vlen = valuelen;
4209 HeapFree(GetProcessHeap(), 0, data);
4210 HeapFree(GetProcessHeap(), 0, valueW);
4211 RegCloseKey(hkey);
4214 #ifdef SONAME_LIBFONTCONFIG
4215 load_fontconfig_fonts();
4216 #elif defined(HAVE_CARBON_CARBON_H)
4217 load_mac_fonts();
4218 #endif
4220 /* then look in any directories that we've specified in the config file */
4221 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
4222 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
4224 DWORD len;
4225 LPWSTR valueW;
4226 LPSTR valueA, ptr;
4228 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
4230 len += sizeof(WCHAR);
4231 valueW = HeapAlloc( GetProcessHeap(), 0, len );
4232 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
4234 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
4235 valueA = HeapAlloc( GetProcessHeap(), 0, len );
4236 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
4237 TRACE( "got font path %s\n", debugstr_a(valueA) );
4238 ptr = valueA;
4239 while (ptr)
4241 const char* home;
4242 LPSTR next = strchr( ptr, ':' );
4243 if (next) *next++ = 0;
4244 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
4245 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
4247 strcpy( unixname, home );
4248 strcat( unixname, ptr + 1 );
4249 ReadFontDir( unixname, TRUE );
4250 HeapFree( GetProcessHeap(), 0, unixname );
4252 else
4253 ReadFontDir( ptr, TRUE );
4254 ptr = next;
4256 HeapFree( GetProcessHeap(), 0, valueA );
4258 HeapFree( GetProcessHeap(), 0, valueW );
4260 RegCloseKey(hkey);
4264 static BOOL move_to_front(const WCHAR *name)
4266 Family *family, *cursor2;
4267 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
4269 if(!strcmpiW(family->FamilyName, name))
4271 list_remove(&family->entry);
4272 list_add_head(&font_list, &family->entry);
4273 return TRUE;
4276 return FALSE;
4279 static BOOL set_default(const WCHAR **name_list)
4281 while (*name_list)
4283 if (move_to_front(*name_list)) return TRUE;
4284 name_list++;
4287 return FALSE;
4290 static void reorder_font_list(void)
4292 set_default( default_serif_list );
4293 set_default( default_fixed_list );
4294 set_default( default_sans_list );
4297 /*************************************************************
4298 * WineEngInit
4300 * Initialize FreeType library and create a list of available faces
4302 BOOL WineEngInit(void)
4304 HKEY hkey;
4305 DWORD disposition;
4306 HANDLE font_mutex;
4308 /* update locale dependent font info in registry */
4309 update_font_info();
4311 if(!init_freetype()) return FALSE;
4313 #ifdef SONAME_LIBFONTCONFIG
4314 init_fontconfig();
4315 #endif
4317 if (!RegOpenKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, KEY_READ, &hkey))
4319 static const WCHAR antialias_fake_bold_or_italic[] = { 'A','n','t','i','a','l','i','a','s','F','a','k','e',
4320 'B','o','l','d','O','r','I','t','a','l','i','c',0 };
4321 static const WCHAR true_options[] = { 'y','Y','t','T','1',0 };
4322 DWORD type, size;
4323 WCHAR buffer[20];
4325 size = sizeof(buffer);
4326 if (!RegQueryValueExW(hkey, antialias_fake_bold_or_italic, NULL, &type, (BYTE*)buffer, &size) &&
4327 type == REG_SZ && size >= 1)
4329 antialias_fakes = (strchrW(true_options, buffer[0]) != NULL);
4331 RegCloseKey(hkey);
4334 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
4336 ERR("Failed to create font mutex\n");
4337 return FALSE;
4339 WaitForSingleObject(font_mutex, INFINITE);
4341 create_font_cache_key(&hkey_font_cache, &disposition);
4343 if(disposition == REG_CREATED_NEW_KEY)
4344 init_font_list();
4345 else
4346 load_font_list_from_cache(hkey_font_cache);
4348 reorder_font_list();
4350 DumpFontList();
4351 LoadSubstList();
4352 DumpSubstList();
4353 LoadReplaceList();
4355 if(disposition == REG_CREATED_NEW_KEY)
4356 update_reg_entries();
4358 init_system_links();
4360 ReleaseMutex(font_mutex);
4361 return TRUE;
4364 /* Some fonts have large usWinDescent values, as a result of storing signed short
4365 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
4366 some font generation tools. */
4367 static inline USHORT get_fixed_windescent(USHORT windescent)
4369 return abs((SHORT)windescent);
4372 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
4374 TT_OS2 *pOS2;
4375 TT_HoriHeader *pHori;
4377 LONG ppem;
4378 const LONG MAX_PPEM = (1 << 16) - 1;
4380 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4381 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4383 if(height == 0) height = 16;
4385 /* Calc. height of EM square:
4387 * For +ve lfHeight we have
4388 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
4389 * Re-arranging gives:
4390 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4392 * For -ve lfHeight we have
4393 * |lfHeight| = ppem
4394 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4395 * with il = winAscent + winDescent - units_per_em]
4399 if(height > 0) {
4400 USHORT windescent = get_fixed_windescent(pOS2->usWinDescent);
4401 if(pOS2->usWinAscent + windescent == 0)
4402 ppem = MulDiv(ft_face->units_per_EM, height,
4403 pHori->Ascender - pHori->Descender);
4404 else
4405 ppem = MulDiv(ft_face->units_per_EM, height,
4406 pOS2->usWinAscent + windescent);
4407 if(ppem > MAX_PPEM) {
4408 WARN("Ignoring too large height %d, ppem %d\n", height, ppem);
4409 ppem = 1;
4412 else if(height >= -MAX_PPEM)
4413 ppem = -height;
4414 else {
4415 WARN("Ignoring too large height %d\n", height);
4416 ppem = 1;
4419 return ppem;
4422 static struct font_mapping *map_font_file( const char *name )
4424 struct font_mapping *mapping;
4425 struct stat st;
4426 int fd;
4428 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
4429 if (fstat( fd, &st ) == -1) goto error;
4431 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
4433 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
4435 mapping->refcount++;
4436 close( fd );
4437 return mapping;
4440 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
4441 goto error;
4443 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
4444 close( fd );
4446 if (mapping->data == MAP_FAILED)
4448 HeapFree( GetProcessHeap(), 0, mapping );
4449 return NULL;
4451 mapping->refcount = 1;
4452 mapping->dev = st.st_dev;
4453 mapping->ino = st.st_ino;
4454 mapping->size = st.st_size;
4455 list_add_tail( &mappings_list, &mapping->entry );
4456 return mapping;
4458 error:
4459 close( fd );
4460 return NULL;
4463 static void unmap_font_file( struct font_mapping *mapping )
4465 if (!--mapping->refcount)
4467 list_remove( &mapping->entry );
4468 munmap( mapping->data, mapping->size );
4469 HeapFree( GetProcessHeap(), 0, mapping );
4473 static LONG load_VDMX(GdiFont*, LONG);
4475 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
4477 FT_Error err;
4478 FT_Face ft_face;
4479 void *data_ptr;
4480 DWORD data_size;
4482 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
4484 if (face->file)
4486 char *filename = strWtoA( CP_UNIXCP, face->file );
4487 font->mapping = map_font_file( filename );
4488 HeapFree( GetProcessHeap(), 0, filename );
4489 if (!font->mapping)
4491 WARN("failed to map %s\n", debugstr_w(face->file));
4492 return 0;
4494 data_ptr = font->mapping->data;
4495 data_size = font->mapping->size;
4497 else
4499 data_ptr = face->font_data_ptr;
4500 data_size = face->font_data_size;
4503 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
4504 if(err) {
4505 ERR("FT_New_Face rets %d\n", err);
4506 return 0;
4509 /* set it here, as load_VDMX needs it */
4510 font->ft_face = ft_face;
4512 if(FT_IS_SCALABLE(ft_face)) {
4513 /* load the VDMX table if we have one */
4514 font->ppem = load_VDMX(font, height);
4515 if(font->ppem == 0)
4516 font->ppem = calc_ppem_for_height(ft_face, height);
4517 TRACE("height %d => ppem %d\n", height, font->ppem);
4519 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
4520 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
4521 } else {
4522 font->ppem = height;
4523 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
4524 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
4526 return ft_face;
4530 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
4532 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4533 a single face with the requested charset. The idea is to check if
4534 the selected font supports the current ANSI codepage, if it does
4535 return the corresponding charset, else return the first charset */
4537 CHARSETINFO csi;
4538 int acp = GetACP(), i;
4539 DWORD fs0;
4541 *cp = acp;
4542 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
4544 const SYSTEM_LINKS *font_link;
4546 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4547 return csi.ciCharset;
4549 font_link = find_font_link(family_name);
4550 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4551 return csi.ciCharset;
4554 for(i = 0; i < 32; i++) {
4555 fs0 = 1L << i;
4556 if(face->fs.fsCsb[0] & fs0) {
4557 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4558 *cp = csi.ciACP;
4559 return csi.ciCharset;
4561 else
4562 FIXME("TCI failing on %x\n", fs0);
4566 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4567 face->fs.fsCsb[0], debugstr_w(face->file));
4568 *cp = acp;
4569 return DEFAULT_CHARSET;
4572 static GdiFont *alloc_font(void)
4574 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4575 ret->refcount = 1;
4576 ret->gmsize = 1;
4577 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4578 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4579 ret->potm = NULL;
4580 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4581 ret->total_kern_pairs = (DWORD)-1;
4582 ret->kern_pairs = NULL;
4583 ret->instance_id = alloc_font_handle(ret);
4584 list_init(&ret->child_fonts);
4585 return ret;
4588 static void free_font(GdiFont *font)
4590 CHILD_FONT *child, *child_next;
4591 DWORD i;
4593 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
4595 list_remove(&child->entry);
4596 if(child->font)
4597 free_font(child->font);
4598 release_face( child->face );
4599 HeapFree(GetProcessHeap(), 0, child);
4602 HeapFree(GetProcessHeap(), 0, font->fileinfo);
4603 free_font_handle(font->instance_id);
4604 if (font->ft_face) pFT_Done_Face(font->ft_face);
4605 if (font->mapping) unmap_font_file( font->mapping );
4606 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4607 HeapFree(GetProcessHeap(), 0, font->potm);
4608 HeapFree(GetProcessHeap(), 0, font->name);
4609 for (i = 0; i < font->gmsize; i++)
4610 HeapFree(GetProcessHeap(),0,font->gm[i]);
4611 HeapFree(GetProcessHeap(), 0, font->gm);
4612 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4613 HeapFree(GetProcessHeap(), 0, font);
4617 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4619 FT_Face ft_face = font->ft_face;
4620 FT_ULong len;
4621 FT_Error err;
4623 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4625 if(!buf)
4626 len = 0;
4627 else
4628 len = cbData;
4630 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4632 /* make sure value of len is the value freetype says it needs */
4633 if (buf && len)
4635 FT_ULong needed = 0;
4636 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4637 if( !err && needed < len) len = needed;
4639 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4640 if (err)
4642 TRACE("Can't find table %c%c%c%c\n",
4643 /* bytes were reversed */
4644 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4645 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4646 return GDI_ERROR;
4648 return len;
4651 /*************************************************************
4652 * load_VDMX
4654 * load the vdmx entry for the specified height
4657 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4658 ( ( (FT_ULong)_x4 << 24 ) | \
4659 ( (FT_ULong)_x3 << 16 ) | \
4660 ( (FT_ULong)_x2 << 8 ) | \
4661 (FT_ULong)_x1 )
4663 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4665 typedef struct {
4666 WORD version;
4667 WORD numRecs;
4668 WORD numRatios;
4669 } VDMX_Header;
4671 typedef struct {
4672 BYTE bCharSet;
4673 BYTE xRatio;
4674 BYTE yStartRatio;
4675 BYTE yEndRatio;
4676 } Ratios;
4678 typedef struct {
4679 WORD recs;
4680 BYTE startsz;
4681 BYTE endsz;
4682 } VDMX_group;
4684 typedef struct {
4685 WORD yPelHeight;
4686 WORD yMax;
4687 WORD yMin;
4688 } VDMX_vTable;
4690 static LONG load_VDMX(GdiFont *font, LONG height)
4692 VDMX_Header hdr;
4693 VDMX_group group;
4694 BYTE devXRatio, devYRatio;
4695 USHORT numRecs, numRatios;
4696 DWORD result, offset = -1;
4697 LONG ppem = 0;
4698 int i;
4700 result = get_font_data(font, MS_VDMX_TAG, 0, &hdr, sizeof(hdr));
4702 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4703 return ppem;
4705 /* FIXME: need the real device aspect ratio */
4706 devXRatio = 1;
4707 devYRatio = 1;
4709 numRecs = GET_BE_WORD(hdr.numRecs);
4710 numRatios = GET_BE_WORD(hdr.numRatios);
4712 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr.version), numRecs, numRatios);
4713 for(i = 0; i < numRatios; i++) {
4714 Ratios ratio;
4716 offset = sizeof(hdr) + (i * sizeof(Ratios));
4717 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4718 offset = -1;
4720 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4722 if (!ratio.bCharSet) continue;
4724 if((ratio.xRatio == 0 &&
4725 ratio.yStartRatio == 0 &&
4726 ratio.yEndRatio == 0) ||
4727 (devXRatio == ratio.xRatio &&
4728 devYRatio >= ratio.yStartRatio &&
4729 devYRatio <= ratio.yEndRatio))
4731 WORD group_offset;
4733 offset = sizeof(hdr) + numRatios * sizeof(ratio) + i * sizeof(group_offset);
4734 get_font_data(font, MS_VDMX_TAG, offset, &group_offset, sizeof(group_offset));
4735 offset = GET_BE_WORD(group_offset);
4736 break;
4740 if(offset == -1) return 0;
4742 if(get_font_data(font, MS_VDMX_TAG, offset, &group, sizeof(group)) != GDI_ERROR) {
4743 USHORT recs;
4744 BYTE startsz, endsz;
4745 WORD *vTable;
4747 recs = GET_BE_WORD(group.recs);
4748 startsz = group.startsz;
4749 endsz = group.endsz;
4751 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4753 vTable = HeapAlloc(GetProcessHeap(), 0, recs * sizeof(VDMX_vTable));
4754 result = get_font_data(font, MS_VDMX_TAG, offset + sizeof(group), vTable, recs * sizeof(VDMX_vTable));
4755 if(result == GDI_ERROR) {
4756 FIXME("Failed to retrieve vTable\n");
4757 goto end;
4760 if(height > 0) {
4761 for(i = 0; i < recs; i++) {
4762 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4763 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4764 ppem = GET_BE_WORD(vTable[i * 3]);
4766 if(yMax + -yMin == height) {
4767 font->yMax = yMax;
4768 font->yMin = yMin;
4769 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4770 break;
4772 if(yMax + -yMin > height) {
4773 if(--i < 0) {
4774 ppem = 0;
4775 goto end; /* failed */
4777 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4778 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4779 ppem = GET_BE_WORD(vTable[i * 3]);
4780 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4781 break;
4784 if(!font->yMax) {
4785 ppem = 0;
4786 TRACE("ppem not found for height %d\n", height);
4788 } else {
4789 ppem = -height;
4790 if(ppem < startsz || ppem > endsz)
4792 ppem = 0;
4793 goto end;
4796 for(i = 0; i < recs; i++) {
4797 USHORT yPelHeight;
4798 yPelHeight = GET_BE_WORD(vTable[i * 3]);
4800 if(yPelHeight > ppem)
4802 ppem = 0;
4803 break; /* failed */
4806 if(yPelHeight == ppem) {
4807 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4808 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4809 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
4810 break;
4814 end:
4815 HeapFree(GetProcessHeap(), 0, vTable);
4818 return ppem;
4821 static void dump_gdi_font_list(void)
4823 GdiFont *font;
4825 TRACE("---------- Font Cache ----------\n");
4826 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct tagGdiFont, entry )
4827 TRACE("font=%p ref=%u %s %d\n", font, font->refcount,
4828 debugstr_w(font->font_desc.lf.lfFaceName), font->font_desc.lf.lfHeight);
4831 static void grab_font( GdiFont *font )
4833 if (!font->refcount++)
4835 list_remove( &font->unused_entry );
4836 unused_font_count--;
4840 static void release_font( GdiFont *font )
4842 if (!font) return;
4843 if (!--font->refcount)
4845 TRACE( "font %p\n", font );
4847 /* add it to the unused list */
4848 list_add_head( &unused_gdi_font_list, &font->unused_entry );
4849 if (unused_font_count > UNUSED_CACHE_SIZE)
4851 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct tagGdiFont, unused_entry );
4852 TRACE( "freeing %p\n", font );
4853 list_remove( &font->entry );
4854 list_remove( &font->unused_entry );
4855 free_font( font );
4857 else unused_font_count++;
4859 if (TRACE_ON(font)) dump_gdi_font_list();
4863 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4865 if(font->font_desc.hash != fd->hash) return TRUE;
4866 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4867 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4868 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4869 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4872 static void calc_hash(FONT_DESC *pfd)
4874 DWORD hash = 0, *ptr, two_chars;
4875 WORD *pwc;
4876 unsigned int i;
4878 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4879 hash ^= *ptr;
4880 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4881 hash ^= *ptr;
4882 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4883 two_chars = *ptr;
4884 pwc = (WCHAR *)&two_chars;
4885 if(!*pwc) break;
4886 *pwc = toupperW(*pwc);
4887 pwc++;
4888 *pwc = toupperW(*pwc);
4889 hash ^= two_chars;
4890 if(!*pwc) break;
4892 hash ^= !pfd->can_use_bitmap;
4893 pfd->hash = hash;
4896 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4898 GdiFont *ret;
4899 FONT_DESC fd;
4901 fd.lf = *plf;
4902 fd.matrix = *pmat;
4903 fd.can_use_bitmap = can_use_bitmap;
4904 calc_hash(&fd);
4906 /* try the in-use list */
4907 LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
4909 if(fontcmp(ret, &fd)) continue;
4910 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4911 list_remove( &ret->entry );
4912 list_add_head( &gdi_font_list, &ret->entry );
4913 grab_font( ret );
4914 return ret;
4916 return NULL;
4919 static void add_to_cache(GdiFont *font)
4921 static DWORD cache_num = 1;
4923 font->cache_num = cache_num++;
4924 list_add_head(&gdi_font_list, &font->entry);
4925 TRACE( "font %p\n", font );
4928 /*************************************************************
4929 * create_child_font_list
4931 static BOOL create_child_font_list(GdiFont *font)
4933 BOOL ret = FALSE;
4934 SYSTEM_LINKS *font_link;
4935 CHILD_FONT *font_link_entry, *new_child;
4936 FontSubst *psub;
4937 WCHAR* font_name;
4939 psub = get_font_subst(&font_subst_list, font->name, -1);
4940 font_name = psub ? psub->to.name : font->name;
4941 font_link = find_font_link(font_name);
4942 if (font_link != NULL)
4944 TRACE("found entry in system list\n");
4945 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4947 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4948 new_child->face = font_link_entry->face;
4949 new_child->font = NULL;
4950 new_child->face->refcount++;
4951 list_add_tail(&font->child_fonts, &new_child->entry);
4952 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4954 ret = TRUE;
4957 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4958 * Sans Serif. This is how asian windows get default fallbacks for fonts
4960 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4961 font->charset != OEM_CHARSET &&
4962 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4964 font_link = find_font_link(szDefaultFallbackLink);
4965 if (font_link != NULL)
4967 TRACE("found entry in default fallback list\n");
4968 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4970 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4971 new_child->face = font_link_entry->face;
4972 new_child->font = NULL;
4973 new_child->face->refcount++;
4974 list_add_tail(&font->child_fonts, &new_child->entry);
4975 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4977 ret = TRUE;
4981 return ret;
4984 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4986 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4988 if (pFT_Set_Charmap)
4990 FT_Int i;
4991 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4993 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4995 for (i = 0; i < ft_face->num_charmaps; i++)
4997 if (ft_face->charmaps[i]->encoding == encoding)
4999 TRACE("found cmap with platform_id %u, encoding_id %u\n",
5000 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
5002 switch (ft_face->charmaps[i]->platform_id)
5004 default:
5005 cmap_def = ft_face->charmaps[i];
5006 break;
5007 case 0: /* Apple Unicode */
5008 cmap0 = ft_face->charmaps[i];
5009 break;
5010 case 1: /* Macintosh */
5011 cmap1 = ft_face->charmaps[i];
5012 break;
5013 case 2: /* ISO */
5014 cmap2 = ft_face->charmaps[i];
5015 break;
5016 case 3: /* Microsoft */
5017 cmap3 = ft_face->charmaps[i];
5018 break;
5022 if (cmap3) /* prefer Microsoft cmap table */
5023 ft_err = pFT_Set_Charmap(ft_face, cmap3);
5024 else if (cmap1)
5025 ft_err = pFT_Set_Charmap(ft_face, cmap1);
5026 else if (cmap2)
5027 ft_err = pFT_Set_Charmap(ft_face, cmap2);
5028 else if (cmap0)
5029 ft_err = pFT_Set_Charmap(ft_face, cmap0);
5030 else if (cmap_def)
5031 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
5033 return ft_err == FT_Err_Ok;
5036 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
5040 /*************************************************************
5041 * freetype_CreateDC
5043 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
5044 LPCWSTR output, const DEVMODEW *devmode )
5046 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
5048 if (!physdev) return FALSE;
5049 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
5050 return TRUE;
5054 /*************************************************************
5055 * freetype_DeleteDC
5057 static BOOL freetype_DeleteDC( PHYSDEV dev )
5059 struct freetype_physdev *physdev = get_freetype_dev( dev );
5060 release_font( physdev->font );
5061 HeapFree( GetProcessHeap(), 0, physdev );
5062 return TRUE;
5065 static FT_Encoding pick_charmap( FT_Face face, int charset )
5067 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
5068 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
5069 const FT_Encoding *encs = regular_order;
5071 if (charset == SYMBOL_CHARSET) encs = symbol_order;
5073 while (*encs != 0)
5075 if (select_charmap( face, *encs )) break;
5076 encs++;
5078 return *encs;
5081 #define GASP_GRIDFIT 0x01
5082 #define GASP_DOGRAY 0x02
5083 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
5085 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
5087 DWORD size;
5088 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
5089 WORD *alloced = NULL, *ptr = buf;
5090 WORD num_recs, version;
5091 BOOL ret = FALSE;
5093 *flags = 0;
5094 size = get_font_data( font, GASP_TAG, 0, NULL, 0 );
5095 if (size == GDI_ERROR) return FALSE;
5096 if (size < 4 * sizeof(WORD)) return FALSE;
5097 if (size > sizeof(buf))
5099 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
5100 if (!ptr) return FALSE;
5103 get_font_data( font, GASP_TAG, 0, ptr, size );
5105 version = GET_BE_WORD( *ptr++ );
5106 num_recs = GET_BE_WORD( *ptr++ );
5108 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
5110 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
5111 goto done;
5114 while (num_recs--)
5116 *flags = GET_BE_WORD( *(ptr + 1) );
5117 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
5118 ptr += 2;
5120 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
5121 ret = TRUE;
5123 done:
5124 HeapFree( GetProcessHeap(), 0, alloced );
5125 return ret;
5128 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5130 const GSUB_ScriptList *script;
5131 const GSUB_Script *deflt = NULL;
5132 int i;
5133 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5135 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5136 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5138 const GSUB_Script *scr;
5139 int offset;
5141 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5142 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5144 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5145 return scr;
5146 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5147 deflt = scr;
5149 return deflt;
5152 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5154 int i;
5155 int offset;
5156 const GSUB_LangSys *Lang;
5158 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5160 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5162 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5163 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5165 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5166 return Lang;
5168 offset = GET_BE_WORD(script->DefaultLangSys);
5169 if (offset)
5171 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5172 return Lang;
5174 return NULL;
5177 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5179 int i;
5180 const GSUB_FeatureList *feature;
5181 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5183 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5184 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5186 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5187 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5189 const GSUB_Feature *feat;
5190 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5191 return feat;
5194 return NULL;
5197 static const char* get_opentype_script(const GdiFont *font)
5200 * I am not sure if this is the correct way to generate our script tag
5203 switch (font->charset)
5205 case ANSI_CHARSET: return "latn";
5206 case BALTIC_CHARSET: return "latn"; /* ?? */
5207 case CHINESEBIG5_CHARSET: return "hani";
5208 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5209 case GB2312_CHARSET: return "hani";
5210 case GREEK_CHARSET: return "grek";
5211 case HANGUL_CHARSET: return "hang";
5212 case RUSSIAN_CHARSET: return "cyrl";
5213 case SHIFTJIS_CHARSET: return "kana";
5214 case TURKISH_CHARSET: return "latn"; /* ?? */
5215 case VIETNAMESE_CHARSET: return "latn";
5216 case JOHAB_CHARSET: return "latn"; /* ?? */
5217 case ARABIC_CHARSET: return "arab";
5218 case HEBREW_CHARSET: return "hebr";
5219 case THAI_CHARSET: return "thai";
5220 default: return "latn";
5224 static const VOID * get_GSUB_vert_feature(const GdiFont *font)
5226 const GSUB_Header *header;
5227 const GSUB_Script *script;
5228 const GSUB_LangSys *language;
5229 const GSUB_Feature *feature;
5231 if (!font->GSUB_Table)
5232 return NULL;
5234 header = font->GSUB_Table;
5236 script = GSUB_get_script_table(header, get_opentype_script(font));
5237 if (!script)
5239 TRACE("Script not found\n");
5240 return NULL;
5242 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5243 if (!language)
5245 TRACE("Language not found\n");
5246 return NULL;
5248 feature = GSUB_get_feature(header, language, "vrt2");
5249 if (!feature)
5250 feature = GSUB_get_feature(header, language, "vert");
5251 if (!feature)
5253 TRACE("vrt2/vert feature not found\n");
5254 return NULL;
5256 return feature;
5259 static void fill_fileinfo_from_face( GdiFont *font, Face *face )
5261 WIN32_FILE_ATTRIBUTE_DATA info;
5262 int len;
5264 if (!face->file)
5266 font->fileinfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*font->fileinfo));
5267 return;
5270 len = strlenW(face->file);
5271 font->fileinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*font->fileinfo) + len * sizeof(WCHAR));
5272 if (GetFileAttributesExW(face->file, GetFileExInfoStandard, &info))
5274 font->fileinfo->writetime = info.ftLastWriteTime;
5275 font->fileinfo->size.QuadPart = (LONGLONG)info.nFileSizeHigh << 32 | info.nFileSizeLow;
5276 strcpyW(font->fileinfo->path, face->file);
5278 else
5279 memset(font->fileinfo, 0, sizeof(*font->fileinfo) + len * sizeof(WCHAR));
5282 /*************************************************************
5283 * freetype_SelectFont
5285 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
5287 struct freetype_physdev *physdev = get_freetype_dev( dev );
5288 GdiFont *ret;
5289 Face *face, *best, *best_bitmap;
5290 Family *family, *last_resort_family;
5291 const struct list *face_list;
5292 INT height, width = 0;
5293 unsigned int score = 0, new_score;
5294 signed int diff = 0, newdiff;
5295 BOOL bd, it, can_use_bitmap, want_vertical;
5296 LOGFONTW lf;
5297 CHARSETINFO csi;
5298 FMAT2 dcmat;
5299 FontSubst *psub = NULL;
5300 DC *dc = get_dc_ptr( dev->hdc );
5301 const SYSTEM_LINKS *font_link;
5303 if (!hfont) /* notification that the font has been changed by another driver */
5305 release_font( physdev->font );
5306 physdev->font = NULL;
5307 release_dc_ptr( dc );
5308 return 0;
5311 GetObjectW( hfont, sizeof(lf), &lf );
5312 lf.lfWidth = abs(lf.lfWidth);
5314 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
5316 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
5317 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
5318 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
5319 lf.lfEscapement);
5321 if(dc->GraphicsMode == GM_ADVANCED)
5323 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
5324 /* Try to avoid not necessary glyph transformations */
5325 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
5327 lf.lfHeight *= fabs(dcmat.eM11);
5328 lf.lfWidth *= fabs(dcmat.eM11);
5329 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
5332 else
5334 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
5335 font scaling abilities. */
5336 dcmat.eM11 = dcmat.eM22 = 1.0;
5337 dcmat.eM21 = dcmat.eM12 = 0;
5338 lf.lfOrientation = lf.lfEscapement;
5339 if (dc->vport2WorldValid)
5341 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
5342 lf.lfOrientation = -lf.lfOrientation;
5343 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
5344 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
5348 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
5349 dcmat.eM21, dcmat.eM22);
5351 GDI_CheckNotLock();
5352 EnterCriticalSection( &freetype_cs );
5354 /* check the cache first */
5355 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5356 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
5357 goto done;
5360 TRACE("not in cache\n");
5361 ret = alloc_font();
5363 ret->font_desc.matrix = dcmat;
5364 ret->font_desc.lf = lf;
5365 ret->font_desc.can_use_bitmap = can_use_bitmap;
5366 calc_hash(&ret->font_desc);
5368 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
5369 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
5370 original value lfCharSet. Note this is a special case for
5371 Symbol and doesn't happen at least for "Wingdings*" */
5373 if(!strcmpiW(lf.lfFaceName, SymbolW))
5374 lf.lfCharSet = SYMBOL_CHARSET;
5376 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
5377 switch(lf.lfCharSet) {
5378 case DEFAULT_CHARSET:
5379 csi.fs.fsCsb[0] = 0;
5380 break;
5381 default:
5382 FIXME("Untranslated charset %d\n", lf.lfCharSet);
5383 csi.fs.fsCsb[0] = 0;
5384 break;
5388 family = NULL;
5389 if(lf.lfFaceName[0] != '\0') {
5390 CHILD_FONT *font_link_entry;
5391 LPWSTR FaceName = lf.lfFaceName;
5393 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
5395 if(psub) {
5396 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
5397 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
5398 if (psub->to.charset != -1)
5399 lf.lfCharSet = psub->to.charset;
5402 /* We want a match on name and charset or just name if
5403 charset was DEFAULT_CHARSET. If the latter then
5404 we fixup the returned charset later in get_nearest_charset
5405 where we'll either use the charset of the current ansi codepage
5406 or if that's unavailable the first charset that the font supports.
5408 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5409 if (!strcmpiW(family->FamilyName, FaceName) ||
5410 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
5412 font_link = find_font_link(family->FamilyName);
5413 face_list = get_face_list_from_family(family);
5414 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5415 if (!(face->scalable || can_use_bitmap))
5416 continue;
5417 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5418 goto found;
5419 if (font_link != NULL &&
5420 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5421 goto found;
5422 if (!csi.fs.fsCsb[0])
5423 goto found;
5428 /* Search by full face name. */
5429 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5430 face_list = get_face_list_from_family(family);
5431 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5432 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
5433 (face->scalable || can_use_bitmap))
5435 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5436 goto found_face;
5437 font_link = find_font_link(family->FamilyName);
5438 if (font_link != NULL &&
5439 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5440 goto found_face;
5446 * Try check the SystemLink list first for a replacement font.
5447 * We may find good replacements there.
5449 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
5451 if(!strcmpiW(font_link->font_name, FaceName) ||
5452 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
5454 TRACE("found entry in system list\n");
5455 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5457 const SYSTEM_LINKS *links;
5459 face = font_link_entry->face;
5460 if (!(face->scalable || can_use_bitmap))
5461 continue;
5462 family = face->family;
5463 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5464 goto found;
5465 links = find_font_link(family->FamilyName);
5466 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
5467 goto found;
5473 psub = NULL; /* substitution is no more relevant */
5475 /* If requested charset was DEFAULT_CHARSET then try using charset
5476 corresponding to the current ansi codepage */
5477 if (!csi.fs.fsCsb[0])
5479 INT acp = GetACP();
5480 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
5481 FIXME("TCI failed on codepage %d\n", acp);
5482 csi.fs.fsCsb[0] = 0;
5483 } else
5484 lf.lfCharSet = csi.ciCharset;
5487 want_vertical = (lf.lfFaceName[0] == '@');
5489 /* Face families are in the top 4 bits of lfPitchAndFamily,
5490 so mask with 0xF0 before testing */
5492 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
5493 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
5494 strcpyW(lf.lfFaceName, defFixed);
5495 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
5496 strcpyW(lf.lfFaceName, defSerif);
5497 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
5498 strcpyW(lf.lfFaceName, defSans);
5499 else
5500 strcpyW(lf.lfFaceName, defSans);
5501 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5502 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
5503 font_link = find_font_link(family->FamilyName);
5504 face_list = get_face_list_from_family(family);
5505 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5506 if (!(face->scalable || can_use_bitmap))
5507 continue;
5508 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5509 goto found;
5510 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5511 goto found;
5516 last_resort_family = NULL;
5517 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5518 font_link = find_font_link(family->FamilyName);
5519 face_list = get_face_list_from_family(family);
5520 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5521 if(!(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical &&
5522 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5523 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
5524 if(face->scalable)
5525 goto found;
5526 if(can_use_bitmap && !last_resort_family)
5527 last_resort_family = family;
5532 if(last_resort_family) {
5533 family = last_resort_family;
5534 csi.fs.fsCsb[0] = 0;
5535 goto found;
5538 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5539 face_list = get_face_list_from_family(family);
5540 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5541 if(face->scalable && !(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical) {
5542 csi.fs.fsCsb[0] = 0;
5543 WARN("just using first face for now\n");
5544 goto found;
5546 if(can_use_bitmap && !last_resort_family)
5547 last_resort_family = family;
5550 if(!last_resort_family) {
5551 FIXME("can't find a single appropriate font - bailing\n");
5552 free_font(ret);
5553 ret = NULL;
5554 goto done;
5557 WARN("could only find a bitmap font - this will probably look awful!\n");
5558 family = last_resort_family;
5559 csi.fs.fsCsb[0] = 0;
5561 found:
5562 it = lf.lfItalic ? 1 : 0;
5563 bd = lf.lfWeight > 550 ? 1 : 0;
5565 height = lf.lfHeight;
5567 face = best = best_bitmap = NULL;
5568 font_link = find_font_link(family->FamilyName);
5569 face_list = get_face_list_from_family(family);
5570 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5572 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5573 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
5574 !csi.fs.fsCsb[0])
5576 BOOL italic, bold;
5578 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
5579 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
5580 new_score = (italic ^ it) + (bold ^ bd);
5581 if(!best || new_score <= score)
5583 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5584 italic, bold, it, bd);
5585 score = new_score;
5586 best = face;
5587 if(best->scalable && score == 0) break;
5588 if(!best->scalable)
5590 if(height > 0)
5591 newdiff = height - (signed int)(best->size.height);
5592 else
5593 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
5594 if(!best_bitmap || new_score < score ||
5595 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
5597 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
5598 diff = newdiff;
5599 best_bitmap = best;
5600 if(score == 0 && diff == 0) break;
5606 if(best)
5607 face = best->scalable ? best : best_bitmap;
5608 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
5609 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
5611 found_face:
5612 height = lf.lfHeight;
5614 ret->fs = face->fs;
5616 if(csi.fs.fsCsb[0]) {
5617 ret->charset = lf.lfCharSet;
5618 ret->codepage = csi.ciACP;
5620 else
5621 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
5623 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
5624 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
5626 ret->aveWidth = height ? lf.lfWidth : 0;
5628 if(!face->scalable) {
5629 /* Windows uses integer scaling factors for bitmap fonts */
5630 INT scale, scaled_height;
5631 GdiFont *cachedfont;
5633 /* FIXME: rotation of bitmap fonts is ignored */
5634 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
5635 if (ret->aveWidth)
5636 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
5637 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
5638 dcmat.eM11 = dcmat.eM22 = 1.0;
5639 /* As we changed the matrix, we need to search the cache for the font again,
5640 * otherwise we might explode the cache. */
5641 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5642 TRACE("Found cached font after non-scalable matrix rescale!\n");
5643 free_font( ret );
5644 ret = cachedfont;
5645 goto done;
5647 calc_hash(&ret->font_desc);
5649 if (height != 0) height = diff;
5650 height += face->size.height;
5652 scale = (height + face->size.height - 1) / face->size.height;
5653 scaled_height = scale * face->size.height;
5654 /* Only jump to the next height if the difference <= 25% original height */
5655 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
5656 /* The jump between unscaled and doubled is delayed by 1 */
5657 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
5658 ret->scale_y = scale;
5660 width = face->size.x_ppem >> 6;
5661 height = face->size.y_ppem >> 6;
5663 else
5664 ret->scale_y = 1.0;
5665 TRACE("font scale y: %f\n", ret->scale_y);
5667 ret->ft_face = OpenFontFace(ret, face, width, height);
5669 if (!ret->ft_face)
5671 free_font( ret );
5672 ret = NULL;
5673 goto done;
5676 fill_fileinfo_from_face( ret, face );
5677 ret->ntmFlags = face->ntmFlags;
5679 pick_charmap( ret->ft_face, ret->charset );
5681 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
5682 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
5683 ret->underline = lf.lfUnderline ? 0xff : 0;
5684 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
5685 create_child_font_list(ret);
5687 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
5689 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
5690 if (length != GDI_ERROR)
5692 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
5693 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
5694 TRACE("Loaded GSUB table of %i bytes\n",length);
5695 ret->vert_feature = get_GSUB_vert_feature(ret);
5696 if (!ret->vert_feature)
5698 TRACE("Vertical feature not found\n");
5699 HeapFree(GetProcessHeap(), 0, ret->GSUB_Table);
5700 ret->GSUB_Table = NULL;
5704 ret->aa_flags = HIWORD( face->flags );
5706 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
5708 add_to_cache(ret);
5709 done:
5710 if (ret)
5712 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
5714 switch (lf.lfQuality)
5716 case NONANTIALIASED_QUALITY:
5717 case ANTIALIASED_QUALITY:
5718 next->funcs->pSelectFont( dev, hfont, aa_flags );
5719 break;
5720 case CLEARTYPE_QUALITY:
5721 case CLEARTYPE_NATURAL_QUALITY:
5722 default:
5723 if (!*aa_flags) *aa_flags = ret->aa_flags;
5724 next->funcs->pSelectFont( dev, hfont, aa_flags );
5726 /* fixup the antialiasing flags for that font */
5727 switch (*aa_flags)
5729 case WINE_GGO_HRGB_BITMAP:
5730 case WINE_GGO_HBGR_BITMAP:
5731 case WINE_GGO_VRGB_BITMAP:
5732 case WINE_GGO_VBGR_BITMAP:
5733 if (is_subpixel_rendering_enabled()) break;
5734 *aa_flags = GGO_GRAY4_BITMAP;
5735 /* fall through */
5736 case GGO_GRAY2_BITMAP:
5737 case GGO_GRAY4_BITMAP:
5738 case GGO_GRAY8_BITMAP:
5739 case WINE_GGO_GRAY16_BITMAP:
5740 if ((!antialias_fakes || (!ret->fake_bold && !ret->fake_italic)) && is_hinting_enabled())
5742 WORD gasp_flags;
5743 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
5745 TRACE( "font %s %d aa disabled by GASP\n",
5746 debugstr_w(lf.lfFaceName), lf.lfHeight );
5747 *aa_flags = GGO_BITMAP;
5752 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5753 release_font( physdev->font );
5754 physdev->font = ret;
5756 LeaveCriticalSection( &freetype_cs );
5757 release_dc_ptr( dc );
5758 return ret ? hfont : 0;
5761 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5763 HRSRC rsrc;
5764 HGLOBAL hMem;
5765 WCHAR *p;
5766 int i;
5768 id += IDS_FIRST_SCRIPT;
5769 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5770 if (!rsrc) return 0;
5771 hMem = LoadResource( gdi32_module, rsrc );
5772 if (!hMem) return 0;
5774 p = LockResource( hMem );
5775 id &= 0x000f;
5776 while (id--) p += *p + 1;
5778 i = min(LF_FACESIZE - 1, *p);
5779 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5780 buffer[i] = 0;
5781 return i;
5784 static inline BOOL is_complex_script_ansi_cp(UINT ansi_cp)
5786 return (ansi_cp == 874 /* Thai */
5787 || ansi_cp == 1255 /* Hebrew */
5788 || ansi_cp == 1256 /* Arabic */
5792 /***************************************************
5793 * create_enum_charset_list
5795 * This function creates charset enumeration list because in DEFAULT_CHARSET
5796 * case, the ANSI codepage's charset takes precedence over other charsets.
5797 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
5798 * This function works as a filter other than DEFAULT_CHARSET case.
5800 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5802 CHARSETINFO csi;
5803 DWORD n = 0;
5805 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5806 csi.fs.fsCsb[0] != 0) {
5807 list->element[n].mask = csi.fs.fsCsb[0];
5808 list->element[n].charset = csi.ciCharset;
5809 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5810 n++;
5812 else { /* charset is DEFAULT_CHARSET or invalid. */
5813 INT acp, i;
5814 DWORD mask = 0;
5816 /* Set the current codepage's charset as the first element. */
5817 acp = GetACP();
5818 if (!is_complex_script_ansi_cp(acp) &&
5819 TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5820 csi.fs.fsCsb[0] != 0) {
5821 list->element[n].mask = csi.fs.fsCsb[0];
5822 list->element[n].charset = csi.ciCharset;
5823 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5824 mask |= csi.fs.fsCsb[0];
5825 n++;
5828 /* Fill out left elements. */
5829 for (i = 0; i < 32; i++) {
5830 FONTSIGNATURE fs;
5831 fs.fsCsb[0] = 1L << i;
5832 fs.fsCsb[1] = 0;
5833 if (fs.fsCsb[0] & mask)
5834 continue; /* skip, already added. */
5835 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5836 continue; /* skip, this is an invalid fsCsb bit. */
5838 list->element[n].mask = fs.fsCsb[0];
5839 list->element[n].charset = csi.ciCharset;
5840 load_script_name( i, list->element[n].name );
5841 mask |= fs.fsCsb[0];
5842 n++;
5845 /* add catch all mask for remaining bits */
5846 if (~mask)
5848 list->element[n].mask = ~mask;
5849 list->element[n].charset = DEFAULT_CHARSET;
5850 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5851 n++;
5854 list->total = n;
5856 return n;
5859 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
5860 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5862 GdiFont *font;
5863 LONG width, height;
5865 if (face->cached_enum_data)
5867 TRACE("Cached\n");
5868 *pelf = face->cached_enum_data->elf;
5869 *pntm = face->cached_enum_data->ntm;
5870 *ptype = face->cached_enum_data->type;
5871 return;
5874 font = alloc_font();
5876 if(face->scalable) {
5877 height = 100;
5878 width = 0;
5879 } else {
5880 height = face->size.y_ppem >> 6;
5881 width = face->size.x_ppem >> 6;
5883 font->scale_y = 1.0;
5885 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5887 free_font(font);
5888 return;
5891 font->name = strdupW( family_name );
5892 font->ntmFlags = face->ntmFlags;
5894 if (get_outline_text_metrics(font))
5896 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5898 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5899 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5900 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5902 lstrcpynW(pelf->elfLogFont.lfFaceName,
5903 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5904 LF_FACESIZE);
5905 lstrcpynW(pelf->elfFullName,
5906 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5907 LF_FULLFACESIZE);
5908 lstrcpynW(pelf->elfStyle,
5909 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5910 LF_FACESIZE);
5912 else
5914 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5916 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5917 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5918 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5920 lstrcpynW(pelf->elfLogFont.lfFaceName, family_name, LF_FACESIZE);
5921 if (face->FullName)
5922 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5923 else
5924 lstrcpynW(pelf->elfFullName, family_name, LF_FULLFACESIZE);
5925 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5928 pntm->ntmTm.ntmFlags = face->ntmFlags;
5929 pntm->ntmFontSig = face->fs;
5931 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5933 pelf->elfLogFont.lfEscapement = 0;
5934 pelf->elfLogFont.lfOrientation = 0;
5935 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5936 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5937 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5938 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5939 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5940 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5941 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5942 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5943 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5944 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5945 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5947 *ptype = 0;
5948 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5949 *ptype |= TRUETYPE_FONTTYPE;
5950 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5951 *ptype |= DEVICE_FONTTYPE;
5952 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5953 *ptype |= RASTER_FONTTYPE;
5955 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5956 if (face->cached_enum_data)
5958 face->cached_enum_data->elf = *pelf;
5959 face->cached_enum_data->ntm = *pntm;
5960 face->cached_enum_data->type = *ptype;
5963 free_font(font);
5966 static BOOL family_matches(Family *family, const WCHAR *face_name)
5968 Face *face;
5969 const struct list *face_list;
5971 if (!strcmpiW(face_name, family->FamilyName)) return TRUE;
5973 face_list = get_face_list_from_family(family);
5974 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5975 if (face->FullName && !strcmpiW(face_name, face->FullName)) return TRUE;
5977 return FALSE;
5980 static BOOL face_matches(const WCHAR *family_name, Face *face, const WCHAR *face_name)
5982 if (!strcmpiW(face_name, family_name)) return TRUE;
5984 return (face->FullName && !strcmpiW(face_name, face->FullName));
5987 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5988 FONTENUMPROCW proc, LPARAM lparam, const WCHAR *subst)
5990 ENUMLOGFONTEXW elf;
5991 NEWTEXTMETRICEXW ntm;
5992 DWORD type = 0;
5993 DWORD i;
5995 GetEnumStructs(face, face->family->FamilyName, &elf, &ntm, &type);
5996 for(i = 0; i < list->total; i++) {
5997 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5998 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5999 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
6000 i = list->total; /* break out of loop after enumeration */
6002 else
6004 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
6005 /* use the DEFAULT_CHARSET case only if no other charset is present */
6006 if (list->element[i].charset == DEFAULT_CHARSET &&
6007 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
6008 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
6009 strcpyW(elf.elfScript, list->element[i].name);
6010 if (!elf.elfScript[0])
6011 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
6013 /* Font Replacement */
6014 if (family != face->family)
6016 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
6017 if (face->FullName)
6018 strcpyW(elf.elfFullName, face->FullName);
6019 else
6020 strcpyW(elf.elfFullName, family->FamilyName);
6022 if (subst)
6023 strcpyW(elf.elfLogFont.lfFaceName, subst);
6024 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
6025 debugstr_w(elf.elfLogFont.lfFaceName),
6026 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
6027 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
6028 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
6029 ntm.ntmTm.ntmFlags);
6030 /* release section before callback (FIXME) */
6031 LeaveCriticalSection( &freetype_cs );
6032 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
6033 EnterCriticalSection( &freetype_cs );
6035 return TRUE;
6038 /*************************************************************
6039 * freetype_EnumFonts
6041 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
6043 Family *family;
6044 Face *face;
6045 const struct list *face_list;
6046 LOGFONTW lf;
6047 struct enum_charset_list enum_charsets;
6049 if (!plf)
6051 lf.lfCharSet = DEFAULT_CHARSET;
6052 lf.lfPitchAndFamily = 0;
6053 lf.lfFaceName[0] = 0;
6054 plf = &lf;
6057 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
6059 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
6061 GDI_CheckNotLock();
6062 EnterCriticalSection( &freetype_cs );
6063 if(plf->lfFaceName[0]) {
6064 WCHAR *face_name = plf->lfFaceName;
6065 FontSubst *psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
6067 if(psub) {
6068 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
6069 debugstr_w(psub->to.name));
6070 face_name = psub->to.name;
6073 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
6074 if (!family_matches(family, face_name)) continue;
6075 face_list = get_face_list_from_family(family);
6076 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
6077 if (!face_matches(family->FamilyName, face, face_name)) continue;
6078 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam, psub ? psub->from.name : NULL)) return FALSE;
6081 } else {
6082 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
6083 face_list = get_face_list_from_family(family);
6084 face = LIST_ENTRY(list_head(face_list), Face, entry);
6085 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam, NULL)) return FALSE;
6088 LeaveCriticalSection( &freetype_cs );
6089 return TRUE;
6092 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
6094 pt->x.value = vec->x >> 6;
6095 pt->x.fract = (vec->x & 0x3f) << 10;
6096 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
6097 pt->y.value = vec->y >> 6;
6098 pt->y.fract = (vec->y & 0x3f) << 10;
6099 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
6102 /***************************************************
6103 * According to the MSDN documentation on WideCharToMultiByte,
6104 * certain codepages cannot set the default_used parameter.
6105 * This returns TRUE if the codepage can set that parameter, false else
6106 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
6108 static BOOL codepage_sets_default_used(UINT codepage)
6110 switch (codepage)
6112 case CP_UTF7:
6113 case CP_UTF8:
6114 case CP_SYMBOL:
6115 return FALSE;
6116 default:
6117 return TRUE;
6122 * GSUB Table handling functions
6125 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
6127 const GSUB_CoverageFormat1* cf1;
6129 cf1 = table;
6131 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
6133 int count = GET_BE_WORD(cf1->GlyphCount);
6134 int i;
6135 TRACE("Coverage Format 1, %i glyphs\n",count);
6136 for (i = 0; i < count; i++)
6137 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
6138 return i;
6139 return -1;
6141 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
6143 const GSUB_CoverageFormat2* cf2;
6144 int i;
6145 int count;
6146 cf2 = (const GSUB_CoverageFormat2*)cf1;
6148 count = GET_BE_WORD(cf2->RangeCount);
6149 TRACE("Coverage Format 2, %i ranges\n",count);
6150 for (i = 0; i < count; i++)
6152 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
6153 return -1;
6154 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
6155 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
6157 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
6158 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
6161 return -1;
6163 else
6164 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
6166 return -1;
6169 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
6171 int i;
6172 int offset;
6173 const GSUB_LookupList *lookup;
6174 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
6176 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
6177 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
6179 const GSUB_LookupTable *look;
6180 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
6181 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
6182 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
6183 if (GET_BE_WORD(look->LookupType) != 1)
6184 FIXME("We only handle SubType 1\n");
6185 else
6187 int j;
6189 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
6191 const GSUB_SingleSubstFormat1 *ssf1;
6192 offset = GET_BE_WORD(look->SubTable[j]);
6193 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
6194 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
6196 int offset = GET_BE_WORD(ssf1->Coverage);
6197 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
6198 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
6200 TRACE(" Glyph 0x%x ->",glyph);
6201 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
6202 TRACE(" 0x%x\n",glyph);
6205 else
6207 const GSUB_SingleSubstFormat2 *ssf2;
6208 INT index;
6209 INT offset;
6211 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
6212 offset = GET_BE_WORD(ssf1->Coverage);
6213 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
6214 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
6215 TRACE(" Coverage index %i\n",index);
6216 if (index != -1)
6218 TRACE(" Glyph is 0x%x ->",glyph);
6219 glyph = GET_BE_WORD(ssf2->Substitute[index]);
6220 TRACE("0x%x\n",glyph);
6226 return glyph;
6230 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
6232 const GSUB_Header *header;
6233 const GSUB_Feature *feature;
6235 if (!font->GSUB_Table)
6236 return glyph;
6238 header = font->GSUB_Table;
6239 feature = font->vert_feature;
6241 return GSUB_apply_feature(header, feature, glyph);
6244 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
6246 FT_UInt glyphId;
6248 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
6249 WCHAR wc = (WCHAR)glyph;
6250 BOOL default_used;
6251 BOOL *default_used_pointer;
6252 FT_UInt ret;
6253 char buf;
6254 default_used_pointer = NULL;
6255 default_used = FALSE;
6256 if (codepage_sets_default_used(font->codepage))
6257 default_used_pointer = &default_used;
6258 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
6260 if (font->codepage == CP_SYMBOL && wc < 0x100)
6261 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
6262 else
6263 ret = 0;
6265 else
6266 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
6267 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6268 return ret;
6271 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
6273 if (glyph < 0x100) glyph += 0xf000;
6274 /* there is a number of old pre-Unicode "broken" TTFs, which
6275 do have symbols at U+00XX instead of U+f0XX */
6276 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
6277 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
6279 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
6281 return glyphId;
6284 /* helper for freetype_GetGlyphIndices */
6285 static FT_UInt get_gdi_glyph_index(const GdiFont *font, UINT glyph)
6287 WCHAR wc = (WCHAR)glyph;
6288 BOOL default_used = FALSE;
6289 BOOL *default_used_pointer = NULL;
6290 FT_UInt ret;
6291 char buf;
6293 if(font->ft_face->charmap->encoding != FT_ENCODING_NONE)
6294 return get_glyph_index(font, glyph);
6296 if (codepage_sets_default_used(font->codepage))
6297 default_used_pointer = &default_used;
6298 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer)
6299 || default_used)
6301 if (font->codepage == CP_SYMBOL && wc < 0x100)
6302 ret = (unsigned char)wc;
6303 else
6304 ret = 0;
6306 else
6307 ret = (unsigned char)buf;
6308 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6309 return ret;
6312 static FT_UInt get_default_char_index(GdiFont *font)
6314 FT_UInt default_char;
6316 if (FT_IS_SFNT(font->ft_face))
6318 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
6319 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
6321 else
6323 TEXTMETRICW textm;
6324 get_text_metrics(font, &textm);
6325 default_char = textm.tmDefaultChar;
6328 return default_char;
6331 /*************************************************************
6332 * freetype_GetGlyphIndices
6334 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
6336 struct freetype_physdev *physdev = get_freetype_dev( dev );
6337 int i;
6338 WORD default_char;
6339 BOOL got_default = FALSE;
6341 if (!physdev->font)
6343 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
6344 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
6347 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
6349 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
6350 got_default = TRUE;
6353 GDI_CheckNotLock();
6354 EnterCriticalSection( &freetype_cs );
6356 for(i = 0; i < count; i++)
6358 pgi[i] = get_gdi_glyph_index(physdev->font, lpstr[i]);
6359 if (pgi[i] == 0)
6361 if (!got_default)
6363 default_char = get_default_char_index(physdev->font);
6364 got_default = TRUE;
6366 pgi[i] = default_char;
6368 else
6369 pgi[i] = get_GSUB_vert_glyph(physdev->font, pgi[i]);
6371 LeaveCriticalSection( &freetype_cs );
6372 return count;
6375 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
6377 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
6378 return !memcmp(matrix, &identity, sizeof(FMAT2));
6381 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
6383 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
6384 return !memcmp(matrix, &identity, sizeof(MAT2));
6387 static void synthesize_bold_glyph(FT_GlyphSlot glyph, LONG ppem, FT_Glyph_Metrics *metrics)
6389 FT_Error err;
6390 static UINT once;
6392 switch(glyph->format) {
6393 case FT_GLYPH_FORMAT_OUTLINE:
6395 FT_Pos strength;
6396 FT_BBox bbox;
6397 if(!pFT_Outline_Embolden)
6398 break;
6400 strength = MulDiv(ppem, 1 << 6, 24);
6401 err = pFT_Outline_Embolden(&glyph->outline, strength);
6402 if(err) {
6403 TRACE("FT_Ouline_Embolden returns %d, ignored\n", err);
6404 break;
6407 pFT_Outline_Get_CBox(&glyph->outline, &bbox);
6408 metrics->width = bbox.xMax - bbox.xMin;
6409 metrics->height = bbox.yMax - bbox.yMin;
6410 metrics->horiBearingX = bbox.xMin;
6411 metrics->horiBearingY = bbox.yMax;
6412 metrics->horiAdvance += (1 << 6);
6413 metrics->vertAdvance += (1 << 6);
6414 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
6415 metrics->vertBearingY = (metrics->vertAdvance - metrics->height) / 2;
6416 break;
6418 default:
6419 if (!once++)
6420 WARN("Emboldening format 0x%x is not supported\n", glyph->format);
6421 return;
6425 static inline BYTE get_max_level( UINT format )
6427 switch( format )
6429 case GGO_GRAY2_BITMAP: return 4;
6430 case GGO_GRAY4_BITMAP: return 16;
6431 case GGO_GRAY8_BITMAP: return 64;
6433 return 255;
6436 extern const unsigned short vertical_orientation_table[];
6438 static BOOL check_unicode_tategaki(WCHAR uchar)
6440 unsigned short orientation = vertical_orientation_table[vertical_orientation_table[vertical_orientation_table[uchar >> 8]+((uchar >> 4) & 0x0f)]+ (uchar & 0xf)];
6442 /* We only reach this code if typographical substitution did not occur */
6443 /* Type: U or Type: Tu */
6444 return (orientation == 1 || orientation == 3);
6447 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
6449 TTPOLYGONHEADER *pph;
6450 TTPOLYCURVE *ppc;
6451 unsigned int needed = 0, point = 0, contour, first_pt;
6452 unsigned int pph_start, cpfx;
6453 DWORD type;
6455 for (contour = 0; contour < outline->n_contours; contour++)
6457 /* Ignore contours containing one point */
6458 if (point == outline->contours[contour])
6460 point++;
6461 continue;
6464 pph_start = needed;
6465 pph = (TTPOLYGONHEADER *)(buf + needed);
6466 first_pt = point;
6467 if (buf)
6469 pph->dwType = TT_POLYGON_TYPE;
6470 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6472 needed += sizeof(*pph);
6473 point++;
6474 while (point <= outline->contours[contour])
6476 ppc = (TTPOLYCURVE *)(buf + needed);
6477 type = outline->tags[point] & FT_Curve_Tag_On ?
6478 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6479 cpfx = 0;
6482 if (buf)
6483 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6484 cpfx++;
6485 point++;
6486 } while (point <= outline->contours[contour] &&
6487 (outline->tags[point] & FT_Curve_Tag_On) ==
6488 (outline->tags[point-1] & FT_Curve_Tag_On));
6489 /* At the end of a contour Windows adds the start point, but
6490 only for Beziers */
6491 if (point > outline->contours[contour] &&
6492 !(outline->tags[point-1] & FT_Curve_Tag_On))
6494 if (buf)
6495 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6496 cpfx++;
6498 else if (point <= outline->contours[contour] &&
6499 outline->tags[point] & FT_Curve_Tag_On)
6501 /* add closing pt for bezier */
6502 if (buf)
6503 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6504 cpfx++;
6505 point++;
6507 if (buf)
6509 ppc->wType = type;
6510 ppc->cpfx = cpfx;
6512 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6514 if (buf)
6515 pph->cb = needed - pph_start;
6517 return needed;
6520 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
6522 /* Convert the quadratic Beziers to cubic Beziers.
6523 The parametric eqn for a cubic Bezier is, from PLRM:
6524 r(t) = at^3 + bt^2 + ct + r0
6525 with the control points:
6526 r1 = r0 + c/3
6527 r2 = r1 + (c + b)/3
6528 r3 = r0 + c + b + a
6530 A quadratic Bezier has the form:
6531 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6533 So equating powers of t leads to:
6534 r1 = 2/3 p1 + 1/3 p0
6535 r2 = 2/3 p1 + 1/3 p2
6536 and of course r0 = p0, r3 = p2
6538 int contour, point = 0, first_pt;
6539 TTPOLYGONHEADER *pph;
6540 TTPOLYCURVE *ppc;
6541 DWORD pph_start, cpfx, type;
6542 FT_Vector cubic_control[4];
6543 unsigned int needed = 0;
6545 for (contour = 0; contour < outline->n_contours; contour++)
6547 pph_start = needed;
6548 pph = (TTPOLYGONHEADER *)(buf + needed);
6549 first_pt = point;
6550 if (buf)
6552 pph->dwType = TT_POLYGON_TYPE;
6553 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6555 needed += sizeof(*pph);
6556 point++;
6557 while (point <= outline->contours[contour])
6559 ppc = (TTPOLYCURVE *)(buf + needed);
6560 type = outline->tags[point] & FT_Curve_Tag_On ?
6561 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6562 cpfx = 0;
6565 if (type == TT_PRIM_LINE)
6567 if (buf)
6568 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6569 cpfx++;
6570 point++;
6572 else
6574 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6575 so cpfx = 3n */
6577 /* FIXME: Possible optimization in endpoint calculation
6578 if there are two consecutive curves */
6579 cubic_control[0] = outline->points[point-1];
6580 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
6582 cubic_control[0].x += outline->points[point].x + 1;
6583 cubic_control[0].y += outline->points[point].y + 1;
6584 cubic_control[0].x >>= 1;
6585 cubic_control[0].y >>= 1;
6587 if (point+1 > outline->contours[contour])
6588 cubic_control[3] = outline->points[first_pt];
6589 else
6591 cubic_control[3] = outline->points[point+1];
6592 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
6594 cubic_control[3].x += outline->points[point].x + 1;
6595 cubic_control[3].y += outline->points[point].y + 1;
6596 cubic_control[3].x >>= 1;
6597 cubic_control[3].y >>= 1;
6600 /* r1 = 1/3 p0 + 2/3 p1
6601 r2 = 1/3 p2 + 2/3 p1 */
6602 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6603 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6604 cubic_control[2] = cubic_control[1];
6605 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6606 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6607 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6608 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6609 if (buf)
6611 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6612 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6613 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6615 cpfx += 3;
6616 point++;
6618 } while (point <= outline->contours[contour] &&
6619 (outline->tags[point] & FT_Curve_Tag_On) ==
6620 (outline->tags[point-1] & FT_Curve_Tag_On));
6621 /* At the end of a contour Windows adds the start point,
6622 but only for Beziers and we've already done that.
6624 if (point <= outline->contours[contour] &&
6625 outline->tags[point] & FT_Curve_Tag_On)
6627 /* This is the closing pt of a bezier, but we've already
6628 added it, so just inc point and carry on */
6629 point++;
6631 if (buf)
6633 ppc->wType = type;
6634 ppc->cpfx = cpfx;
6636 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6638 if (buf)
6639 pph->cb = needed - pph_start;
6641 return needed;
6644 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6646 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
6647 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
6648 const MAT2* lpmat)
6650 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
6651 GLYPHMETRICS gm;
6652 FT_Face ft_face = incoming_font->ft_face;
6653 GdiFont *font = incoming_font;
6654 FT_Glyph_Metrics metrics;
6655 FT_UInt glyph_index;
6656 DWORD width, height, pitch, needed = 0;
6657 FT_Bitmap ft_bitmap;
6658 FT_Error err;
6659 INT left, right, top = 0, bottom = 0, adv;
6660 INT origin_x = 0, origin_y = 0;
6661 FT_Angle angle = 0;
6662 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
6663 double widthRatio = 1.0;
6664 FT_Matrix transMat = identityMat;
6665 FT_Matrix transMatUnrotated;
6666 FT_Matrix transMatTategaki;
6667 BOOL needsTransform = FALSE;
6668 BOOL tategaki = (font->name[0] == '@');
6669 BOOL vertical_metrics;
6670 UINT original_index;
6671 LONG avgAdvance = 0;
6672 FT_Fixed em_scale;
6674 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
6675 buflen, buf, lpmat);
6677 TRACE("font transform %f %f %f %f\n",
6678 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
6679 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
6681 if(format & GGO_GLYPH_INDEX) {
6682 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
6683 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
6684 as glyph index. "Treasure Adventure Game" depends on this. */
6685 glyph_index = pFT_Get_Char_Index(font->ft_face, glyph);
6686 TRACE("translate glyph index %04x -> %04x\n", glyph, glyph_index);
6687 } else
6688 glyph_index = glyph;
6689 original_index = glyph_index;
6690 format &= ~GGO_GLYPH_INDEX;
6691 /* TODO: Window also turns off tategaki for glyphs passed in by index
6692 if their unicode code points fall outside of the range that is
6693 rotated. */
6694 } else {
6695 BOOL vert;
6696 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index, &vert);
6697 ft_face = font->ft_face;
6698 original_index = glyph_index;
6699 if (!vert && tategaki)
6700 tategaki = check_unicode_tategaki(glyph);
6703 if(format & GGO_UNHINTED) {
6704 load_flags |= FT_LOAD_NO_HINTING;
6705 format &= ~GGO_UNHINTED;
6708 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
6709 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
6710 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
6711 font->gmsize * sizeof(GM*));
6712 } else {
6713 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
6714 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
6716 *lpgm = FONT_GM(font,original_index)->gm;
6717 *abc = FONT_GM(font,original_index)->abc;
6718 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6719 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6720 lpgm->gmCellIncX, lpgm->gmCellIncY);
6721 return 1; /* FIXME */
6725 if (!font->gm[original_index / GM_BLOCK_SIZE])
6726 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
6728 /* Scaling factor */
6729 if (font->aveWidth)
6731 TEXTMETRICW tm;
6733 get_text_metrics(font, &tm);
6735 widthRatio = (double)font->aveWidth;
6736 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6738 else
6739 widthRatio = font->scale_y;
6741 /* Scaling transform */
6742 if (widthRatio != 1.0 || font->scale_y != 1.0)
6744 FT_Matrix scaleMat;
6745 scaleMat.xx = FT_FixedFromFloat(widthRatio);
6746 scaleMat.xy = 0;
6747 scaleMat.yx = 0;
6748 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
6750 pFT_Matrix_Multiply(&scaleMat, &transMat);
6751 needsTransform = TRUE;
6754 /* Slant transform */
6755 if (font->fake_italic) {
6756 FT_Matrix slantMat;
6758 slantMat.xx = (1 << 16);
6759 slantMat.xy = ((1 << 16) >> 2);
6760 slantMat.yx = 0;
6761 slantMat.yy = (1 << 16);
6762 pFT_Matrix_Multiply(&slantMat, &transMat);
6763 needsTransform = TRUE;
6766 /* Rotation transform */
6767 transMatUnrotated = transMat;
6768 transMatTategaki = transMat;
6769 if(font->orientation || tategaki) {
6770 FT_Matrix rotationMat;
6771 FT_Matrix taterotationMat;
6772 FT_Vector vecAngle;
6774 double orient = font->orientation / 10.0;
6775 double tate_orient = 0.f;
6777 if (tategaki)
6778 tate_orient = ((font->orientation+900)%3600)/10.0;
6779 else
6780 tate_orient = font->orientation/10.0;
6782 if (orient)
6784 angle = FT_FixedFromFloat(orient);
6785 pFT_Vector_Unit(&vecAngle, angle);
6786 rotationMat.xx = vecAngle.x;
6787 rotationMat.xy = -vecAngle.y;
6788 rotationMat.yx = -rotationMat.xy;
6789 rotationMat.yy = rotationMat.xx;
6791 pFT_Matrix_Multiply(&rotationMat, &transMat);
6794 if (tate_orient)
6796 angle = FT_FixedFromFloat(tate_orient);
6797 pFT_Vector_Unit(&vecAngle, angle);
6798 taterotationMat.xx = vecAngle.x;
6799 taterotationMat.xy = -vecAngle.y;
6800 taterotationMat.yx = -taterotationMat.xy;
6801 taterotationMat.yy = taterotationMat.xx;
6802 pFT_Matrix_Multiply(&taterotationMat, &transMatTategaki);
6805 needsTransform = TRUE;
6808 /* World transform */
6809 if (!is_identity_FMAT2(&font->font_desc.matrix))
6811 FT_Matrix worldMat;
6812 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
6813 worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21);
6814 worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12);
6815 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
6816 pFT_Matrix_Multiply(&worldMat, &transMat);
6817 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
6818 pFT_Matrix_Multiply(&worldMat, &transMatTategaki);
6819 needsTransform = TRUE;
6822 /* Extra transformation specified by caller */
6823 if (!is_identity_MAT2(lpmat))
6825 FT_Matrix extraMat;
6826 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
6827 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
6828 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
6829 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
6830 pFT_Matrix_Multiply(&extraMat, &transMat);
6831 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
6832 pFT_Matrix_Multiply(&extraMat, &transMatTategaki);
6833 needsTransform = TRUE;
6836 vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face));
6837 /* there is a freetype bug where vertical metrics are only
6838 properly scaled and correct in 2.4.0 or greater */
6839 if ((vertical_metrics) && (FT_Version.major < 2 || (FT_Version.major == 2 && FT_Version.minor < 4)))
6840 vertical_metrics = FALSE;
6842 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
6843 if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
6845 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
6847 if(err) {
6848 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
6849 return GDI_ERROR;
6852 metrics = ft_face->glyph->metrics;
6853 if(font->fake_bold)
6854 synthesize_bold_glyph(ft_face->glyph, font->ppem, &metrics);
6856 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6857 * by the text metrics. The proper behavior is to clip the glyph metrics to
6858 * fit within the maximums specified in the text metrics. */
6859 if(incoming_font->potm || get_outline_text_metrics(incoming_font) ||
6860 get_bitmap_text_metrics(incoming_font)) {
6861 TEXTMETRICW *ptm = &incoming_font->potm->otmTextMetrics;
6862 top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
6863 bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
6864 metrics.horiBearingY = top;
6865 metrics.height = top - bottom;
6867 /* TODO: Are we supposed to clip the width as well...? */
6868 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6871 em_scale = MulDiv(incoming_font->ppem, 1 << 16, incoming_font->ft_face->units_per_EM);
6873 if(FT_IS_SCALABLE(incoming_font->ft_face) && !font->fake_bold) {
6874 TEXTMETRICW tm;
6875 if (get_text_metrics(incoming_font, &tm) &&
6876 !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
6877 avgAdvance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
6878 if (avgAdvance &&
6879 (metrics.horiAdvance+63) >> 6 == pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale))
6880 TRACE("Fixed-pitch full-width character detected\n");
6881 else
6882 avgAdvance = 0; /* cancel this feature */
6886 if(!needsTransform) {
6887 left = (INT)(metrics.horiBearingX) & -64;
6888 right = (INT)((metrics.horiBearingX + metrics.width) + 63) & -64;
6889 if (!avgAdvance)
6890 adv = (INT)(metrics.horiAdvance + 63) >> 6;
6891 else
6892 adv = (INT)avgAdvance * 2;
6894 top = (metrics.horiBearingY + 63) & -64;
6895 bottom = (metrics.horiBearingY - metrics.height) & -64;
6896 gm.gmCellIncX = adv;
6897 gm.gmCellIncY = 0;
6898 origin_x = left;
6899 origin_y = top;
6900 abc->abcA = origin_x >> 6;
6901 abc->abcB = metrics.width >> 6;
6902 } else {
6903 INT xc, yc;
6904 FT_Vector vec;
6905 FT_Pos lsb;
6907 left = right = 0;
6909 for(xc = 0; xc < 2; xc++) {
6910 for(yc = 0; yc < 2; yc++) {
6911 vec.x = metrics.horiBearingX + xc * metrics.width;
6912 vec.y = metrics.horiBearingY - yc * metrics.height;
6913 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
6914 pFT_Vector_Transform(&vec, &transMatTategaki);
6915 if(xc == 0 && yc == 0) {
6916 left = right = vec.x;
6917 top = bottom = vec.y;
6918 } else {
6919 if(vec.x < left) left = vec.x;
6920 else if(vec.x > right) right = vec.x;
6921 if(vec.y < bottom) bottom = vec.y;
6922 else if(vec.y > top) top = vec.y;
6926 left = left & -64;
6927 right = (right + 63) & -64;
6928 bottom = bottom & -64;
6929 top = (top + 63) & -64;
6931 if (tategaki && (font->potm || get_outline_text_metrics(font)))
6933 if (vertical_metrics)
6934 lsb = metrics.horiBearingY + metrics.vertBearingY;
6935 else
6936 lsb = metrics.vertAdvance + (font->potm->otmDescent << 6);
6937 vec.x = lsb;
6938 vec.y = font->potm->otmDescent << 6;
6939 TRACE ("Vec %ld,%ld\n", vec.x>>6, vec.y>>6);
6940 pFT_Vector_Transform(&vec, &transMat);
6941 origin_x = (vec.x + left) & -64;
6942 origin_y = (vec.y + top + 63) & -64;
6944 else
6946 origin_x = left;
6947 origin_y = top;
6948 lsb = metrics.horiBearingX;
6951 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
6952 if (vertical_metrics)
6953 vec.x = metrics.vertAdvance;
6954 else
6955 vec.x = metrics.horiAdvance;
6956 vec.y = 0;
6957 pFT_Vector_Transform(&vec, &transMat);
6958 gm.gmCellIncY = -((vec.y+63) >> 6);
6959 if (!avgAdvance || vec.y)
6960 gm.gmCellIncX = (vec.x+63) >> 6;
6961 else {
6962 vec.x = incoming_font->ntmAvgWidth;
6963 vec.y = 0;
6964 pFT_Vector_Transform(&vec, &transMat);
6965 gm.gmCellIncX = pFT_MulFix(vec.x, em_scale) * 2;
6968 if (vertical_metrics)
6969 vec.x = metrics.vertAdvance;
6970 else
6971 vec.x = metrics.horiAdvance;
6972 vec.y = 0;
6973 pFT_Vector_Transform(&vec, &transMatUnrotated);
6974 if (!avgAdvance || vec.y)
6975 adv = (vec.x+63) >> 6;
6976 else {
6977 vec.x = incoming_font->ntmAvgWidth;
6978 vec.y = 0;
6979 pFT_Vector_Transform(&vec, &transMatUnrotated);
6980 adv = pFT_MulFix(vec.x, em_scale) * 2;
6983 vec.x = lsb;
6984 vec.y = 0;
6985 pFT_Vector_Transform(&vec, &transMatUnrotated);
6986 abc->abcA = vec.x >> 6;
6988 vec.x = metrics.width;
6989 vec.y = 0;
6990 pFT_Vector_Transform(&vec, &transMatUnrotated);
6991 if (vec.x >= 0)
6992 abc->abcB = vec.x >> 6;
6993 else
6994 abc->abcB = -vec.x >> 6;
6997 width = (right - left) >> 6;
6998 height = (top - bottom) >> 6;
6999 gm.gmBlackBoxX = width ? width : 1;
7000 gm.gmBlackBoxY = height ? height : 1;
7001 gm.gmptGlyphOrigin.x = origin_x >> 6;
7002 gm.gmptGlyphOrigin.y = origin_y >> 6;
7003 if (!abc->abcB) abc->abcB = 1;
7004 abc->abcC = adv - abc->abcA - abc->abcB;
7006 TRACE("%u,%u,%s,%d,%d\n", gm.gmBlackBoxX, gm.gmBlackBoxY,
7007 wine_dbgstr_point(&gm.gmptGlyphOrigin),
7008 gm.gmCellIncX, gm.gmCellIncY);
7010 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
7011 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
7013 FONT_GM(font,original_index)->gm = gm;
7014 FONT_GM(font,original_index)->abc = *abc;
7015 FONT_GM(font,original_index)->init = TRUE;
7018 if(format == GGO_METRICS)
7020 *lpgm = gm;
7021 return 1; /* FIXME */
7024 if(ft_face->glyph->format != ft_glyph_format_outline &&
7025 (format == GGO_NATIVE || format == GGO_BEZIER))
7027 TRACE("loaded a bitmap\n");
7028 return GDI_ERROR;
7031 switch(format) {
7032 case GGO_BITMAP:
7033 pitch = ((width + 31) >> 5) << 2;
7034 needed = pitch * height;
7036 if(!buf || !buflen) break;
7037 if (!needed) return GDI_ERROR; /* empty glyph */
7038 if (needed > buflen)
7039 return GDI_ERROR;
7041 switch(ft_face->glyph->format) {
7042 case ft_glyph_format_bitmap:
7044 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
7045 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
7046 INT h = min( height, ft_face->glyph->bitmap.rows );
7047 while(h--) {
7048 memcpy(dst, src, w);
7049 src += ft_face->glyph->bitmap.pitch;
7050 dst += pitch;
7052 break;
7055 case ft_glyph_format_outline:
7056 ft_bitmap.width = width;
7057 ft_bitmap.rows = height;
7058 ft_bitmap.pitch = pitch;
7059 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
7060 ft_bitmap.buffer = buf;
7062 if(needsTransform)
7063 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
7065 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
7067 /* Note: FreeType will only set 'black' bits for us. */
7068 memset(buf, 0, needed);
7069 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
7070 break;
7072 default:
7073 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
7074 return GDI_ERROR;
7076 break;
7078 case GGO_GRAY2_BITMAP:
7079 case GGO_GRAY4_BITMAP:
7080 case GGO_GRAY8_BITMAP:
7081 case WINE_GGO_GRAY16_BITMAP:
7083 unsigned int max_level, row, col;
7084 BYTE *start, *ptr;
7086 pitch = (width + 3) / 4 * 4;
7087 needed = pitch * height;
7089 if(!buf || !buflen) break;
7090 if (!needed) return GDI_ERROR; /* empty glyph */
7091 if (needed > buflen)
7092 return GDI_ERROR;
7094 max_level = get_max_level( format );
7096 switch(ft_face->glyph->format) {
7097 case ft_glyph_format_bitmap:
7099 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
7100 INT h = min( height, ft_face->glyph->bitmap.rows );
7101 INT x;
7102 memset( buf, 0, needed );
7103 while(h--) {
7104 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
7105 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
7106 src += ft_face->glyph->bitmap.pitch;
7107 dst += pitch;
7109 break;
7111 case ft_glyph_format_outline:
7113 ft_bitmap.width = width;
7114 ft_bitmap.rows = height;
7115 ft_bitmap.pitch = pitch;
7116 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
7117 ft_bitmap.buffer = buf;
7119 if(needsTransform)
7120 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
7122 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
7124 memset(ft_bitmap.buffer, 0, buflen);
7126 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
7128 if (max_level != 255)
7130 for (row = 0, start = buf; row < height; row++)
7132 for (col = 0, ptr = start; col < width; col++, ptr++)
7133 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
7134 start += pitch;
7137 break;
7140 default:
7141 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
7142 return GDI_ERROR;
7144 break;
7147 case WINE_GGO_HRGB_BITMAP:
7148 case WINE_GGO_HBGR_BITMAP:
7149 case WINE_GGO_VRGB_BITMAP:
7150 case WINE_GGO_VBGR_BITMAP:
7151 #ifdef FT_LCD_FILTER_H
7153 switch (ft_face->glyph->format)
7155 case FT_GLYPH_FORMAT_BITMAP:
7157 BYTE *src, *dst;
7158 INT src_pitch, x;
7160 pitch = width * 4;
7161 needed = pitch * height;
7163 if (!buf || !buflen) break;
7164 if (!needed) return GDI_ERROR; /* empty glyph */
7165 if (needed > buflen)
7166 return GDI_ERROR;
7168 memset(buf, 0, buflen);
7169 dst = buf;
7170 src = ft_face->glyph->bitmap.buffer;
7171 src_pitch = ft_face->glyph->bitmap.pitch;
7173 height = min( height, ft_face->glyph->bitmap.rows );
7174 while ( height-- )
7176 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
7178 if ( src[x / 8] & masks[x % 8] )
7179 ((unsigned int *)dst)[x] = ~0u;
7181 src += src_pitch;
7182 dst += pitch;
7185 break;
7188 case FT_GLYPH_FORMAT_OUTLINE:
7190 unsigned int *dst;
7191 BYTE *src;
7192 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
7193 INT x_shift, y_shift;
7194 BOOL rgb;
7195 FT_Render_Mode render_mode =
7196 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
7197 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
7199 if (!width || !height)
7201 if (!buf || !buflen) break;
7202 return GDI_ERROR;
7205 if ( render_mode == FT_RENDER_MODE_LCD)
7207 gm.gmBlackBoxX += 2;
7208 gm.gmptGlyphOrigin.x -= 1;
7209 left -= (1 << 6);
7211 else
7213 gm.gmBlackBoxY += 2;
7214 gm.gmptGlyphOrigin.y += 1;
7215 top += (1 << 6);
7218 width = gm.gmBlackBoxX;
7219 height = gm.gmBlackBoxY;
7220 pitch = width * 4;
7221 needed = pitch * height;
7223 if (!buf || !buflen) break;
7224 if (needed > buflen)
7225 return GDI_ERROR;
7227 memset(buf, 0, buflen);
7228 dst = buf;
7229 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
7231 if ( needsTransform )
7232 pFT_Outline_Transform (&ft_face->glyph->outline, &transMatTategaki);
7234 if ( pFT_Library_SetLcdFilter )
7235 pFT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT );
7236 pFT_Render_Glyph (ft_face->glyph, render_mode);
7238 src = ft_face->glyph->bitmap.buffer;
7239 src_pitch = ft_face->glyph->bitmap.pitch;
7240 src_width = ft_face->glyph->bitmap.width;
7241 src_height = ft_face->glyph->bitmap.rows;
7243 if ( render_mode == FT_RENDER_MODE_LCD)
7245 rgb_interval = 1;
7246 hmul = 3;
7247 vmul = 1;
7249 else
7251 rgb_interval = src_pitch;
7252 hmul = 1;
7253 vmul = 3;
7256 x_shift = ft_face->glyph->bitmap_left - (left >> 6);
7257 if ( x_shift < 0 )
7259 src += hmul * -x_shift;
7260 src_width -= hmul * -x_shift;
7262 else if ( x_shift > 0 )
7264 dst += x_shift;
7265 width -= x_shift;
7268 y_shift = (top >> 6) - ft_face->glyph->bitmap_top;
7269 if ( y_shift < 0 )
7271 src += src_pitch * vmul * -y_shift;
7272 src_height -= vmul * -y_shift;
7274 else if ( y_shift > 0 )
7276 dst += y_shift * ( pitch / sizeof(*dst) );
7277 height -= y_shift;
7280 width = min( width, src_width / hmul );
7281 height = min( height, src_height / vmul );
7283 while ( height-- )
7285 for ( x = 0; x < width; x++ )
7287 if ( rgb )
7289 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
7290 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
7291 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
7292 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
7294 else
7296 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
7297 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
7298 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
7299 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
7302 src += src_pitch * vmul;
7303 dst += pitch / sizeof(*dst);
7306 break;
7309 default:
7310 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
7311 return GDI_ERROR;
7314 break;
7316 #else
7317 return GDI_ERROR;
7318 #endif
7320 case GGO_NATIVE:
7322 FT_Outline *outline = &ft_face->glyph->outline;
7324 if(buflen == 0) buf = NULL;
7326 if (needsTransform && buf)
7327 pFT_Outline_Transform(outline, &transMatTategaki);
7329 needed = get_native_glyph_outline(outline, buflen, NULL);
7331 if (!buf || !buflen)
7332 break;
7333 if (needed > buflen)
7334 return GDI_ERROR;
7336 get_native_glyph_outline(outline, buflen, buf);
7337 break;
7339 case GGO_BEZIER:
7341 FT_Outline *outline = &ft_face->glyph->outline;
7342 if(buflen == 0) buf = NULL;
7344 if (needsTransform && buf)
7345 pFT_Outline_Transform(outline, &transMat);
7347 needed = get_bezier_glyph_outline(outline, buflen, NULL);
7349 if (!buf || !buflen)
7350 break;
7351 if (needed > buflen)
7352 return GDI_ERROR;
7354 get_bezier_glyph_outline(outline, buflen, buf);
7355 break;
7358 default:
7359 FIXME("Unsupported format %d\n", format);
7360 return GDI_ERROR;
7362 *lpgm = gm;
7363 return needed;
7366 static BOOL get_bitmap_text_metrics(GdiFont *font)
7368 FT_Face ft_face = font->ft_face;
7369 FT_WinFNT_HeaderRec winfnt_header;
7370 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
7371 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
7372 font->potm->otmSize = size;
7374 #define TM font->potm->otmTextMetrics
7375 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
7377 TM.tmHeight = winfnt_header.pixel_height;
7378 TM.tmAscent = winfnt_header.ascent;
7379 TM.tmDescent = TM.tmHeight - TM.tmAscent;
7380 TM.tmInternalLeading = winfnt_header.internal_leading;
7381 TM.tmExternalLeading = winfnt_header.external_leading;
7382 TM.tmAveCharWidth = winfnt_header.avg_width;
7383 TM.tmMaxCharWidth = winfnt_header.max_width;
7384 TM.tmWeight = winfnt_header.weight;
7385 TM.tmOverhang = 0;
7386 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
7387 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
7388 TM.tmFirstChar = winfnt_header.first_char;
7389 TM.tmLastChar = winfnt_header.last_char;
7390 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
7391 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
7392 TM.tmItalic = winfnt_header.italic;
7393 TM.tmUnderlined = font->underline;
7394 TM.tmStruckOut = font->strikeout;
7395 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
7396 TM.tmCharSet = winfnt_header.charset;
7398 else
7400 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
7401 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
7402 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7403 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
7404 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
7405 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
7406 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
7407 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
7408 TM.tmOverhang = 0;
7409 TM.tmDigitizedAspectX = 96; /* FIXME */
7410 TM.tmDigitizedAspectY = 96; /* FIXME */
7411 TM.tmFirstChar = 1;
7412 TM.tmLastChar = 255;
7413 TM.tmDefaultChar = 32;
7414 TM.tmBreakChar = 32;
7415 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
7416 TM.tmUnderlined = font->underline;
7417 TM.tmStruckOut = font->strikeout;
7418 /* NB inverted meaning of TMPF_FIXED_PITCH */
7419 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
7420 TM.tmCharSet = font->charset;
7422 #undef TM
7424 return TRUE;
7428 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
7430 double scale_x, scale_y;
7432 if (font->aveWidth)
7434 scale_x = (double)font->aveWidth;
7435 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7437 else
7438 scale_x = font->scale_y;
7440 scale_x *= fabs(font->font_desc.matrix.eM11);
7441 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7443 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7444 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7446 SCALE_Y(ptm->tmHeight);
7447 SCALE_Y(ptm->tmAscent);
7448 SCALE_Y(ptm->tmDescent);
7449 SCALE_Y(ptm->tmInternalLeading);
7450 SCALE_Y(ptm->tmExternalLeading);
7451 SCALE_Y(ptm->tmOverhang);
7453 SCALE_X(ptm->tmAveCharWidth);
7454 SCALE_X(ptm->tmMaxCharWidth);
7456 #undef SCALE_X
7457 #undef SCALE_Y
7460 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
7462 double scale_x, scale_y;
7464 if (font->aveWidth)
7466 scale_x = (double)font->aveWidth;
7467 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7469 else
7470 scale_x = font->scale_y;
7472 scale_x *= fabs(font->font_desc.matrix.eM11);
7473 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7475 scale_font_metrics(font, &potm->otmTextMetrics);
7477 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7478 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7480 SCALE_Y(potm->otmAscent);
7481 SCALE_Y(potm->otmDescent);
7482 SCALE_Y(potm->otmLineGap);
7483 SCALE_Y(potm->otmsCapEmHeight);
7484 SCALE_Y(potm->otmsXHeight);
7485 SCALE_Y(potm->otmrcFontBox.top);
7486 SCALE_Y(potm->otmrcFontBox.bottom);
7487 SCALE_X(potm->otmrcFontBox.left);
7488 SCALE_X(potm->otmrcFontBox.right);
7489 SCALE_Y(potm->otmMacAscent);
7490 SCALE_Y(potm->otmMacDescent);
7491 SCALE_Y(potm->otmMacLineGap);
7492 SCALE_X(potm->otmptSubscriptSize.x);
7493 SCALE_Y(potm->otmptSubscriptSize.y);
7494 SCALE_X(potm->otmptSubscriptOffset.x);
7495 SCALE_Y(potm->otmptSubscriptOffset.y);
7496 SCALE_X(potm->otmptSuperscriptSize.x);
7497 SCALE_Y(potm->otmptSuperscriptSize.y);
7498 SCALE_X(potm->otmptSuperscriptOffset.x);
7499 SCALE_Y(potm->otmptSuperscriptOffset.y);
7500 SCALE_Y(potm->otmsStrikeoutSize);
7501 SCALE_Y(potm->otmsStrikeoutPosition);
7502 SCALE_Y(potm->otmsUnderscoreSize);
7503 SCALE_Y(potm->otmsUnderscorePosition);
7505 #undef SCALE_X
7506 #undef SCALE_Y
7509 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
7511 if(!font->potm)
7513 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
7515 /* Make sure that the font has sane width/height ratio */
7516 if (font->aveWidth)
7518 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
7520 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
7521 font->aveWidth = 0;
7525 *ptm = font->potm->otmTextMetrics;
7526 scale_font_metrics(font, ptm);
7527 return TRUE;
7530 static BOOL face_has_symbol_charmap(FT_Face ft_face)
7532 int i;
7534 for(i = 0; i < ft_face->num_charmaps; i++)
7536 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
7537 return TRUE;
7539 return FALSE;
7542 static BOOL get_outline_text_metrics(GdiFont *font)
7544 BOOL ret = FALSE;
7545 FT_Face ft_face = font->ft_face;
7546 UINT needed, lenfam, lensty, lenface, lenfull;
7547 TT_OS2 *pOS2;
7548 TT_HoriHeader *pHori;
7549 TT_Postscript *pPost;
7550 FT_Fixed em_scale;
7551 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
7552 char *cp;
7553 INT ascent, descent;
7554 USHORT windescent;
7556 TRACE("font=%p\n", font);
7558 if(!FT_IS_SCALABLE(ft_face))
7559 return FALSE;
7561 needed = sizeof(*font->potm);
7563 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
7564 family_nameW = strdupW(font->name);
7566 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
7567 if (!style_nameW)
7569 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
7570 style_nameW = towstr( CP_ACP, ft_face->style_name );
7572 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
7574 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
7575 if (!face_nameW)
7577 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
7578 face_nameW = strdupW(font->name);
7580 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
7581 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
7583 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
7584 if (!full_nameW)
7586 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
7587 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
7588 full_nameW = strdupW(fake_nameW);
7590 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
7592 /* These names should be read from the TT name table */
7594 /* length of otmpFamilyName */
7595 needed += lenfam;
7597 /* length of otmpFaceName */
7598 needed += lenface;
7600 /* length of otmpStyleName */
7601 needed += lensty;
7603 /* length of otmpFullName */
7604 needed += lenfull;
7607 em_scale = (FT_Fixed)MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
7609 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
7610 if(!pOS2) {
7611 FIXME("Can't find OS/2 table - not TT font?\n");
7612 goto end;
7615 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
7616 if(!pHori) {
7617 FIXME("Can't find HHEA table - not TT font?\n");
7618 goto end;
7621 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
7623 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",
7624 pOS2->usWinAscent, pOS2->usWinDescent,
7625 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
7626 pOS2->xAvgCharWidth,
7627 ft_face->ascender, ft_face->descender, ft_face->height,
7628 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
7629 ft_face->bbox.yMax, ft_face->bbox.yMin);
7631 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
7632 font->potm->otmSize = needed;
7634 #define TM font->potm->otmTextMetrics
7636 windescent = get_fixed_windescent(pOS2->usWinDescent);
7637 if(pOS2->usWinAscent + windescent == 0) {
7638 ascent = pHori->Ascender;
7639 descent = -pHori->Descender;
7640 } else {
7641 ascent = pOS2->usWinAscent;
7642 descent = windescent;
7645 font->ntmCellHeight = ascent + descent;
7646 font->ntmAvgWidth = pOS2->xAvgCharWidth;
7648 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7649 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7651 if(font->yMax) {
7652 TM.tmAscent = font->yMax;
7653 TM.tmDescent = -font->yMin;
7654 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
7655 } else {
7656 TM.tmAscent = SCALE_Y(ascent);
7657 TM.tmDescent = SCALE_Y(descent);
7658 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
7661 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7663 /* MSDN says:
7664 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7666 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
7667 ((ascent + descent) -
7668 (pHori->Ascender - pHori->Descender))));
7670 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
7671 if (TM.tmAveCharWidth == 0) {
7672 TM.tmAveCharWidth = 1;
7674 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
7675 TM.tmWeight = FW_REGULAR;
7676 if (font->fake_bold) {
7677 TM.tmAveCharWidth++;
7678 TM.tmMaxCharWidth++;
7679 TM.tmWeight = FW_BOLD;
7681 else
7683 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
7685 if (pOS2->usWeightClass > FW_MEDIUM)
7686 TM.tmWeight = pOS2->usWeightClass;
7688 else if (pOS2->usWeightClass <= FW_MEDIUM)
7689 TM.tmWeight = pOS2->usWeightClass;
7691 TM.tmOverhang = 0;
7692 TM.tmDigitizedAspectX = 96; /* FIXME */
7693 TM.tmDigitizedAspectY = 96; /* FIXME */
7694 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7695 * symbol range to 0 - f0ff
7698 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
7700 TM.tmFirstChar = 0;
7701 switch(GetACP())
7703 case 1255: /* Hebrew */
7704 TM.tmLastChar = 0xf896;
7705 break;
7706 case 1257: /* Baltic */
7707 TM.tmLastChar = 0xf8fd;
7708 break;
7709 default:
7710 TM.tmLastChar = 0xf0ff;
7712 TM.tmBreakChar = 0x20;
7713 TM.tmDefaultChar = 0x1f;
7715 else
7717 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
7718 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
7720 if(pOS2->usFirstCharIndex <= 1)
7721 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
7722 else if (pOS2->usFirstCharIndex > 0xff)
7723 TM.tmBreakChar = 0x20;
7724 else
7725 TM.tmBreakChar = pOS2->usFirstCharIndex;
7726 TM.tmDefaultChar = TM.tmBreakChar - 1;
7728 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
7729 TM.tmUnderlined = font->underline;
7730 TM.tmStruckOut = font->strikeout;
7732 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7733 if(!FT_IS_FIXED_WIDTH(ft_face) &&
7734 (pOS2->version == 0xFFFFU ||
7735 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
7736 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
7737 else
7738 TM.tmPitchAndFamily = 0;
7740 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
7742 case PAN_FAMILY_SCRIPT:
7743 TM.tmPitchAndFamily |= FF_SCRIPT;
7744 break;
7746 case PAN_FAMILY_DECORATIVE:
7747 TM.tmPitchAndFamily |= FF_DECORATIVE;
7748 break;
7750 case PAN_ANY:
7751 case PAN_NO_FIT:
7752 case PAN_FAMILY_TEXT_DISPLAY:
7753 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
7754 /* which is clearly not what the panose spec says. */
7755 default:
7756 if(TM.tmPitchAndFamily == 0 || /* fixed */
7757 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
7758 TM.tmPitchAndFamily = FF_MODERN;
7759 else
7761 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
7763 case PAN_ANY:
7764 case PAN_NO_FIT:
7765 default:
7766 TM.tmPitchAndFamily |= FF_DONTCARE;
7767 break;
7769 case PAN_SERIF_COVE:
7770 case PAN_SERIF_OBTUSE_COVE:
7771 case PAN_SERIF_SQUARE_COVE:
7772 case PAN_SERIF_OBTUSE_SQUARE_COVE:
7773 case PAN_SERIF_SQUARE:
7774 case PAN_SERIF_THIN:
7775 case PAN_SERIF_BONE:
7776 case PAN_SERIF_EXAGGERATED:
7777 case PAN_SERIF_TRIANGLE:
7778 TM.tmPitchAndFamily |= FF_ROMAN;
7779 break;
7781 case PAN_SERIF_NORMAL_SANS:
7782 case PAN_SERIF_OBTUSE_SANS:
7783 case PAN_SERIF_PERP_SANS:
7784 case PAN_SERIF_FLARED:
7785 case PAN_SERIF_ROUNDED:
7786 TM.tmPitchAndFamily |= FF_SWISS;
7787 break;
7790 break;
7793 if(FT_IS_SCALABLE(ft_face))
7794 TM.tmPitchAndFamily |= TMPF_VECTOR;
7796 if(FT_IS_SFNT(ft_face))
7798 if (font->ntmFlags & NTM_PS_OPENTYPE)
7799 TM.tmPitchAndFamily |= TMPF_DEVICE;
7800 else
7801 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
7804 TM.tmCharSet = font->charset;
7806 font->potm->otmFiller = 0;
7807 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
7808 font->potm->otmfsSelection = pOS2->fsSelection;
7809 font->potm->otmfsType = pOS2->fsType;
7810 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
7811 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
7812 font->potm->otmItalicAngle = 0; /* POST table */
7813 font->potm->otmEMSquare = ft_face->units_per_EM;
7814 font->potm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
7815 font->potm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
7816 font->potm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
7817 font->potm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
7818 font->potm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
7819 font->potm->otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
7820 font->potm->otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
7821 font->potm->otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
7822 font->potm->otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
7823 font->potm->otmMacAscent = TM.tmAscent;
7824 font->potm->otmMacDescent = -TM.tmDescent;
7825 font->potm->otmMacLineGap = font->potm->otmLineGap;
7826 font->potm->otmusMinimumPPEM = 0; /* TT Header */
7827 font->potm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
7828 font->potm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
7829 font->potm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
7830 font->potm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
7831 font->potm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
7832 font->potm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
7833 font->potm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
7834 font->potm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
7835 font->potm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
7836 font->potm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
7837 if(!pPost) {
7838 font->potm->otmsUnderscoreSize = 0;
7839 font->potm->otmsUnderscorePosition = 0;
7840 } else {
7841 font->potm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
7842 font->potm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
7844 #undef SCALE_X
7845 #undef SCALE_Y
7846 #undef TM
7848 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7849 cp = (char*)font->potm + sizeof(*font->potm);
7850 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
7851 strcpyW((WCHAR*)cp, family_nameW);
7852 cp += lenfam;
7853 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
7854 strcpyW((WCHAR*)cp, style_nameW);
7855 cp += lensty;
7856 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7857 strcpyW((WCHAR*)cp, face_nameW);
7858 cp += lenface;
7859 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
7860 strcpyW((WCHAR*)cp, full_nameW);
7861 ret = TRUE;
7863 end:
7864 HeapFree(GetProcessHeap(), 0, style_nameW);
7865 HeapFree(GetProcessHeap(), 0, family_nameW);
7866 HeapFree(GetProcessHeap(), 0, face_nameW);
7867 HeapFree(GetProcessHeap(), 0, full_nameW);
7868 return ret;
7871 /*************************************************************
7872 * freetype_GetGlyphOutline
7874 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
7875 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7877 struct freetype_physdev *physdev = get_freetype_dev( dev );
7878 DWORD ret;
7879 ABC abc;
7881 if (!physdev->font)
7883 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
7884 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
7887 GDI_CheckNotLock();
7888 EnterCriticalSection( &freetype_cs );
7889 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
7890 LeaveCriticalSection( &freetype_cs );
7891 return ret;
7894 /*************************************************************
7895 * freetype_GetTextMetrics
7897 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
7899 struct freetype_physdev *physdev = get_freetype_dev( dev );
7900 BOOL ret;
7902 if (!physdev->font)
7904 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
7905 return dev->funcs->pGetTextMetrics( dev, metrics );
7908 GDI_CheckNotLock();
7909 EnterCriticalSection( &freetype_cs );
7910 ret = get_text_metrics( physdev->font, metrics );
7911 LeaveCriticalSection( &freetype_cs );
7912 return ret;
7915 /*************************************************************
7916 * freetype_GetOutlineTextMetrics
7918 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
7920 struct freetype_physdev *physdev = get_freetype_dev( dev );
7921 UINT ret = 0;
7923 if (!physdev->font)
7925 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
7926 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
7929 TRACE("font=%p\n", physdev->font);
7931 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
7933 GDI_CheckNotLock();
7934 EnterCriticalSection( &freetype_cs );
7936 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
7938 if(potm && cbSize >= physdev->font->potm->otmSize)
7940 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
7941 scale_outline_font_metrics(physdev->font, potm);
7943 ret = physdev->font->potm->otmSize;
7945 LeaveCriticalSection( &freetype_cs );
7946 return ret;
7949 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
7951 child->font = alloc_font();
7952 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
7953 if(!child->font->ft_face)
7955 free_font(child->font);
7956 child->font = NULL;
7957 return FALSE;
7960 child->font->font_desc = font->font_desc;
7961 child->font->ntmFlags = child->face->ntmFlags;
7962 child->font->orientation = font->orientation;
7963 child->font->scale_y = font->scale_y;
7964 child->font->name = strdupW(child->face->family->FamilyName);
7965 child->font->base_font = font;
7966 TRACE("created child font %p for base %p\n", child->font, font);
7967 return TRUE;
7970 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL* vert)
7972 FT_UInt g,o;
7973 CHILD_FONT *child_font;
7975 if(font->base_font)
7976 font = font->base_font;
7978 *linked_font = font;
7980 if((*glyph = get_glyph_index(font, c)))
7982 o = *glyph;
7983 *glyph = get_GSUB_vert_glyph(font, *glyph);
7984 *vert = (o != *glyph);
7985 return TRUE;
7988 if (c < 32) goto done; /* don't check linked fonts for control characters */
7990 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7992 if(!child_font->font)
7993 if(!load_child_font(font, child_font))
7994 continue;
7996 if(!child_font->font->ft_face)
7997 continue;
7998 g = get_glyph_index(child_font->font, c);
7999 o = g;
8000 g = get_GSUB_vert_glyph(child_font->font, g);
8001 if(g)
8003 *glyph = g;
8004 *linked_font = child_font->font;
8005 *vert = (o != g);
8006 return TRUE;
8010 done:
8011 *vert = FALSE;
8012 return FALSE;
8015 /*************************************************************
8016 * freetype_GetCharWidth
8018 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
8020 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8021 UINT c;
8022 GLYPHMETRICS gm;
8023 ABC abc;
8024 struct freetype_physdev *physdev = get_freetype_dev( dev );
8026 if (!physdev->font)
8028 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
8029 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
8032 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
8034 GDI_CheckNotLock();
8035 EnterCriticalSection( &freetype_cs );
8036 for(c = firstChar; c <= lastChar; c++) {
8037 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
8038 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
8040 LeaveCriticalSection( &freetype_cs );
8041 return TRUE;
8044 /*************************************************************
8045 * freetype_GetCharABCWidths
8047 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
8049 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8050 UINT c;
8051 GLYPHMETRICS gm;
8052 struct freetype_physdev *physdev = get_freetype_dev( dev );
8054 if (!physdev->font)
8056 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
8057 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
8060 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
8062 GDI_CheckNotLock();
8063 EnterCriticalSection( &freetype_cs );
8065 for(c = firstChar; c <= lastChar; c++, buffer++)
8066 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
8068 LeaveCriticalSection( &freetype_cs );
8069 return TRUE;
8072 /*************************************************************
8073 * freetype_GetCharABCWidthsI
8075 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
8077 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8078 UINT c;
8079 GLYPHMETRICS gm;
8080 struct freetype_physdev *physdev = get_freetype_dev( dev );
8082 if (!physdev->font)
8084 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
8085 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
8088 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
8089 return FALSE;
8091 GDI_CheckNotLock();
8092 EnterCriticalSection( &freetype_cs );
8094 for(c = 0; c < count; c++, buffer++)
8095 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
8096 &gm, buffer, 0, NULL, &identity );
8098 LeaveCriticalSection( &freetype_cs );
8099 return TRUE;
8102 /*************************************************************
8103 * freetype_GetTextExtentExPoint
8105 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
8107 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8108 INT idx, pos;
8109 ABC abc;
8110 GLYPHMETRICS gm;
8111 struct freetype_physdev *physdev = get_freetype_dev( dev );
8113 if (!physdev->font)
8115 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
8116 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
8119 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
8121 GDI_CheckNotLock();
8122 EnterCriticalSection( &freetype_cs );
8124 for (idx = pos = 0; idx < count; idx++)
8126 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
8127 pos += abc.abcA + abc.abcB + abc.abcC;
8128 dxs[idx] = pos;
8131 LeaveCriticalSection( &freetype_cs );
8132 return TRUE;
8135 /*************************************************************
8136 * freetype_GetTextExtentExPointI
8138 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
8140 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
8141 INT idx, pos;
8142 ABC abc;
8143 GLYPHMETRICS gm;
8144 struct freetype_physdev *physdev = get_freetype_dev( dev );
8146 if (!physdev->font)
8148 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
8149 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
8152 TRACE("%p, %p, %d\n", physdev->font, indices, count);
8154 GDI_CheckNotLock();
8155 EnterCriticalSection( &freetype_cs );
8157 for (idx = pos = 0; idx < count; idx++)
8159 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
8160 &gm, &abc, 0, NULL, &identity );
8161 pos += abc.abcA + abc.abcB + abc.abcC;
8162 dxs[idx] = pos;
8165 LeaveCriticalSection( &freetype_cs );
8166 return TRUE;
8169 /*************************************************************
8170 * freetype_GetFontData
8172 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
8174 struct freetype_physdev *physdev = get_freetype_dev( dev );
8176 if (!physdev->font)
8178 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
8179 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
8182 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
8183 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
8184 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
8186 return get_font_data( physdev->font, table, offset, buf, cbData );
8189 /*************************************************************
8190 * freetype_GetTextFace
8192 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
8194 INT n;
8195 struct freetype_physdev *physdev = get_freetype_dev( dev );
8197 if (!physdev->font)
8199 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
8200 return dev->funcs->pGetTextFace( dev, count, str );
8203 n = strlenW(physdev->font->name) + 1;
8204 if (str)
8206 lstrcpynW(str, physdev->font->name, count);
8207 n = min(count, n);
8209 return n;
8212 /*************************************************************
8213 * freetype_GetTextCharsetInfo
8215 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
8217 struct freetype_physdev *physdev = get_freetype_dev( dev );
8219 if (!physdev->font)
8221 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
8222 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
8224 if (fs) *fs = physdev->font->fs;
8225 return physdev->font->charset;
8228 /* Retrieve a list of supported Unicode ranges for a given font.
8229 * Can be called with NULL gs to calculate the buffer size. Returns
8230 * the number of ranges found.
8232 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
8234 DWORD num_ranges = 0;
8236 if (face->charmap->encoding == FT_ENCODING_UNICODE)
8238 FT_UInt glyph_code;
8239 FT_ULong char_code, char_code_prev;
8241 glyph_code = 0;
8242 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
8244 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
8245 face->num_glyphs, glyph_code, char_code);
8247 if (!glyph_code) return 0;
8249 if (gs)
8251 gs->ranges[0].wcLow = (USHORT)char_code;
8252 gs->ranges[0].cGlyphs = 0;
8253 gs->cGlyphsSupported = 0;
8256 num_ranges = 1;
8257 while (glyph_code)
8259 if (char_code < char_code_prev)
8261 ERR("expected increasing char code from FT_Get_Next_Char\n");
8262 return 0;
8264 if (char_code - char_code_prev > 1)
8266 num_ranges++;
8267 if (gs)
8269 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
8270 gs->ranges[num_ranges - 1].cGlyphs = 1;
8271 gs->cGlyphsSupported++;
8274 else if (gs)
8276 gs->ranges[num_ranges - 1].cGlyphs++;
8277 gs->cGlyphsSupported++;
8279 char_code_prev = char_code;
8280 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
8283 else
8284 FIXME("encoding %u not supported\n", face->charmap->encoding);
8286 return num_ranges;
8289 /*************************************************************
8290 * freetype_GetFontUnicodeRanges
8292 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
8294 struct freetype_physdev *physdev = get_freetype_dev( dev );
8295 DWORD size, num_ranges;
8297 if (!physdev->font)
8299 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
8300 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
8303 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
8304 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
8305 if (glyphset)
8307 glyphset->cbThis = size;
8308 glyphset->cRanges = num_ranges;
8309 glyphset->flAccel = 0;
8311 return size;
8314 /*************************************************************
8315 * freetype_FontIsLinked
8317 static BOOL freetype_FontIsLinked( PHYSDEV dev )
8319 struct freetype_physdev *physdev = get_freetype_dev( dev );
8320 BOOL ret;
8322 if (!physdev->font)
8324 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
8325 return dev->funcs->pFontIsLinked( dev );
8328 GDI_CheckNotLock();
8329 EnterCriticalSection( &freetype_cs );
8330 ret = !list_empty(&physdev->font->child_fonts);
8331 LeaveCriticalSection( &freetype_cs );
8332 return ret;
8335 /*************************************************************************
8336 * GetRasterizerCaps (GDI32.@)
8338 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8340 lprs->nSize = sizeof(RASTERIZER_STATUS);
8341 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
8342 lprs->nLanguageID = 0;
8343 return TRUE;
8346 /*************************************************************
8347 * freetype_GetFontRealizationInfo
8349 static BOOL freetype_GetFontRealizationInfo( PHYSDEV dev, void *ptr )
8351 struct freetype_physdev *physdev = get_freetype_dev( dev );
8352 struct font_realization_info *info = ptr;
8354 if (!physdev->font)
8356 dev = GET_NEXT_PHYSDEV( dev, pGetFontRealizationInfo );
8357 return dev->funcs->pGetFontRealizationInfo( dev, ptr );
8360 TRACE("(%p, %p)\n", physdev->font, info);
8362 info->flags = 1;
8363 if(FT_IS_SCALABLE(physdev->font->ft_face))
8364 info->flags |= 2;
8366 info->cache_num = physdev->font->cache_num;
8367 info->instance_id = physdev->font->instance_id;
8368 if (info->size == sizeof(*info))
8370 info->unk = 0;
8371 info->face_index = physdev->font->ft_face->face_index;
8372 info->simulations = 0;
8373 if (physdev->font->fake_bold)
8374 info->simulations |= 0x1;
8375 if (physdev->font->fake_italic)
8376 info->simulations |= 0x2;
8379 return TRUE;
8382 /*************************************************************************
8383 * GetFontFileInfo (GDI32.@)
8385 BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_fileinfo *info, DWORD size, DWORD *needed )
8387 struct font_handle_entry *entry = handle_entry( instance_id );
8388 const GdiFont *font;
8390 if (!entry)
8392 SetLastError(ERROR_INVALID_PARAMETER);
8393 return FALSE;
8396 font = entry->obj;
8397 *needed = sizeof(*info) + strlenW(font->fileinfo->path) * sizeof(WCHAR);
8398 if (*needed > size)
8400 SetLastError(ERROR_INSUFFICIENT_BUFFER);
8401 return FALSE;
8404 /* path is included too */
8405 memcpy(info, font->fileinfo, *needed);
8406 return TRUE;
8409 /*************************************************************************
8410 * Kerning support for TrueType fonts
8412 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
8414 struct TT_kern_table
8416 USHORT version;
8417 USHORT nTables;
8420 struct TT_kern_subtable
8422 USHORT version;
8423 USHORT length;
8424 union
8426 USHORT word;
8427 struct
8429 USHORT horizontal : 1;
8430 USHORT minimum : 1;
8431 USHORT cross_stream: 1;
8432 USHORT override : 1;
8433 USHORT reserved1 : 4;
8434 USHORT format : 8;
8435 } bits;
8436 } coverage;
8439 struct TT_format0_kern_subtable
8441 USHORT nPairs;
8442 USHORT searchRange;
8443 USHORT entrySelector;
8444 USHORT rangeShift;
8447 struct TT_kern_pair
8449 USHORT left;
8450 USHORT right;
8451 short value;
8454 static DWORD parse_format0_kern_subtable(GdiFont *font,
8455 const struct TT_format0_kern_subtable *tt_f0_ks,
8456 const USHORT *glyph_to_char,
8457 KERNINGPAIR *kern_pair, DWORD cPairs)
8459 USHORT i, nPairs;
8460 const struct TT_kern_pair *tt_kern_pair;
8462 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
8464 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
8466 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8467 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
8468 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
8470 if (!kern_pair || !cPairs)
8471 return nPairs;
8473 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
8475 nPairs = min(nPairs, cPairs);
8477 for (i = 0; i < nPairs; i++)
8479 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
8480 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
8481 /* this algorithm appears to better match what Windows does */
8482 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
8483 if (kern_pair->iKernAmount < 0)
8485 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
8486 kern_pair->iKernAmount -= font->ppem;
8488 else if (kern_pair->iKernAmount > 0)
8490 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
8491 kern_pair->iKernAmount += font->ppem;
8493 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
8495 TRACE("left %u right %u value %d\n",
8496 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
8498 kern_pair++;
8500 TRACE("copied %u entries\n", nPairs);
8501 return nPairs;
8504 /*************************************************************
8505 * freetype_GetKerningPairs
8507 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
8509 DWORD length;
8510 void *buf;
8511 const struct TT_kern_table *tt_kern_table;
8512 const struct TT_kern_subtable *tt_kern_subtable;
8513 USHORT i, nTables;
8514 USHORT *glyph_to_char;
8515 GdiFont *font;
8516 struct freetype_physdev *physdev = get_freetype_dev( dev );
8518 if (!(font = physdev->font))
8520 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
8521 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
8524 GDI_CheckNotLock();
8525 EnterCriticalSection( &freetype_cs );
8526 if (font->total_kern_pairs != (DWORD)-1)
8528 if (cPairs && kern_pair)
8530 cPairs = min(cPairs, font->total_kern_pairs);
8531 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8533 else cPairs = font->total_kern_pairs;
8535 LeaveCriticalSection( &freetype_cs );
8536 return cPairs;
8539 font->total_kern_pairs = 0;
8541 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
8543 if (length == GDI_ERROR)
8545 TRACE("no kerning data in the font\n");
8546 LeaveCriticalSection( &freetype_cs );
8547 return 0;
8550 buf = HeapAlloc(GetProcessHeap(), 0, length);
8551 if (!buf)
8553 WARN("Out of memory\n");
8554 LeaveCriticalSection( &freetype_cs );
8555 return 0;
8558 get_font_data(font, MS_KERN_TAG, 0, buf, length);
8560 /* build a glyph index to char code map */
8561 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
8562 if (!glyph_to_char)
8564 WARN("Out of memory allocating a glyph index to char code map\n");
8565 HeapFree(GetProcessHeap(), 0, buf);
8566 LeaveCriticalSection( &freetype_cs );
8567 return 0;
8570 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
8572 FT_UInt glyph_code;
8573 FT_ULong char_code;
8575 glyph_code = 0;
8576 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
8578 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
8579 font->ft_face->num_glyphs, glyph_code, char_code);
8581 while (glyph_code)
8583 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
8585 /* FIXME: This doesn't match what Windows does: it does some fancy
8586 * things with duplicate glyph index to char code mappings, while
8587 * we just avoid overriding existing entries.
8589 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
8590 glyph_to_char[glyph_code] = (USHORT)char_code;
8592 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
8595 else
8597 ULONG n;
8599 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
8600 for (n = 0; n <= 65535; n++)
8601 glyph_to_char[n] = (USHORT)n;
8604 tt_kern_table = buf;
8605 nTables = GET_BE_WORD(tt_kern_table->nTables);
8606 TRACE("version %u, nTables %u\n",
8607 GET_BE_WORD(tt_kern_table->version), nTables);
8609 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
8611 for (i = 0; i < nTables; i++)
8613 struct TT_kern_subtable tt_kern_subtable_copy;
8615 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
8616 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
8617 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
8619 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8620 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
8621 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
8623 /* According to the TrueType specification this is the only format
8624 * that will be properly interpreted by Windows and OS/2
8626 if (tt_kern_subtable_copy.coverage.bits.format == 0)
8628 DWORD new_chunk, old_total = font->total_kern_pairs;
8630 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8631 glyph_to_char, NULL, 0);
8632 font->total_kern_pairs += new_chunk;
8634 if (!font->kern_pairs)
8635 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
8636 font->total_kern_pairs * sizeof(*font->kern_pairs));
8637 else
8638 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
8639 font->total_kern_pairs * sizeof(*font->kern_pairs));
8641 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8642 glyph_to_char, font->kern_pairs + old_total, new_chunk);
8644 else
8645 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
8647 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
8650 HeapFree(GetProcessHeap(), 0, glyph_to_char);
8651 HeapFree(GetProcessHeap(), 0, buf);
8653 if (cPairs && kern_pair)
8655 cPairs = min(cPairs, font->total_kern_pairs);
8656 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8658 else cPairs = font->total_kern_pairs;
8660 LeaveCriticalSection( &freetype_cs );
8661 return cPairs;
8664 static const struct gdi_dc_funcs freetype_funcs =
8666 NULL, /* pAbortDoc */
8667 NULL, /* pAbortPath */
8668 NULL, /* pAlphaBlend */
8669 NULL, /* pAngleArc */
8670 NULL, /* pArc */
8671 NULL, /* pArcTo */
8672 NULL, /* pBeginPath */
8673 NULL, /* pBlendImage */
8674 NULL, /* pChord */
8675 NULL, /* pCloseFigure */
8676 NULL, /* pCreateCompatibleDC */
8677 freetype_CreateDC, /* pCreateDC */
8678 freetype_DeleteDC, /* pDeleteDC */
8679 NULL, /* pDeleteObject */
8680 NULL, /* pDeviceCapabilities */
8681 NULL, /* pEllipse */
8682 NULL, /* pEndDoc */
8683 NULL, /* pEndPage */
8684 NULL, /* pEndPath */
8685 freetype_EnumFonts, /* pEnumFonts */
8686 NULL, /* pEnumICMProfiles */
8687 NULL, /* pExcludeClipRect */
8688 NULL, /* pExtDeviceMode */
8689 NULL, /* pExtEscape */
8690 NULL, /* pExtFloodFill */
8691 NULL, /* pExtSelectClipRgn */
8692 NULL, /* pExtTextOut */
8693 NULL, /* pFillPath */
8694 NULL, /* pFillRgn */
8695 NULL, /* pFlattenPath */
8696 freetype_FontIsLinked, /* pFontIsLinked */
8697 NULL, /* pFrameRgn */
8698 NULL, /* pGdiComment */
8699 NULL, /* pGetBoundsRect */
8700 freetype_GetCharABCWidths, /* pGetCharABCWidths */
8701 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
8702 freetype_GetCharWidth, /* pGetCharWidth */
8703 NULL, /* pGetDeviceCaps */
8704 NULL, /* pGetDeviceGammaRamp */
8705 freetype_GetFontData, /* pGetFontData */
8706 freetype_GetFontRealizationInfo, /* pGetFontRealizationInfo */
8707 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
8708 freetype_GetGlyphIndices, /* pGetGlyphIndices */
8709 freetype_GetGlyphOutline, /* pGetGlyphOutline */
8710 NULL, /* pGetICMProfile */
8711 NULL, /* pGetImage */
8712 freetype_GetKerningPairs, /* pGetKerningPairs */
8713 NULL, /* pGetNearestColor */
8714 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
8715 NULL, /* pGetPixel */
8716 NULL, /* pGetSystemPaletteEntries */
8717 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
8718 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
8719 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
8720 freetype_GetTextFace, /* pGetTextFace */
8721 freetype_GetTextMetrics, /* pGetTextMetrics */
8722 NULL, /* pGradientFill */
8723 NULL, /* pIntersectClipRect */
8724 NULL, /* pInvertRgn */
8725 NULL, /* pLineTo */
8726 NULL, /* pModifyWorldTransform */
8727 NULL, /* pMoveTo */
8728 NULL, /* pOffsetClipRgn */
8729 NULL, /* pOffsetViewportOrg */
8730 NULL, /* pOffsetWindowOrg */
8731 NULL, /* pPaintRgn */
8732 NULL, /* pPatBlt */
8733 NULL, /* pPie */
8734 NULL, /* pPolyBezier */
8735 NULL, /* pPolyBezierTo */
8736 NULL, /* pPolyDraw */
8737 NULL, /* pPolyPolygon */
8738 NULL, /* pPolyPolyline */
8739 NULL, /* pPolygon */
8740 NULL, /* pPolyline */
8741 NULL, /* pPolylineTo */
8742 NULL, /* pPutImage */
8743 NULL, /* pRealizeDefaultPalette */
8744 NULL, /* pRealizePalette */
8745 NULL, /* pRectangle */
8746 NULL, /* pResetDC */
8747 NULL, /* pRestoreDC */
8748 NULL, /* pRoundRect */
8749 NULL, /* pSaveDC */
8750 NULL, /* pScaleViewportExt */
8751 NULL, /* pScaleWindowExt */
8752 NULL, /* pSelectBitmap */
8753 NULL, /* pSelectBrush */
8754 NULL, /* pSelectClipPath */
8755 freetype_SelectFont, /* pSelectFont */
8756 NULL, /* pSelectPalette */
8757 NULL, /* pSelectPen */
8758 NULL, /* pSetArcDirection */
8759 NULL, /* pSetBkColor */
8760 NULL, /* pSetBkMode */
8761 NULL, /* pSetDCBrushColor */
8762 NULL, /* pSetDCPenColor */
8763 NULL, /* pSetDIBColorTable */
8764 NULL, /* pSetDIBitsToDevice */
8765 NULL, /* pSetDeviceClipping */
8766 NULL, /* pSetDeviceGammaRamp */
8767 NULL, /* pSetLayout */
8768 NULL, /* pSetMapMode */
8769 NULL, /* pSetMapperFlags */
8770 NULL, /* pSetPixel */
8771 NULL, /* pSetPolyFillMode */
8772 NULL, /* pSetROP2 */
8773 NULL, /* pSetRelAbs */
8774 NULL, /* pSetStretchBltMode */
8775 NULL, /* pSetTextAlign */
8776 NULL, /* pSetTextCharacterExtra */
8777 NULL, /* pSetTextColor */
8778 NULL, /* pSetTextJustification */
8779 NULL, /* pSetViewportExt */
8780 NULL, /* pSetViewportOrg */
8781 NULL, /* pSetWindowExt */
8782 NULL, /* pSetWindowOrg */
8783 NULL, /* pSetWorldTransform */
8784 NULL, /* pStartDoc */
8785 NULL, /* pStartPage */
8786 NULL, /* pStretchBlt */
8787 NULL, /* pStretchDIBits */
8788 NULL, /* pStrokeAndFillPath */
8789 NULL, /* pStrokePath */
8790 NULL, /* pUnrealizePalette */
8791 NULL, /* pWidenPath */
8792 NULL, /* wine_get_wgl_driver */
8793 GDI_PRIORITY_FONT_DRV /* priority */
8796 #else /* HAVE_FREETYPE */
8798 struct font_fileinfo;
8800 /*************************************************************************/
8802 BOOL WineEngInit(void)
8804 return FALSE;
8807 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8809 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8810 return 1;
8813 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8815 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8816 return TRUE;
8819 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
8821 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
8822 return NULL;
8825 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
8826 LPCWSTR font_file, LPCWSTR font_path )
8828 FIXME("stub\n");
8829 return FALSE;
8832 /*************************************************************************
8833 * GetRasterizerCaps (GDI32.@)
8835 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8837 lprs->nSize = sizeof(RASTERIZER_STATUS);
8838 lprs->wFlags = 0;
8839 lprs->nLanguageID = 0;
8840 return TRUE;
8843 /*************************************************************************
8844 * GetFontFileInfo (GDI32.@)
8846 BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_fileinfo *info, DWORD size, DWORD *needed)
8848 *needed = 0;
8849 return FALSE;
8852 #endif /* HAVE_FREETYPE */