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
25 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.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>
62 #undef GetCurrentThread
65 #undef GetCurrentProcess
78 #endif /* HAVE_CARBON_CARBON_H */
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
92 WINE_DEFAULT_DEBUG_CHANNEL(font);
96 #ifdef HAVE_FT2BUILD_H
99 #ifdef HAVE_FREETYPE_FREETYPE_H
100 #include <freetype/freetype.h>
102 #ifdef HAVE_FREETYPE_FTGLYPH_H
103 #include <freetype/ftglyph.h>
105 #ifdef HAVE_FREETYPE_TTTABLES_H
106 #include <freetype/tttables.h>
108 #ifdef HAVE_FREETYPE_FTTYPES_H
109 #include <freetype/fttypes.h>
111 #ifdef HAVE_FREETYPE_FTSNAMES_H
112 #include <freetype/ftsnames.h>
114 #ifdef HAVE_FREETYPE_TTNAMEID_H
115 #include <freetype/ttnameid.h>
117 #ifdef HAVE_FREETYPE_FTOUTLN_H
118 #include <freetype/ftoutln.h>
120 #ifdef HAVE_FREETYPE_FTTRIGON_H
121 #include <freetype/fttrigon.h>
123 #ifdef HAVE_FREETYPE_FTWINFNT_H
124 #include <freetype/ftwinfnt.h>
126 #ifdef HAVE_FREETYPE_FTMODAPI_H
127 #include <freetype/ftmodapi.h>
129 #ifdef HAVE_FREETYPE_FTLCDFIL_H
130 #include <freetype/ftlcdfil.h>
133 #ifndef HAVE_FT_TRUETYPEENGINETYPE
136 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
137 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
138 FT_TRUETYPE_ENGINE_TYPE_PATENTED
139 } FT_TrueTypeEngineType;
142 static FT_Library library = 0;
149 static FT_Version_t FT_Version;
150 static DWORD FT_SimpleVersion;
152 static void *ft_handle = NULL;
154 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
155 MAKE_FUNCPTR(FT_Done_Face);
156 MAKE_FUNCPTR(FT_Get_Char_Index);
157 MAKE_FUNCPTR(FT_Get_First_Char);
158 MAKE_FUNCPTR(FT_Get_Module);
159 MAKE_FUNCPTR(FT_Get_Next_Char);
160 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
163 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
164 MAKE_FUNCPTR(FT_Init_FreeType);
165 MAKE_FUNCPTR(FT_Library_Version);
166 MAKE_FUNCPTR(FT_Load_Glyph);
167 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
168 MAKE_FUNCPTR(FT_Matrix_Multiply);
169 #ifdef FT_MULFIX_INLINED
170 #define pFT_MulFix FT_MULFIX_INLINED
172 MAKE_FUNCPTR(FT_MulFix);
174 MAKE_FUNCPTR(FT_New_Face);
175 MAKE_FUNCPTR(FT_New_Memory_Face);
176 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
177 MAKE_FUNCPTR(FT_Outline_Transform);
178 MAKE_FUNCPTR(FT_Outline_Translate);
179 MAKE_FUNCPTR(FT_Render_Glyph);
180 MAKE_FUNCPTR(FT_Select_Charmap);
181 MAKE_FUNCPTR(FT_Set_Charmap);
182 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
183 MAKE_FUNCPTR(FT_Vector_Transform);
184 MAKE_FUNCPTR(FT_Vector_Unit);
185 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
186 #ifdef HAVE_FREETYPE_FTLCDFIL_H
187 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
190 #ifdef SONAME_LIBFONTCONFIG
191 #include <fontconfig/fontconfig.h>
192 MAKE_FUNCPTR(FcConfigGetCurrent);
193 MAKE_FUNCPTR(FcFontList);
194 MAKE_FUNCPTR(FcFontSetDestroy);
195 MAKE_FUNCPTR(FcInit);
196 MAKE_FUNCPTR(FcObjectSetAdd);
197 MAKE_FUNCPTR(FcObjectSetCreate);
198 MAKE_FUNCPTR(FcObjectSetDestroy);
199 MAKE_FUNCPTR(FcPatternCreate);
200 MAKE_FUNCPTR(FcPatternDestroy);
201 MAKE_FUNCPTR(FcPatternGetBool);
202 MAKE_FUNCPTR(FcPatternGetString);
208 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
209 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
210 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
213 #ifndef ft_encoding_none
214 #define FT_ENCODING_NONE ft_encoding_none
216 #ifndef ft_encoding_ms_symbol
217 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
219 #ifndef ft_encoding_unicode
220 #define FT_ENCODING_UNICODE ft_encoding_unicode
222 #ifndef ft_encoding_apple_roman
223 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
226 #ifdef WORDS_BIGENDIAN
227 #define GET_BE_WORD(x) (x)
229 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
232 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
239 FT_Short internal_leading;
242 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
243 So to let this compile on older versions of FreeType we'll define the
244 new structure here. */
246 FT_Short height, width;
247 FT_Pos size, x_ppem, y_ppem;
253 NEWTEXTMETRICEXW ntm;
257 typedef struct tagFace {
263 DWORD font_data_size;
266 FONTSIGNATURE fs_links;
268 FT_Fixed font_version;
270 Bitmap_Size size; /* set if face is a bitmap */
271 BOOL external; /* TRUE if we should manually add this font to the registry */
272 struct tagFamily *family;
273 /* Cached data for Enum */
274 struct enum_data *cached_enum_data;
277 typedef struct tagFamily {
279 const WCHAR *FamilyName;
280 const WCHAR *EnglishName;
286 INT adv; /* These three hold to widths of the unrotated chars */
304 typedef struct tagHFONTLIST {
319 struct list hfontlist;
320 OUTLINETEXTMETRICW *potm;
321 DWORD total_kern_pairs;
322 KERNINGPAIR *kern_pairs;
323 struct list child_fonts;
325 /* the following members can be accessed without locking, they are never modified after creation */
327 struct font_mapping *mapping;
350 const WCHAR *font_name;
354 struct enum_charset_element {
360 struct enum_charset_list {
362 struct enum_charset_element element[32];
365 #define GM_BLOCK_SIZE 128
366 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
368 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
369 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
370 #define UNUSED_CACHE_SIZE 10
371 static struct list child_font_list = LIST_INIT(child_font_list);
372 static struct list system_links = LIST_INIT(system_links);
374 static struct list font_subst_list = LIST_INIT(font_subst_list);
376 static struct list font_list = LIST_INIT(font_list);
378 struct freetype_physdev
380 struct gdi_physdev dev;
384 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
386 return (struct freetype_physdev *)dev;
389 static const struct gdi_dc_funcs freetype_funcs;
391 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
392 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
393 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
395 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
396 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
397 'W','i','n','d','o','w','s','\\',
398 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
399 'F','o','n','t','s','\0'};
401 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
402 'W','i','n','d','o','w','s',' ','N','T','\\',
403 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
404 'F','o','n','t','s','\0'};
406 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
407 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
408 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
409 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
411 static const WCHAR * const SystemFontValues[4] = {
418 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
419 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
421 /* Interesting and well-known (frequently-assumed!) font names */
422 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
423 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 };
424 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
425 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
426 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
427 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
428 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
429 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
431 static const WCHAR arial[] = {'A','r','i','a','l',0};
432 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
433 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};
434 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};
435 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
436 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
437 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
438 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
439 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
441 static const WCHAR *default_serif_list[] =
445 bitstream_vera_serif,
449 static const WCHAR *default_fixed_list[] =
453 bitstream_vera_sans_mono,
457 static const WCHAR *default_sans_list[] =
466 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
467 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
468 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
469 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
470 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
471 'E','u','r','o','p','e','a','n','\0'};
472 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
473 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
474 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
475 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
476 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
477 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
478 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
479 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
480 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
481 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
482 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
483 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
485 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
495 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
503 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
512 typedef struct tagFontSubst {
518 /* Registry font cache key and value names */
519 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
520 'F','o','n','t','s',0};
521 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
522 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
523 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
524 static const WCHAR face_italic_value[] = {'I','t','a','l','i','c',0};
525 static const WCHAR face_bold_value[] = {'B','o','l','d',0};
526 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
527 static const WCHAR face_external_value[] = {'E','x','t','e','r','n','a','l',0};
528 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
529 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
530 static const WCHAR face_size_value[] = {'S','i','z','e',0};
531 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
532 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
533 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
534 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
535 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
548 static struct list mappings_list = LIST_INIT( mappings_list );
550 static CRITICAL_SECTION freetype_cs;
551 static CRITICAL_SECTION_DEBUG critsect_debug =
554 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
555 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
557 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
559 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
561 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
562 static BOOL use_default_fallback = FALSE;
564 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
566 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
567 'W','i','n','d','o','w','s',' ','N','T','\\',
568 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
569 'S','y','s','t','e','m','L','i','n','k',0};
571 /****************************************
572 * Notes on .fon files
574 * The fonts System, FixedSys and Terminal are special. There are typically multiple
575 * versions installed for different resolutions and codepages. Windows stores which one to use
576 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
578 * FIXEDFON.FON FixedSys
580 * OEMFONT.FON Terminal
581 * LogPixels Current dpi set by the display control panel applet
582 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
583 * also has a LogPixels value that appears to mirror this)
585 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
586 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
587 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
588 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
589 * so that makes sense.
591 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
592 * to be mapped into the registry on Windows 2000 at least).
595 * ega80woa.fon=ega80850.fon
596 * ega40woa.fon=ega40850.fon
597 * cga80woa.fon=cga80850.fon
598 * cga40woa.fon=cga40850.fon
601 /* These are all structures needed for the GSUB table */
603 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
604 #define TATEGAKI_LOWER_BOUND 0x02F1
620 GSUB_ScriptRecord ScriptRecord[1];
626 } GSUB_LangSysRecord;
631 GSUB_LangSysRecord LangSysRecord[1];
635 WORD LookupOrder; /* Reserved */
636 WORD ReqFeatureIndex;
638 WORD FeatureIndex[1];
644 } GSUB_FeatureRecord;
648 GSUB_FeatureRecord FeatureRecord[1];
652 WORD FeatureParams; /* Reserved */
654 WORD LookupListIndex[1];
673 } GSUB_CoverageFormat1;
678 WORD StartCoverageIndex;
684 GSUB_RangeRecord RangeRecord[1];
685 } GSUB_CoverageFormat2;
688 WORD SubstFormat; /* = 1 */
691 } GSUB_SingleSubstFormat1;
694 WORD SubstFormat; /* = 2 */
698 }GSUB_SingleSubstFormat2;
700 #ifdef HAVE_CARBON_CARBON_H
701 static char *find_cache_dir(void)
705 static char cached_path[MAX_PATH];
706 static const char *wine = "/Wine", *fonts = "/Fonts";
708 if(*cached_path) return cached_path;
710 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
713 WARN("can't create cached data folder\n");
716 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
719 WARN("can't create cached data path\n");
723 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
725 ERR("Could not create full path\n");
729 strcat(cached_path, wine);
731 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
733 WARN("Couldn't mkdir %s\n", cached_path);
737 strcat(cached_path, fonts);
738 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
740 WARN("Couldn't mkdir %s\n", cached_path);
747 /******************************************************************
750 * Extracts individual TrueType font files from a Mac suitcase font
751 * and saves them into the user's caches directory (see
753 * Returns a NULL terminated array of filenames.
755 * We do this because they are apps that try to read ttf files
756 * themselves and they don't like Mac suitcase files.
758 static char **expand_mac_font(const char *path)
765 const char *filename;
769 unsigned int size, max_size;
772 TRACE("path %s\n", path);
774 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
777 WARN("failed to get ref\n");
781 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
784 TRACE("no data fork, so trying resource fork\n");
785 res_ref = FSOpenResFile(&ref, fsRdPerm);
788 TRACE("unable to open resource fork\n");
795 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
798 CloseResFile(res_ref);
802 out_dir = find_cache_dir();
804 filename = strrchr(path, '/');
805 if(!filename) filename = path;
808 /* output filename has the form out_dir/filename_%04x.ttf */
809 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
816 unsigned short *num_faces_ptr, num_faces, face;
819 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
821 fond = Get1IndResource(fond_res, idx);
823 TRACE("got fond resource %d\n", idx);
826 fam_rec = *(FamRec**)fond;
827 num_faces_ptr = (unsigned short *)(fam_rec + 1);
828 num_faces = GET_BE_WORD(*num_faces_ptr);
830 assoc = (AsscEntry*)(num_faces_ptr + 1);
831 TRACE("num faces %04x\n", num_faces);
832 for(face = 0; face < num_faces; face++, assoc++)
835 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
836 unsigned short size, font_id;
839 size = GET_BE_WORD(assoc->fontSize);
840 font_id = GET_BE_WORD(assoc->fontID);
843 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
847 TRACE("trying to load sfnt id %04x\n", font_id);
848 sfnt = GetResource(sfnt_res, font_id);
851 TRACE("can't get sfnt resource %04x\n", font_id);
855 output = HeapAlloc(GetProcessHeap(), 0, output_len);
860 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
862 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
863 if(fd != -1 || errno == EEXIST)
867 unsigned char *sfnt_data;
870 sfnt_data = *(unsigned char**)sfnt;
871 write(fd, sfnt_data, GetHandleSize(sfnt));
875 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
878 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
880 ret.array[ret.size++] = output;
884 WARN("unable to create %s\n", output);
885 HeapFree(GetProcessHeap(), 0, output);
888 ReleaseResource(sfnt);
891 ReleaseResource(fond);
894 CloseResFile(res_ref);
899 #endif /* HAVE_CARBON_CARBON_H */
901 static inline BOOL is_win9x(void)
903 return GetVersion() & 0x80000000;
906 This function builds an FT_Fixed from a double. It fails if the absolute
907 value of the float number is greater than 32768.
909 static inline FT_Fixed FT_FixedFromFloat(double f)
915 This function builds an FT_Fixed from a FIXED. It simply put f.value
916 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
918 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
920 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
924 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
929 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
930 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
932 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
933 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
935 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
937 if(face_name && strcmpiW(face_name, family->FamilyName))
939 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
943 file = strrchr(face->file, '/');
948 if(!strcasecmp(file, file_nameA))
950 HeapFree(GetProcessHeap(), 0, file_nameA);
955 HeapFree(GetProcessHeap(), 0, file_nameA);
959 static Family *find_family_from_name(const WCHAR *name)
963 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
965 if(!strcmpiW(family->FamilyName, name))
972 static void DumpSubstList(void)
976 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
978 if(psub->from.charset != -1 || psub->to.charset != -1)
979 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
980 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
982 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
983 debugstr_w(psub->to.name));
988 static LPWSTR strdupW(LPCWSTR p)
991 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
992 ret = HeapAlloc(GetProcessHeap(), 0, len);
997 static LPSTR strdupA(LPCSTR p)
1000 DWORD len = (strlen(p) + 1);
1001 ret = HeapAlloc(GetProcessHeap(), 0, len);
1002 memcpy(ret, p, len);
1006 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1011 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1013 if(!strcmpiW(element->from.name, from_name) &&
1014 (element->from.charset == from_charset ||
1015 element->from.charset == -1))
1022 #define ADD_FONT_SUBST_FORCE 1
1024 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1026 FontSubst *from_exist, *to_exist;
1028 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1030 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1032 list_remove(&from_exist->entry);
1033 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
1034 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
1035 HeapFree(GetProcessHeap(), 0, from_exist);
1041 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1045 HeapFree(GetProcessHeap(), 0, subst->to.name);
1046 subst->to.name = strdupW(to_exist->to.name);
1049 list_add_tail(subst_list, &subst->entry);
1054 HeapFree(GetProcessHeap(), 0, subst->from.name);
1055 HeapFree(GetProcessHeap(), 0, subst->to.name);
1056 HeapFree(GetProcessHeap(), 0, subst);
1060 static void split_subst_info(NameCs *nc, LPSTR str)
1062 CHAR *p = strrchr(str, ',');
1067 nc->charset = strtol(p+1, NULL, 10);
1070 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
1071 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1072 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
1075 static void LoadSubstList(void)
1079 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1083 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1084 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1085 &hkey) == ERROR_SUCCESS) {
1087 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1088 &valuelen, &datalen, NULL, NULL);
1090 valuelen++; /* returned value doesn't include room for '\0' */
1091 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1092 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1096 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1097 &dlen) == ERROR_SUCCESS) {
1098 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1100 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1101 split_subst_info(&psub->from, value);
1102 split_subst_info(&psub->to, data);
1104 /* Win 2000 doesn't allow mapping between different charsets
1105 or mapping of DEFAULT_CHARSET */
1106 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1107 psub->to.charset == DEFAULT_CHARSET) {
1108 HeapFree(GetProcessHeap(), 0, psub->to.name);
1109 HeapFree(GetProcessHeap(), 0, psub->from.name);
1110 HeapFree(GetProcessHeap(), 0, psub);
1112 add_font_subst(&font_subst_list, psub, 0);
1114 /* reset dlen and vlen */
1118 HeapFree(GetProcessHeap(), 0, data);
1119 HeapFree(GetProcessHeap(), 0, value);
1125 /*****************************************************************
1126 * get_name_table_entry
1128 * Supply the platform, encoding, language and name ids in req
1129 * and if the name exists the function will fill in the string
1130 * and string_len members. The string is owned by FreeType so
1131 * don't free it. Returns TRUE if the name is found else FALSE.
1133 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1136 FT_UInt num_names, name_index;
1138 if(FT_IS_SFNT(ft_face))
1140 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1142 for(name_index = 0; name_index < num_names; name_index++)
1144 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1146 if((name.platform_id == req->platform_id) &&
1147 (name.encoding_id == req->encoding_id) &&
1148 (name.language_id == req->language_id) &&
1149 (name.name_id == req->name_id))
1151 req->string = name.string;
1152 req->string_len = name.string_len;
1159 req->string_len = 0;
1163 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1168 name.platform_id = TT_PLATFORM_MICROSOFT;
1169 name.encoding_id = TT_MS_ID_UNICODE_CS;
1170 name.language_id = language_id;
1171 name.name_id = name_id;
1173 if(get_name_table_entry(ft_face, &name))
1177 /* String is not nul terminated and string_len is a byte length. */
1178 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1179 for(i = 0; i < name.string_len / 2; i++)
1181 WORD *tmp = (WORD *)&name.string[i * 2];
1182 ret[i] = GET_BE_WORD(*tmp);
1185 TRACE("Got localised name %s\n", debugstr_w(ret));
1191 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1194 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1195 if(r != ERROR_SUCCESS) return r;
1196 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1197 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1200 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1202 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1205 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1208 DWORD num_strikes, max_strike_key_len;
1210 /* If we have a File Name key then this is a real font, not just the parent
1211 key of a bunch of non-scalable strikes */
1212 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1216 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1217 face->cached_enum_data = NULL;
1219 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1220 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1222 face->StyleName = strdupW(face_name);
1223 face->family = family;
1225 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1227 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1228 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1229 face->FullName = fullName;
1232 face->FullName = NULL;
1234 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1235 reg_load_dword(hkey_face, face_italic_value, &italic);
1236 reg_load_dword(hkey_face, face_bold_value, &bold);
1237 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1238 reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external);
1240 needed = sizeof(face->fs);
1241 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1242 memset(&face->fs_links, 0, sizeof(face->fs_links));
1244 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1246 face->scalable = TRUE;
1247 memset(&face->size, 0, sizeof(face->size));
1251 face->scalable = FALSE;
1252 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1253 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1254 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1255 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1256 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1258 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1259 face->size.height, face->size.width, face->size.size >> 6,
1260 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1264 if (italic) face->ntmFlags |= NTM_ITALIC;
1265 if (bold) face->ntmFlags |= NTM_BOLD;
1266 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1268 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1269 face->fs.fsCsb[0], face->fs.fsCsb[1],
1270 face->fs.fsUsb[0], face->fs.fsUsb[1],
1271 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1273 if(!italic && !bold)
1274 list_add_head(&family->faces, &face->entry);
1276 list_add_tail(&family->faces, &face->entry);
1278 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1281 /* do we have any bitmap strikes? */
1282 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1283 NULL, NULL, NULL, NULL);
1284 if(num_strikes != 0)
1286 WCHAR strike_name[10];
1287 DWORD strike_index = 0;
1289 needed = sizeof(strike_name) / sizeof(WCHAR);
1290 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1291 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1294 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1295 load_face(hkey_strike, face_name, family);
1296 RegCloseKey(hkey_strike);
1297 needed = sizeof(strike_name) / sizeof(WCHAR);
1302 static void load_font_list_from_cache(HKEY hkey_font_cache)
1304 DWORD max_family_key_len, size;
1306 DWORD family_index = 0;
1310 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1311 NULL, NULL, NULL, NULL);
1312 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1314 size = max_family_key_len + 1;
1315 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1316 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1318 WCHAR *english_family = NULL;
1319 DWORD face_index = 0;
1321 DWORD max_face_key_len;
1323 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1324 TRACE("opened family key %s\n", debugstr_w(family_name));
1325 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1327 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1328 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1331 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1332 family->FamilyName = strdupW(family_name);
1333 family->EnglishName = english_family;
1334 list_init(&family->faces);
1335 list_add_tail(&font_list, &family->entry);
1339 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1340 subst->from.name = strdupW(english_family);
1341 subst->from.charset = -1;
1342 subst->to.name = strdupW(family_name);
1343 subst->to.charset = -1;
1344 add_font_subst(&font_subst_list, subst, 0);
1347 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1348 NULL, NULL, NULL, NULL);
1350 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1351 size = max_face_key_len + 1;
1352 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1353 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1357 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1358 load_face(hkey_face, face_name, family);
1359 RegCloseKey(hkey_face);
1360 size = max_face_key_len + 1;
1362 HeapFree(GetProcessHeap(), 0, face_name);
1363 RegCloseKey(hkey_family);
1364 size = max_family_key_len + 1;
1367 HeapFree(GetProcessHeap(), 0, family_name);
1370 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1373 HKEY hkey_wine_fonts;
1375 /* We don't want to create the fonts key as volatile, so open this first */
1376 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1377 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1378 if(ret != ERROR_SUCCESS)
1380 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1384 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1385 KEY_ALL_ACCESS, NULL, hkey, disposition);
1386 RegCloseKey(hkey_wine_fonts);
1390 static void add_face_to_cache(Face *face)
1392 HKEY hkey_font_cache, hkey_family, hkey_face;
1393 WCHAR *face_key_name;
1395 create_font_cache_key(&hkey_font_cache, NULL);
1397 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1398 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1399 if(face->family->EnglishName)
1400 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1401 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1404 face_key_name = face->StyleName;
1407 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1408 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1409 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1411 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1414 HeapFree(GetProcessHeap(), 0, face_key_name);
1416 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1418 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1419 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1421 reg_save_dword(hkey_face, face_index_value, face->face_index);
1422 reg_save_dword(hkey_face, face_italic_value, (face->ntmFlags & NTM_ITALIC) != 0);
1423 reg_save_dword(hkey_face, face_bold_value, (face->ntmFlags & NTM_BOLD) != 0);
1424 reg_save_dword(hkey_face, face_version_value, face->font_version);
1425 reg_save_dword(hkey_face, face_external_value, face->external);
1427 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1431 reg_save_dword(hkey_face, face_height_value, face->size.height);
1432 reg_save_dword(hkey_face, face_width_value, face->size.width);
1433 reg_save_dword(hkey_face, face_size_value, face->size.size);
1434 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1435 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1436 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1438 RegCloseKey(hkey_face);
1439 RegCloseKey(hkey_family);
1440 RegCloseKey(hkey_font_cache);
1443 static inline int TestStyles(DWORD flags, DWORD styles)
1445 return (flags & styles) == styles;
1448 static int StyleOrdering(Face *face)
1450 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1452 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1454 if (TestStyles(face->ntmFlags, NTM_BOLD))
1456 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1459 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1460 debugstr_w(face->family->FamilyName),
1461 debugstr_w(face->StyleName),
1467 /* Add a style of face to a font family using an ordering of the list such
1468 that regular fonts come before bold and italic, and single styles come
1469 before compound styles. */
1470 static void AddFaceToFamily(Face *face, Family *family)
1474 LIST_FOR_EACH( entry, &family->faces )
1476 Face *ent = LIST_ENTRY(entry, Face, entry);
1477 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1479 list_add_before( entry, &face->entry );
1482 #define ADDFONT_EXTERNAL_FONT 0x01
1483 #define ADDFONT_FORCE_BITMAP 0x02
1484 #define ADDFONT_ADD_TO_CACHE 0x04
1486 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1490 TT_Header *pHeader = NULL;
1491 WCHAR *english_family, *localised_family, *StyleW;
1495 struct list *family_elem_ptr, *face_elem_ptr;
1497 FT_Long face_index = 0, num_faces;
1498 FT_WinFNT_HeaderRec winfnt_header;
1499 int i, bitmap_num, internal_leading;
1502 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1503 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1505 #ifdef HAVE_CARBON_CARBON_H
1506 if(file && !fake_family)
1508 char **mac_list = expand_mac_font(file);
1511 BOOL had_one = FALSE;
1513 for(cursor = mac_list; *cursor; cursor++)
1516 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1517 HeapFree(GetProcessHeap(), 0, *cursor);
1519 HeapFree(GetProcessHeap(), 0, mac_list);
1524 #endif /* HAVE_CARBON_CARBON_H */
1527 char *family_name = fake_family;
1531 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1532 err = pFT_New_Face(library, file, face_index, &ft_face);
1535 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1536 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1540 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1544 if(!FT_IS_SFNT(ft_face) && (FT_IS_SCALABLE(ft_face) || !(flags & ADDFONT_FORCE_BITMAP))) { /* for now we'll accept TT/OT or bitmap fonts*/
1545 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1546 pFT_Done_Face(ft_face);
1550 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1551 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1552 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1553 pFT_Done_Face(ft_face);
1557 if(FT_IS_SFNT(ft_face))
1559 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1560 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1561 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1563 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1564 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1565 pFT_Done_Face(ft_face);
1569 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1570 we don't want to load these. */
1571 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1575 if(!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1577 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1578 pFT_Done_Face(ft_face);
1584 if(!ft_face->family_name || !ft_face->style_name) {
1585 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1586 pFT_Done_Face(ft_face);
1590 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1592 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1593 pFT_Done_Face(ft_face);
1599 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1600 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1602 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1603 HeapFree(GetProcessHeap(), 0, localised_family);
1604 num_faces = ft_face->num_faces;
1605 pFT_Done_Face(ft_face);
1608 HeapFree(GetProcessHeap(), 0, localised_family);
1612 family_name = ft_face->family_name;
1616 My_FT_Bitmap_Size *size = NULL;
1619 if(!FT_IS_SCALABLE(ft_face))
1620 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1622 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1623 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1624 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1626 localised_family = NULL;
1628 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1629 if(localised_family && !strcmpiW(localised_family, english_family)) {
1630 HeapFree(GetProcessHeap(), 0, localised_family);
1631 localised_family = NULL;
1636 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1637 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1638 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1643 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1644 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1645 family->EnglishName = localised_family ? strdupW(english_family) : NULL;
1646 list_init(&family->faces);
1647 list_add_tail(&font_list, &family->entry);
1649 if(localised_family) {
1650 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1651 subst->from.name = strdupW(english_family);
1652 subst->from.charset = -1;
1653 subst->to.name = strdupW(localised_family);
1654 subst->to.charset = -1;
1655 add_font_subst(&font_subst_list, subst, 0);
1658 HeapFree(GetProcessHeap(), 0, localised_family);
1659 HeapFree(GetProcessHeap(), 0, english_family);
1661 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1662 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1663 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1665 internal_leading = 0;
1666 memset(&fs, 0, sizeof(fs));
1668 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1670 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1671 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1672 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1673 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1674 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1675 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1676 if(pOS2->version == 0) {
1679 if(pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1680 fs.fsCsb[0] |= FS_LATIN1;
1682 fs.fsCsb[0] |= FS_SYMBOL;
1685 else if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1687 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1688 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1689 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1691 internal_leading = winfnt_header.internal_leading;
1694 face_elem_ptr = list_head(&family->faces);
1695 while(face_elem_ptr) {
1696 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1697 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1698 if(!strcmpiW(face->StyleName, StyleW) &&
1699 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1700 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1701 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1702 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1705 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1706 HeapFree(GetProcessHeap(), 0, StyleW);
1707 pFT_Done_Face(ft_face);
1710 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1711 TRACE("Original font is newer so skipping this one\n");
1712 HeapFree(GetProcessHeap(), 0, StyleW);
1713 pFT_Done_Face(ft_face);
1716 TRACE("Replacing original with this one\n");
1717 list_remove(&face->entry);
1718 HeapFree(GetProcessHeap(), 0, face->file);
1719 HeapFree(GetProcessHeap(), 0, face->StyleName);
1720 HeapFree(GetProcessHeap(), 0, face->FullName);
1721 HeapFree(GetProcessHeap(), 0, face);
1726 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1727 face->cached_enum_data = NULL;
1728 face->StyleName = StyleW;
1729 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1732 face->file = strdupA(file);
1733 face->font_data_ptr = NULL;
1734 face->font_data_size = 0;
1739 face->font_data_ptr = font_data_ptr;
1740 face->font_data_size = font_data_size;
1742 face->face_index = face_index;
1744 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1745 face->ntmFlags |= NTM_ITALIC;
1746 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1747 face->ntmFlags |= NTM_BOLD;
1748 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1749 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1750 face->family = family;
1751 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1753 memset(&face->fs_links, 0, sizeof(face->fs_links));
1755 if(FT_IS_SCALABLE(ft_face)) {
1756 memset(&face->size, 0, sizeof(face->size));
1757 face->scalable = TRUE;
1759 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1760 size->height, size->width, size->size >> 6,
1761 size->x_ppem >> 6, size->y_ppem >> 6);
1762 face->size.height = size->height;
1763 face->size.width = size->width;
1764 face->size.size = size->size;
1765 face->size.x_ppem = size->x_ppem;
1766 face->size.y_ppem = size->y_ppem;
1767 face->size.internal_leading = internal_leading;
1768 face->scalable = FALSE;
1771 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1773 if (!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1775 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1776 face->ntmFlags |= NTM_PS_OPENTYPE;
1779 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1780 face->fs.fsCsb[0], face->fs.fsCsb[1],
1781 face->fs.fsUsb[0], face->fs.fsUsb[1],
1782 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1785 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1786 for(i = 0; i < ft_face->num_charmaps; i++) {
1787 switch(ft_face->charmaps[i]->encoding) {
1788 case FT_ENCODING_UNICODE:
1789 case FT_ENCODING_APPLE_ROMAN:
1790 face->fs.fsCsb[0] |= FS_LATIN1;
1792 case FT_ENCODING_MS_SYMBOL:
1793 face->fs.fsCsb[0] |= FS_SYMBOL;
1801 if(flags & ADDFONT_ADD_TO_CACHE)
1802 add_face_to_cache(face);
1804 AddFaceToFamily(face, family);
1806 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1808 num_faces = ft_face->num_faces;
1809 pFT_Done_Face(ft_face);
1810 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1811 debugstr_w(StyleW));
1812 } while(num_faces > ++face_index);
1816 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1818 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1821 static void DumpFontList(void)
1825 struct list *family_elem_ptr, *face_elem_ptr;
1827 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1828 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1829 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1830 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1831 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1832 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1834 TRACE(" %d", face->size.height);
1841 /***********************************************************
1842 * The replacement list is a way to map an entire font
1843 * family onto another family. For example adding
1845 * [HKCU\Software\Wine\Fonts\Replacements]
1846 * "Wingdings"="Winedings"
1848 * would enumerate the Winedings font both as Winedings and
1849 * Wingdings. However if a real Wingdings font is present the
1850 * replacement does not take place.
1853 static void LoadReplaceList(void)
1856 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1861 struct list *family_elem_ptr, *face_elem_ptr;
1864 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1865 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1867 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1868 &valuelen, &datalen, NULL, NULL);
1870 valuelen++; /* returned value doesn't include room for '\0' */
1871 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1872 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1876 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1877 &dlen) == ERROR_SUCCESS) {
1878 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1879 /* "NewName"="Oldname" */
1880 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1882 if(!find_family_from_name(value))
1884 /* Find the old family and hence all of the font files
1886 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1887 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1888 if(!strcmpiW(family->FamilyName, data)) {
1889 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1890 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1891 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1892 debugstr_w(face->StyleName), familyA);
1893 /* Now add a new entry with the new family name */
1894 AddFontToList(face->file, face->font_data_ptr, face->font_data_size,
1895 familyA, family->FamilyName,
1896 ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1902 /* reset dlen and vlen */
1906 HeapFree(GetProcessHeap(), 0, data);
1907 HeapFree(GetProcessHeap(), 0, value);
1912 /*************************************************************
1915 static BOOL init_system_links(void)
1919 DWORD type, max_val, max_data, val_len, data_len, index;
1920 WCHAR *value, *data;
1921 WCHAR *entry, *next;
1922 SYSTEM_LINKS *font_link, *system_font_link;
1923 CHILD_FONT *child_font;
1924 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1925 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1931 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1933 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1934 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1935 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1936 val_len = max_val + 1;
1937 data_len = max_data;
1939 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1941 memset(&fs, 0, sizeof(fs));
1942 psub = get_font_subst(&font_subst_list, value, -1);
1943 /* Don't store fonts that are only substitutes for other fonts */
1946 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1949 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1950 font_link->font_name = strdupW(value);
1951 list_init(&font_link->links);
1952 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1955 CHILD_FONT *child_font;
1957 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1959 next = entry + strlenW(entry) + 1;
1961 face_name = strchrW(entry, ',');
1965 while(isspaceW(*face_name))
1968 psub = get_font_subst(&font_subst_list, face_name, -1);
1970 face_name = psub->to.name;
1972 face = find_face_from_filename(entry, face_name);
1975 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1979 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1980 child_font->face = face;
1981 child_font->font = NULL;
1982 fs.fsCsb[0] |= face->fs.fsCsb[0];
1983 fs.fsCsb[1] |= face->fs.fsCsb[1];
1984 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1985 list_add_tail(&font_link->links, &child_font->entry);
1987 family = find_family_from_name(font_link->font_name);
1990 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1992 face->fs_links = fs;
1995 list_add_tail(&system_links, &font_link->entry);
1997 val_len = max_val + 1;
1998 data_len = max_data;
2001 HeapFree(GetProcessHeap(), 0, value);
2002 HeapFree(GetProcessHeap(), 0, data);
2006 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2009 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2010 system_font_link->font_name = strdupW(System);
2011 list_init(&system_font_link->links);
2013 face = find_face_from_filename(tahoma_ttf, Tahoma);
2016 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2017 child_font->face = face;
2018 child_font->font = NULL;
2019 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2020 list_add_tail(&system_font_link->links, &child_font->entry);
2022 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2024 if(!strcmpiW(font_link->font_name, Tahoma))
2026 CHILD_FONT *font_link_entry;
2027 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2029 CHILD_FONT *new_child;
2030 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2031 new_child->face = font_link_entry->face;
2032 new_child->font = NULL;
2033 list_add_tail(&system_font_link->links, &new_child->entry);
2038 list_add_tail(&system_links, &system_font_link->entry);
2042 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2045 struct dirent *dent;
2046 char path[MAX_PATH];
2048 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2050 dir = opendir(dirname);
2052 WARN("Can't open directory %s\n", debugstr_a(dirname));
2055 while((dent = readdir(dir)) != NULL) {
2056 struct stat statbuf;
2058 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2061 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2063 sprintf(path, "%s/%s", dirname, dent->d_name);
2065 if(stat(path, &statbuf) == -1)
2067 WARN("Can't stat %s\n", debugstr_a(path));
2070 if(S_ISDIR(statbuf.st_mode))
2071 ReadFontDir(path, external_fonts);
2074 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2075 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2076 AddFontFileToList(path, NULL, NULL, addfont_flags);
2083 static void load_fontconfig_fonts(void)
2085 #ifdef SONAME_LIBFONTCONFIG
2086 void *fc_handle = NULL;
2095 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2097 TRACE("Wine cannot find the fontconfig library (%s).\n",
2098 SONAME_LIBFONTCONFIG);
2101 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
2102 LOAD_FUNCPTR(FcConfigGetCurrent);
2103 LOAD_FUNCPTR(FcFontList);
2104 LOAD_FUNCPTR(FcFontSetDestroy);
2105 LOAD_FUNCPTR(FcInit);
2106 LOAD_FUNCPTR(FcObjectSetAdd);
2107 LOAD_FUNCPTR(FcObjectSetCreate);
2108 LOAD_FUNCPTR(FcObjectSetDestroy);
2109 LOAD_FUNCPTR(FcPatternCreate);
2110 LOAD_FUNCPTR(FcPatternDestroy);
2111 LOAD_FUNCPTR(FcPatternGetBool);
2112 LOAD_FUNCPTR(FcPatternGetString);
2115 if(!pFcInit()) return;
2117 config = pFcConfigGetCurrent();
2118 pat = pFcPatternCreate();
2119 os = pFcObjectSetCreate();
2120 pFcObjectSetAdd(os, FC_FILE);
2121 pFcObjectSetAdd(os, FC_SCALABLE);
2122 fontset = pFcFontList(config, pat, os);
2123 if(!fontset) return;
2124 for(i = 0; i < fontset->nfont; i++) {
2127 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2129 TRACE("fontconfig: %s\n", file);
2131 /* We're just interested in OT/TT fonts for now, so this hack just
2132 picks up the scalable fonts without extensions .pf[ab] to save time
2133 loading every other font */
2135 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2137 TRACE("not scalable\n");
2141 len = strlen( file );
2142 if(len < 4) continue;
2143 ext = &file[ len - 3 ];
2144 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2145 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2147 pFcFontSetDestroy(fontset);
2148 pFcObjectSetDestroy(os);
2149 pFcPatternDestroy(pat);
2155 static BOOL load_font_from_data_dir(LPCWSTR file)
2158 const char *data_dir = wine_get_data_dir();
2160 if (!data_dir) data_dir = wine_get_build_dir();
2167 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2169 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2171 strcpy(unix_name, data_dir);
2172 strcat(unix_name, "/fonts/");
2174 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2176 EnterCriticalSection( &freetype_cs );
2177 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2178 LeaveCriticalSection( &freetype_cs );
2179 HeapFree(GetProcessHeap(), 0, unix_name);
2184 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2186 static const WCHAR slashW[] = {'\\','\0'};
2188 WCHAR windowsdir[MAX_PATH];
2191 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2192 strcatW(windowsdir, fontsW);
2193 strcatW(windowsdir, slashW);
2194 strcatW(windowsdir, file);
2195 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2196 EnterCriticalSection( &freetype_cs );
2197 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2198 LeaveCriticalSection( &freetype_cs );
2199 HeapFree(GetProcessHeap(), 0, unixname);
2204 static void load_system_fonts(void)
2207 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2208 const WCHAR * const *value;
2210 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2213 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2214 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2215 strcatW(windowsdir, fontsW);
2216 for(value = SystemFontValues; *value; value++) {
2217 dlen = sizeof(data);
2218 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2222 sprintfW(pathW, fmtW, windowsdir, data);
2223 if((unixname = wine_get_unix_file_name(pathW))) {
2224 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2225 HeapFree(GetProcessHeap(), 0, unixname);
2228 load_font_from_data_dir(data);
2235 /*************************************************************
2237 * This adds registry entries for any externally loaded fonts
2238 * (fonts from fontconfig or FontDirs). It also deletes entries
2239 * of no longer existing fonts.
2242 static void update_reg_entries(void)
2244 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2249 struct list *family_elem_ptr, *face_elem_ptr;
2251 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2252 static const WCHAR spaceW[] = {' ', '\0'};
2255 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2256 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2257 ERR("Can't create Windows font reg key\n");
2261 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2262 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2263 ERR("Can't create Windows font reg key\n");
2267 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2268 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2269 ERR("Can't create external font reg key\n");
2273 /* enumerate the fonts and add external ones to the two keys */
2275 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2276 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2277 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2278 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2279 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2280 if(!face->external) continue;
2282 if (!(face->ntmFlags & NTM_REGULAR))
2283 len = len_fam + strlenW(face->StyleName) + 1;
2284 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2285 strcpyW(valueW, family->FamilyName);
2286 if(len != len_fam) {
2287 strcatW(valueW, spaceW);
2288 strcatW(valueW, face->StyleName);
2290 strcatW(valueW, TrueType);
2292 file = wine_get_dos_file_name(face->file);
2294 len = strlenW(file) + 1;
2297 if((path = strrchr(face->file, '/')) == NULL)
2301 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2303 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2304 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2306 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2307 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2308 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2310 HeapFree(GetProcessHeap(), 0, file);
2311 HeapFree(GetProcessHeap(), 0, valueW);
2315 if(external_key) RegCloseKey(external_key);
2316 if(win9x_key) RegCloseKey(win9x_key);
2317 if(winnt_key) RegCloseKey(winnt_key);
2321 static void delete_external_font_keys(void)
2323 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2324 DWORD dlen, vlen, datalen, valuelen, i, type;
2328 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2329 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2330 ERR("Can't create Windows font reg key\n");
2334 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2335 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2336 ERR("Can't create Windows font reg key\n");
2340 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2341 ERR("Can't create external font reg key\n");
2345 /* Delete all external fonts added last time */
2347 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2348 &valuelen, &datalen, NULL, NULL);
2349 valuelen++; /* returned value doesn't include room for '\0' */
2350 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2351 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2353 dlen = datalen * sizeof(WCHAR);
2356 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2357 &dlen) == ERROR_SUCCESS) {
2359 RegDeleteValueW(winnt_key, valueW);
2360 RegDeleteValueW(win9x_key, valueW);
2361 /* reset dlen and vlen */
2365 HeapFree(GetProcessHeap(), 0, data);
2366 HeapFree(GetProcessHeap(), 0, valueW);
2368 /* Delete the old external fonts key */
2369 RegCloseKey(external_key);
2370 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2373 if(win9x_key) RegCloseKey(win9x_key);
2374 if(winnt_key) RegCloseKey(winnt_key);
2377 /*************************************************************
2378 * WineEngAddFontResourceEx
2381 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2387 if (ft_handle) /* do it only if we have freetype up and running */
2392 FIXME("Ignoring flags %x\n", flags);
2394 if((unixname = wine_get_unix_file_name(file)))
2396 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2398 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2399 EnterCriticalSection( &freetype_cs );
2400 ret = AddFontFileToList(unixname, NULL, NULL, addfont_flags);
2401 LeaveCriticalSection( &freetype_cs );
2402 HeapFree(GetProcessHeap(), 0, unixname);
2404 if (!ret && !strchrW(file, '\\')) {
2405 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2406 ret = load_font_from_winfonts_dir(file);
2408 /* Try in datadir/fonts (or builddir/fonts),
2409 * needed for Magic the Gathering Online
2411 ret = load_font_from_data_dir(file);
2418 /*************************************************************
2419 * WineEngAddFontMemResourceEx
2422 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2426 if (ft_handle) /* do it only if we have freetype up and running */
2428 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2430 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2431 memcpy(pFontCopy, pbFont, cbFont);
2433 EnterCriticalSection( &freetype_cs );
2434 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2435 LeaveCriticalSection( &freetype_cs );
2439 TRACE("AddFontToList failed\n");
2440 HeapFree(GetProcessHeap(), 0, pFontCopy);
2443 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2444 * For now return something unique but quite random
2446 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2447 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2454 /*************************************************************
2455 * WineEngRemoveFontResourceEx
2458 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2461 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2465 static const struct nls_update_font_list
2467 UINT ansi_cp, oem_cp;
2468 const char *oem, *fixed, *system;
2469 const char *courier, *serif, *small, *sserif;
2470 /* these are for font substitutes */
2471 const char *shelldlg, *tmsrmn;
2472 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2476 const char *from, *to;
2477 } arial_0, courier_new_0, times_new_roman_0;
2478 } nls_update_font_list[] =
2480 /* Latin 1 (United States) */
2481 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2482 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2483 "Tahoma","Times New Roman",
2484 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2487 /* Latin 1 (Multilingual) */
2488 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2489 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2490 "Tahoma","Times New Roman", /* FIXME unverified */
2491 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2494 /* Eastern Europe */
2495 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2496 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2497 "Tahoma","Times New Roman", /* FIXME unverified */
2498 "Fixedsys,238", "System,238",
2499 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2500 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2501 { "Arial CE,0", "Arial,238" },
2502 { "Courier New CE,0", "Courier New,238" },
2503 { "Times New Roman CE,0", "Times New Roman,238" }
2506 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2507 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2508 "Tahoma","Times New Roman", /* FIXME unverified */
2509 "Fixedsys,204", "System,204",
2510 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2511 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2512 { "Arial Cyr,0", "Arial,204" },
2513 { "Courier New Cyr,0", "Courier New,204" },
2514 { "Times New Roman Cyr,0", "Times New Roman,204" }
2517 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2518 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2519 "Tahoma","Times New Roman", /* FIXME unverified */
2520 "Fixedsys,161", "System,161",
2521 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2522 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2523 { "Arial Greek,0", "Arial,161" },
2524 { "Courier New Greek,0", "Courier New,161" },
2525 { "Times New Roman Greek,0", "Times New Roman,161" }
2528 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2529 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2530 "Tahoma","Times New Roman", /* FIXME unverified */
2531 "Fixedsys,162", "System,162",
2532 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2533 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2534 { "Arial Tur,0", "Arial,162" },
2535 { "Courier New Tur,0", "Courier New,162" },
2536 { "Times New Roman Tur,0", "Times New Roman,162" }
2539 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2540 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2541 "Tahoma","Times New Roman", /* FIXME unverified */
2542 "Fixedsys,177", "System,177",
2543 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2544 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2548 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2549 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2550 "Tahoma","Times New Roman", /* FIXME unverified */
2551 "Fixedsys,178", "System,178",
2552 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2553 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2557 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2558 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2559 "Tahoma","Times New Roman", /* FIXME unverified */
2560 "Fixedsys,186", "System,186",
2561 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2562 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2563 { "Arial Baltic,0", "Arial,186" },
2564 { "Courier New Baltic,0", "Courier New,186" },
2565 { "Times New Roman Baltic,0", "Times New Roman,186" }
2568 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2569 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2570 "Tahoma","Times New Roman", /* FIXME unverified */
2571 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2575 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2576 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2577 "Tahoma","Times New Roman", /* FIXME unverified */
2578 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2582 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2583 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2584 "MS UI Gothic","MS Serif",
2585 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2588 /* Chinese Simplified */
2589 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2590 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2591 "SimSun", "NSimSun",
2592 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2596 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2597 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2599 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2602 /* Chinese Traditional */
2603 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2604 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2605 "PMingLiU", "MingLiU",
2606 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2611 static const WCHAR *font_links_list[] =
2613 Lucida_Sans_Unicode,
2614 Microsoft_Sans_Serif,
2618 static const struct font_links_defaults_list
2620 /* Keyed off substitution for "MS Shell Dlg" */
2621 const WCHAR *shelldlg;
2622 /* Maximum of four substitutes, plus terminating NULL pointer */
2623 const WCHAR *substitutes[5];
2624 } font_links_defaults_list[] =
2626 /* Non East-Asian */
2627 { Tahoma, /* FIXME unverified ordering */
2628 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2630 /* Below lists are courtesy of
2631 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2635 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2637 /* Chinese Simplified */
2639 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2643 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2645 /* Chinese Traditional */
2647 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2651 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2653 return ( ansi_cp == 932 /* CP932 for Japanese */
2654 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2655 || ansi_cp == 949 /* CP949 for Korean */
2656 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2659 static inline HKEY create_fonts_NT_registry_key(void)
2663 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2664 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2668 static inline HKEY create_fonts_9x_registry_key(void)
2672 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2673 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2677 static inline HKEY create_config_fonts_registry_key(void)
2681 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2682 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2686 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2688 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2689 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2690 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2691 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2694 static void set_value_key(HKEY hkey, const char *name, const char *value)
2697 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2699 RegDeleteValueA(hkey, name);
2702 static void update_font_info(void)
2704 char buf[40], cpbuf[40];
2707 UINT i, ansi_cp = 0, oem_cp = 0;
2710 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2713 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2714 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2715 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2716 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2717 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2719 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2720 if (is_dbcs_ansi_cp(ansi_cp))
2721 use_default_fallback = TRUE;
2724 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2726 if (!strcmp( buf, cpbuf )) /* already set correctly */
2731 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2733 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2735 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2738 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2742 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2743 nls_update_font_list[i].oem_cp == oem_cp)
2745 hkey = create_config_fonts_registry_key();
2746 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2747 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2748 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2751 hkey = create_fonts_NT_registry_key();
2752 add_font_list(hkey, &nls_update_font_list[i]);
2755 hkey = create_fonts_9x_registry_key();
2756 add_font_list(hkey, &nls_update_font_list[i]);
2759 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2761 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2762 strlen(nls_update_font_list[i].shelldlg)+1);
2763 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2764 strlen(nls_update_font_list[i].tmsrmn)+1);
2766 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2767 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2768 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2769 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2770 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2771 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2772 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2773 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2775 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2776 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2777 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2785 /* Delete the FontSubstitutes from other locales */
2786 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2788 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2789 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2790 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2796 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2798 /* Clear out system links */
2799 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2802 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2812 WCHAR buff[MAX_PATH];
2816 static const WCHAR comma[] = {',',0};
2818 RegDeleteValueW(hkey, name);
2823 for (i = 0; values[i] != NULL; i++)
2826 if (!strcmpiW(name,value))
2828 psub = get_font_subst(&font_subst_list, value, -1);
2830 value = psub->to.name;
2831 family = find_family_from_name(value);
2835 /* Use first extant filename for this Family */
2836 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2840 file = strrchr(face->file, '/');
2849 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2850 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2851 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2852 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2853 if (sizeof(buff)-(data-buff) < entryLen + 1)
2855 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2856 HeapFree(GetProcessHeap(), 0, fileW);
2859 strcpyW(data, fileW);
2860 strcatW(data, comma);
2861 strcatW(data, value);
2863 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2864 HeapFree(GetProcessHeap(), 0, fileW);
2870 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2872 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2874 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2877 static void update_system_links(void)
2885 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2887 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2889 if (disposition == REG_OPENED_EXISTING_KEY)
2891 TRACE("SystemLink key already exists, doing nothing\n");
2896 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2898 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2903 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2905 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2907 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2908 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2910 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2911 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2914 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2916 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2921 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2923 WARN("failed to create SystemLink key\n");
2927 static BOOL init_freetype(void)
2929 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2932 "Wine cannot find the FreeType font library. To enable Wine to\n"
2933 "use TrueType fonts please install a version of FreeType greater than\n"
2934 "or equal to 2.0.5.\n"
2935 "http://www.freetype.org\n");
2939 #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;}
2941 LOAD_FUNCPTR(FT_Done_Face)
2942 LOAD_FUNCPTR(FT_Get_Char_Index)
2943 LOAD_FUNCPTR(FT_Get_First_Char)
2944 LOAD_FUNCPTR(FT_Get_Module)
2945 LOAD_FUNCPTR(FT_Get_Next_Char)
2946 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2947 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2948 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2949 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
2950 LOAD_FUNCPTR(FT_Init_FreeType)
2951 LOAD_FUNCPTR(FT_Library_Version)
2952 LOAD_FUNCPTR(FT_Load_Glyph)
2953 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
2954 LOAD_FUNCPTR(FT_Matrix_Multiply)
2955 #ifndef FT_MULFIX_INLINED
2956 LOAD_FUNCPTR(FT_MulFix)
2958 LOAD_FUNCPTR(FT_New_Face)
2959 LOAD_FUNCPTR(FT_New_Memory_Face)
2960 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2961 LOAD_FUNCPTR(FT_Outline_Transform)
2962 LOAD_FUNCPTR(FT_Outline_Translate)
2963 LOAD_FUNCPTR(FT_Render_Glyph)
2964 LOAD_FUNCPTR(FT_Select_Charmap)
2965 LOAD_FUNCPTR(FT_Set_Charmap)
2966 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2967 LOAD_FUNCPTR(FT_Vector_Transform)
2968 LOAD_FUNCPTR(FT_Vector_Unit)
2970 /* Don't warn if these ones are missing */
2971 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2972 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2973 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2976 if(pFT_Init_FreeType(&library) != 0) {
2977 ERR("Can't init FreeType library\n");
2978 wine_dlclose(ft_handle, NULL, 0);
2982 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2984 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2985 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2986 ((FT_Version.minor << 8) & 0x00ff00) |
2987 ((FT_Version.patch ) & 0x0000ff);
2989 font_driver = &freetype_funcs;
2994 "Wine cannot find certain functions that it needs inside the FreeType\n"
2995 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2996 "FreeType to at least version 2.1.4.\n"
2997 "http://www.freetype.org\n");
2998 wine_dlclose(ft_handle, NULL, 0);
3003 static void init_font_list(void)
3005 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3006 static const WCHAR pathW[] = {'P','a','t','h',0};
3008 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3009 WCHAR windowsdir[MAX_PATH];
3011 const char *data_dir;
3013 delete_external_font_keys();
3015 /* load the system bitmap fonts */
3016 load_system_fonts();
3018 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3019 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3020 strcatW(windowsdir, fontsW);
3021 if((unixname = wine_get_unix_file_name(windowsdir)))
3023 ReadFontDir(unixname, FALSE);
3024 HeapFree(GetProcessHeap(), 0, unixname);
3027 /* load the system truetype fonts */
3028 data_dir = wine_get_data_dir();
3029 if (!data_dir) data_dir = wine_get_build_dir();
3030 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3032 strcpy(unixname, data_dir);
3033 strcat(unixname, "/fonts/");
3034 ReadFontDir(unixname, TRUE);
3035 HeapFree(GetProcessHeap(), 0, unixname);
3038 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3039 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3040 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3042 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3043 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3044 &hkey) == ERROR_SUCCESS)
3046 LPWSTR data, valueW;
3047 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3048 &valuelen, &datalen, NULL, NULL);
3050 valuelen++; /* returned value doesn't include room for '\0' */
3051 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3052 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3055 dlen = datalen * sizeof(WCHAR);
3057 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3058 &dlen) == ERROR_SUCCESS)
3060 if(data[0] && (data[1] == ':'))
3062 if((unixname = wine_get_unix_file_name(data)))
3064 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3065 HeapFree(GetProcessHeap(), 0, unixname);
3068 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3070 WCHAR pathW[MAX_PATH];
3071 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3074 sprintfW(pathW, fmtW, windowsdir, data);
3075 if((unixname = wine_get_unix_file_name(pathW)))
3077 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3078 HeapFree(GetProcessHeap(), 0, unixname);
3081 load_font_from_data_dir(data);
3083 /* reset dlen and vlen */
3088 HeapFree(GetProcessHeap(), 0, data);
3089 HeapFree(GetProcessHeap(), 0, valueW);
3093 load_fontconfig_fonts();
3095 /* then look in any directories that we've specified in the config file */
3096 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3097 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3103 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3105 len += sizeof(WCHAR);
3106 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3107 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3109 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3110 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3111 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3112 TRACE( "got font path %s\n", debugstr_a(valueA) );
3116 LPSTR next = strchr( ptr, ':' );
3117 if (next) *next++ = 0;
3118 ReadFontDir( ptr, TRUE );
3121 HeapFree( GetProcessHeap(), 0, valueA );
3123 HeapFree( GetProcessHeap(), 0, valueW );
3129 static BOOL move_to_front(const WCHAR *name)
3131 Family *family, *cursor2;
3132 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3134 if(!strcmpiW(family->FamilyName, name))
3136 list_remove(&family->entry);
3137 list_add_head(&font_list, &family->entry);
3144 static BOOL set_default(const WCHAR **name_list)
3148 if (move_to_front(*name_list)) return TRUE;
3155 static void reorder_font_list(void)
3157 set_default( default_serif_list );
3158 set_default( default_fixed_list );
3159 set_default( default_sans_list );
3162 /*************************************************************
3165 * Initialize FreeType library and create a list of available faces
3167 BOOL WineEngInit(void)
3169 HKEY hkey_font_cache;
3173 /* update locale dependent font info in registry */
3176 if(!init_freetype()) return FALSE;
3178 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3180 ERR("Failed to create font mutex\n");
3183 WaitForSingleObject(font_mutex, INFINITE);
3185 create_font_cache_key(&hkey_font_cache, &disposition);
3187 if(disposition == REG_CREATED_NEW_KEY)
3190 load_font_list_from_cache(hkey_font_cache);
3192 RegCloseKey(hkey_font_cache);
3194 reorder_font_list();
3201 if(disposition == REG_CREATED_NEW_KEY)
3202 update_reg_entries();
3204 update_system_links();
3205 init_system_links();
3207 ReleaseMutex(font_mutex);
3212 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3215 TT_HoriHeader *pHori;
3219 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3220 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3222 if(height == 0) height = 16;
3224 /* Calc. height of EM square:
3226 * For +ve lfHeight we have
3227 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3228 * Re-arranging gives:
3229 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3231 * For -ve lfHeight we have
3233 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3234 * with il = winAscent + winDescent - units_per_em]
3239 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3240 ppem = MulDiv(ft_face->units_per_EM, height,
3241 pHori->Ascender - pHori->Descender);
3243 ppem = MulDiv(ft_face->units_per_EM, height,
3244 pOS2->usWinAscent + pOS2->usWinDescent);
3252 static struct font_mapping *map_font_file( const char *name )
3254 struct font_mapping *mapping;
3258 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3259 if (fstat( fd, &st ) == -1) goto error;
3261 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3263 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3265 mapping->refcount++;
3270 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3273 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3276 if (mapping->data == MAP_FAILED)
3278 HeapFree( GetProcessHeap(), 0, mapping );
3281 mapping->refcount = 1;
3282 mapping->dev = st.st_dev;
3283 mapping->ino = st.st_ino;
3284 mapping->size = st.st_size;
3285 list_add_tail( &mappings_list, &mapping->entry );
3293 static void unmap_font_file( struct font_mapping *mapping )
3295 if (!--mapping->refcount)
3297 list_remove( &mapping->entry );
3298 munmap( mapping->data, mapping->size );
3299 HeapFree( GetProcessHeap(), 0, mapping );
3303 static LONG load_VDMX(GdiFont*, LONG);
3305 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3312 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3316 if (!(font->mapping = map_font_file( face->file )))
3318 WARN("failed to map %s\n", debugstr_a(face->file));
3321 data_ptr = font->mapping->data;
3322 data_size = font->mapping->size;
3326 data_ptr = face->font_data_ptr;
3327 data_size = face->font_data_size;
3330 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3332 ERR("FT_New_Face rets %d\n", err);
3336 /* set it here, as load_VDMX needs it */
3337 font->ft_face = ft_face;
3339 if(FT_IS_SCALABLE(ft_face)) {
3340 /* load the VDMX table if we have one */
3341 font->ppem = load_VDMX(font, height);
3343 font->ppem = calc_ppem_for_height(ft_face, height);
3344 TRACE("height %d => ppem %d\n", height, font->ppem);
3346 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3347 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3349 font->ppem = height;
3350 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3351 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3357 static int get_nearest_charset(Face *face, int *cp)
3359 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3360 a single face with the requested charset. The idea is to check if
3361 the selected font supports the current ANSI codepage, if it does
3362 return the corresponding charset, else return the first charset */
3365 int acp = GetACP(), i;
3369 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3370 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3371 return csi.ciCharset;
3373 for(i = 0; i < 32; i++) {
3375 if(face->fs.fsCsb[0] & fs0) {
3376 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3378 return csi.ciCharset;
3381 FIXME("TCI failing on %x\n", fs0);
3385 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3386 face->fs.fsCsb[0], face->file);
3388 return DEFAULT_CHARSET;
3391 static GdiFont *alloc_font(void)
3393 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3395 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3396 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3398 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3399 ret->total_kern_pairs = (DWORD)-1;
3400 ret->kern_pairs = NULL;
3401 list_init(&ret->hfontlist);
3402 list_init(&ret->child_fonts);
3406 static void free_font(GdiFont *font)
3408 struct list *cursor, *cursor2;
3411 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3413 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3414 list_remove(cursor);
3416 free_font(child->font);
3417 HeapFree(GetProcessHeap(), 0, child);
3420 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3422 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3423 DeleteObject(hfontlist->hfont);
3424 list_remove(&hfontlist->entry);
3425 HeapFree(GetProcessHeap(), 0, hfontlist);
3428 if (font->ft_face) pFT_Done_Face(font->ft_face);
3429 if (font->mapping) unmap_font_file( font->mapping );
3430 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3431 HeapFree(GetProcessHeap(), 0, font->potm);
3432 HeapFree(GetProcessHeap(), 0, font->name);
3433 for (i = 0; i < font->gmsize; i++)
3434 HeapFree(GetProcessHeap(),0,font->gm[i]);
3435 HeapFree(GetProcessHeap(), 0, font->gm);
3436 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3437 HeapFree(GetProcessHeap(), 0, font);
3441 /*************************************************************
3444 * load the vdmx entry for the specified height
3447 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3448 ( ( (FT_ULong)_x4 << 24 ) | \
3449 ( (FT_ULong)_x3 << 16 ) | \
3450 ( (FT_ULong)_x2 << 8 ) | \
3453 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3468 static LONG load_VDMX(GdiFont *font, LONG height)
3472 BYTE devXRatio, devYRatio;
3473 USHORT numRecs, numRatios;
3474 DWORD result, offset = -1;
3478 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
3480 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3483 /* FIXME: need the real device aspect ratio */
3487 numRecs = GET_BE_WORD(hdr[1]);
3488 numRatios = GET_BE_WORD(hdr[2]);
3490 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3491 for(i = 0; i < numRatios; i++) {
3494 offset = (3 * 2) + (i * sizeof(Ratios));
3495 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3498 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3500 if((ratio.xRatio == 0 &&
3501 ratio.yStartRatio == 0 &&
3502 ratio.yEndRatio == 0) ||
3503 (devXRatio == ratio.xRatio &&
3504 devYRatio >= ratio.yStartRatio &&
3505 devYRatio <= ratio.yEndRatio))
3507 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3508 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3509 offset = GET_BE_WORD(tmp);
3515 FIXME("No suitable ratio found\n");
3519 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3521 BYTE startsz, endsz;
3524 recs = GET_BE_WORD(group.recs);
3525 startsz = group.startsz;
3526 endsz = group.endsz;
3528 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3530 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3531 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3532 if(result == GDI_ERROR) {
3533 FIXME("Failed to retrieve vTable\n");
3538 for(i = 0; i < recs; i++) {
3539 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3540 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3541 ppem = GET_BE_WORD(vTable[i * 3]);
3543 if(yMax + -yMin == height) {
3546 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3549 if(yMax + -yMin > height) {
3552 goto end; /* failed */
3554 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3555 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3556 ppem = GET_BE_WORD(vTable[i * 3]);
3557 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3563 TRACE("ppem not found for height %d\n", height);
3567 HeapFree(GetProcessHeap(), 0, vTable);
3573 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3575 if(font->font_desc.hash != fd->hash) return TRUE;
3576 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3577 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3578 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3579 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3582 static void calc_hash(FONT_DESC *pfd)
3584 DWORD hash = 0, *ptr, two_chars;
3588 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3590 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3592 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3594 pwc = (WCHAR *)&two_chars;
3596 *pwc = toupperW(*pwc);
3598 *pwc = toupperW(*pwc);
3602 hash ^= !pfd->can_use_bitmap;
3607 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3612 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3616 fd.can_use_bitmap = can_use_bitmap;
3619 /* try the child list */
3620 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3621 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3622 if(!fontcmp(ret, &fd)) {
3623 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3624 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3625 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3626 if(hflist->hfont == hfont)
3632 /* try the in-use list */
3633 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3634 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3635 if(!fontcmp(ret, &fd)) {
3636 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3637 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3638 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3639 if(hflist->hfont == hfont)
3642 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3643 hflist->hfont = hfont;
3644 list_add_head(&ret->hfontlist, &hflist->entry);
3649 /* then the unused list */
3650 font_elem_ptr = list_head(&unused_gdi_font_list);
3651 while(font_elem_ptr) {
3652 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3653 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3654 if(!fontcmp(ret, &fd)) {
3655 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3656 assert(list_empty(&ret->hfontlist));
3657 TRACE("Found %p in unused list\n", ret);
3658 list_remove(&ret->entry);
3659 list_add_head(&gdi_font_list, &ret->entry);
3660 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3661 hflist->hfont = hfont;
3662 list_add_head(&ret->hfontlist, &hflist->entry);
3669 static void add_to_cache(GdiFont *font)
3671 static DWORD cache_num = 1;
3673 font->cache_num = cache_num++;
3674 list_add_head(&gdi_font_list, &font->entry);
3677 /*************************************************************
3678 * create_child_font_list
3680 static BOOL create_child_font_list(GdiFont *font)
3683 SYSTEM_LINKS *font_link;
3684 CHILD_FONT *font_link_entry, *new_child;
3688 psub = get_font_subst(&font_subst_list, font->name, -1);
3689 font_name = psub ? psub->to.name : font->name;
3690 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3692 if(!strcmpiW(font_link->font_name, font_name))
3694 TRACE("found entry in system list\n");
3695 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3697 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3698 new_child->face = font_link_entry->face;
3699 new_child->font = NULL;
3700 list_add_tail(&font->child_fonts, &new_child->entry);
3701 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3708 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3709 * Sans Serif. This is how asian windows get default fallbacks for fonts
3711 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3712 font->charset != OEM_CHARSET &&
3713 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3714 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3716 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3718 TRACE("found entry in default fallback list\n");
3719 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3721 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3722 new_child->face = font_link_entry->face;
3723 new_child->font = NULL;
3724 list_add_tail(&font->child_fonts, &new_child->entry);
3725 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3735 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3737 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3739 if (pFT_Set_Charmap)
3742 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3744 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3746 for (i = 0; i < ft_face->num_charmaps; i++)
3748 if (ft_face->charmaps[i]->encoding == encoding)
3750 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3751 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3753 switch (ft_face->charmaps[i]->platform_id)
3756 cmap_def = ft_face->charmaps[i];
3758 case 0: /* Apple Unicode */
3759 cmap0 = ft_face->charmaps[i];
3761 case 1: /* Macintosh */
3762 cmap1 = ft_face->charmaps[i];
3765 cmap2 = ft_face->charmaps[i];
3767 case 3: /* Microsoft */
3768 cmap3 = ft_face->charmaps[i];
3773 if (cmap3) /* prefer Microsoft cmap table */
3774 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3776 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3778 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3780 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3782 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3784 return ft_err == FT_Err_Ok;
3787 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3791 /*************************************************************
3794 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3795 LPCWSTR output, const DEVMODEW *devmode )
3797 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3799 if (!physdev) return FALSE;
3800 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3805 /*************************************************************
3808 static BOOL freetype_DeleteDC( PHYSDEV dev )
3810 struct freetype_physdev *physdev = get_freetype_dev( dev );
3811 HeapFree( GetProcessHeap(), 0, physdev );
3816 /*************************************************************
3817 * freetype_SelectFont
3819 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3821 struct freetype_physdev *physdev = get_freetype_dev( dev );
3823 Face *face, *best, *best_bitmap;
3824 Family *family, *last_resort_family;
3825 struct list *family_elem_ptr, *face_elem_ptr;
3826 INT height, width = 0;
3827 unsigned int score = 0, new_score;
3828 signed int diff = 0, newdiff;
3829 BOOL bd, it, can_use_bitmap;
3834 FontSubst *psub = NULL;
3835 DC *dc = get_dc_ptr( dev->hdc );
3837 if (!hfont) /* notification that the font has been changed by another driver */
3840 physdev->font = NULL;
3841 release_dc_ptr( dc );
3845 GetObjectW( hfont, sizeof(lf), &lf );
3846 lf.lfWidth = abs(lf.lfWidth);
3848 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
3850 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3851 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3852 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3855 if(dc->GraphicsMode == GM_ADVANCED)
3856 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3859 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3860 font scaling abilities. */
3861 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3862 dcmat.eM21 = dcmat.eM12 = 0;
3865 /* Try to avoid not necessary glyph transformations */
3866 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3868 lf.lfHeight *= fabs(dcmat.eM11);
3869 lf.lfWidth *= fabs(dcmat.eM11);
3870 dcmat.eM11 = dcmat.eM22 = 1.0;
3873 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3874 dcmat.eM21, dcmat.eM22);
3877 EnterCriticalSection( &freetype_cs );
3879 /* check the cache first */
3880 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3881 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3885 if(list_empty(&font_list)) /* No fonts installed */
3887 TRACE("No fonts installed\n");
3891 TRACE("not in cache\n");
3894 ret->font_desc.matrix = dcmat;
3895 ret->font_desc.lf = lf;
3896 ret->font_desc.can_use_bitmap = can_use_bitmap;
3897 calc_hash(&ret->font_desc);
3898 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3899 hflist->hfont = hfont;
3900 list_add_head(&ret->hfontlist, &hflist->entry);
3902 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3903 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3904 original value lfCharSet. Note this is a special case for
3905 Symbol and doesn't happen at least for "Wingdings*" */
3907 if(!strcmpiW(lf.lfFaceName, SymbolW))
3908 lf.lfCharSet = SYMBOL_CHARSET;
3910 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3911 switch(lf.lfCharSet) {
3912 case DEFAULT_CHARSET:
3913 csi.fs.fsCsb[0] = 0;
3916 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3917 csi.fs.fsCsb[0] = 0;
3923 if(lf.lfFaceName[0] != '\0') {
3924 SYSTEM_LINKS *font_link;
3925 CHILD_FONT *font_link_entry;
3926 LPWSTR FaceName = lf.lfFaceName;
3929 * Check for a leading '@' this signals that the font is being
3930 * requested in tategaki mode (vertical writing substitution) but
3931 * does not affect the fontface that is to be selected.
3933 if (lf.lfFaceName[0]=='@')
3934 FaceName = &lf.lfFaceName[1];
3936 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3939 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3940 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3941 if (psub->to.charset != -1)
3942 lf.lfCharSet = psub->to.charset;
3945 /* We want a match on name and charset or just name if
3946 charset was DEFAULT_CHARSET. If the latter then
3947 we fixup the returned charset later in get_nearest_charset
3948 where we'll either use the charset of the current ansi codepage
3949 or if that's unavailable the first charset that the font supports.
3951 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3952 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3953 if (!strcmpiW(family->FamilyName, FaceName) ||
3954 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3956 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3957 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3958 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3959 if(face->scalable || can_use_bitmap)
3965 /* Search by full face name. */
3966 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3967 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3968 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3969 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3970 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
3971 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
3973 if(face->scalable || can_use_bitmap)
3980 * Try check the SystemLink list first for a replacement font.
3981 * We may find good replacements there.
3983 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3985 if(!strcmpiW(font_link->font_name, FaceName) ||
3986 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3988 TRACE("found entry in system list\n");
3989 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3991 face = font_link_entry->face;
3992 family = face->family;
3993 if(csi.fs.fsCsb[0] &
3994 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3996 if(face->scalable || can_use_bitmap)
4004 psub = NULL; /* substitution is no more relevant */
4006 /* If requested charset was DEFAULT_CHARSET then try using charset
4007 corresponding to the current ansi codepage */
4008 if (!csi.fs.fsCsb[0])
4011 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4012 FIXME("TCI failed on codepage %d\n", acp);
4013 csi.fs.fsCsb[0] = 0;
4015 lf.lfCharSet = csi.ciCharset;
4018 /* Face families are in the top 4 bits of lfPitchAndFamily,
4019 so mask with 0xF0 before testing */
4021 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4022 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4023 strcpyW(lf.lfFaceName, defFixed);
4024 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4025 strcpyW(lf.lfFaceName, defSerif);
4026 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4027 strcpyW(lf.lfFaceName, defSans);
4029 strcpyW(lf.lfFaceName, defSans);
4030 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4031 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4032 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4033 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4034 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4035 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
4036 if(face->scalable || can_use_bitmap)
4042 last_resort_family = NULL;
4043 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4044 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4045 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4046 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4047 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
4050 if(can_use_bitmap && !last_resort_family)
4051 last_resort_family = family;
4056 if(last_resort_family) {
4057 family = last_resort_family;
4058 csi.fs.fsCsb[0] = 0;
4062 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4063 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4064 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4065 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4066 if(face->scalable) {
4067 csi.fs.fsCsb[0] = 0;
4068 WARN("just using first face for now\n");
4071 if(can_use_bitmap && !last_resort_family)
4072 last_resort_family = family;
4075 if(!last_resort_family) {
4076 FIXME("can't find a single appropriate font - bailing\n");
4082 WARN("could only find a bitmap font - this will probably look awful!\n");
4083 family = last_resort_family;
4084 csi.fs.fsCsb[0] = 0;
4087 it = lf.lfItalic ? 1 : 0;
4088 bd = lf.lfWeight > 550 ? 1 : 0;
4090 height = lf.lfHeight;
4092 face = best = best_bitmap = NULL;
4093 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
4095 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4099 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4100 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4101 new_score = (italic ^ it) + (bold ^ bd);
4102 if(!best || new_score <= score)
4104 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4105 italic, bold, it, bd);
4108 if(best->scalable && score == 0) break;
4112 newdiff = height - (signed int)(best->size.height);
4114 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4115 if(!best_bitmap || new_score < score ||
4116 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4118 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4121 if(score == 0 && diff == 0) break;
4128 face = best->scalable ? best : best_bitmap;
4129 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4130 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4133 height = lf.lfHeight;
4137 if(csi.fs.fsCsb[0]) {
4138 ret->charset = lf.lfCharSet;
4139 ret->codepage = csi.ciACP;
4142 ret->charset = get_nearest_charset(face, &ret->codepage);
4144 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4145 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4147 ret->aveWidth = height ? lf.lfWidth : 0;
4149 if(!face->scalable) {
4150 /* Windows uses integer scaling factors for bitmap fonts */
4151 INT scale, scaled_height;
4152 GdiFont *cachedfont;
4154 /* FIXME: rotation of bitmap fonts is ignored */
4155 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4157 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4158 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4159 dcmat.eM11 = dcmat.eM22 = 1.0;
4160 /* As we changed the matrix, we need to search the cache for the font again,
4161 * otherwise we might explode the cache. */
4162 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4163 TRACE("Found cached font after non-scalable matrix rescale!\n");
4168 calc_hash(&ret->font_desc);
4170 if (height != 0) height = diff;
4171 height += face->size.height;
4173 scale = (height + face->size.height - 1) / face->size.height;
4174 scaled_height = scale * face->size.height;
4175 /* Only jump to the next height if the difference <= 25% original height */
4176 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4177 /* The jump between unscaled and doubled is delayed by 1 */
4178 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4179 ret->scale_y = scale;
4181 width = face->size.x_ppem >> 6;
4182 height = face->size.y_ppem >> 6;
4186 TRACE("font scale y: %f\n", ret->scale_y);
4188 ret->ft_face = OpenFontFace(ret, face, width, height);
4197 ret->ntmFlags = face->ntmFlags;
4199 if (ret->charset == SYMBOL_CHARSET &&
4200 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4203 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4207 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4210 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4211 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4212 ret->underline = lf.lfUnderline ? 0xff : 0;
4213 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4214 create_child_font_list(ret);
4216 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
4218 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
4219 if (length != GDI_ERROR)
4221 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4222 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4223 TRACE("Loaded GSUB table of %i bytes\n",length);
4227 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4234 physdev->font = ret;
4236 LeaveCriticalSection( &freetype_cs );
4237 release_dc_ptr( dc );
4238 return ret ? hfont : 0;
4241 static void dump_gdi_font_list(void)
4244 struct list *elem_ptr;
4246 TRACE("---------- gdiFont Cache ----------\n");
4247 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4248 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4249 TRACE("gdiFont=%p %s %d\n",
4250 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4253 TRACE("---------- Unused gdiFont Cache ----------\n");
4254 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4255 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4256 TRACE("gdiFont=%p %s %d\n",
4257 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4260 TRACE("---------- Child gdiFont Cache ----------\n");
4261 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4262 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4263 TRACE("gdiFont=%p %s %d\n",
4264 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4268 /*************************************************************
4269 * WineEngDestroyFontInstance
4271 * free the gdiFont associated with this handle
4274 BOOL WineEngDestroyFontInstance(HFONT handle)
4279 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4283 EnterCriticalSection( &freetype_cs );
4285 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4287 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4288 while(hfontlist_elem_ptr) {
4289 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4290 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4291 if(hflist->hfont == handle) {
4292 TRACE("removing child font %p from child list\n", gdiFont);
4293 list_remove(&gdiFont->entry);
4294 LeaveCriticalSection( &freetype_cs );
4300 TRACE("destroying hfont=%p\n", handle);
4302 dump_gdi_font_list();
4304 font_elem_ptr = list_head(&gdi_font_list);
4305 while(font_elem_ptr) {
4306 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4307 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4309 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4310 while(hfontlist_elem_ptr) {
4311 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4312 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4313 if(hflist->hfont == handle) {
4314 list_remove(&hflist->entry);
4315 HeapFree(GetProcessHeap(), 0, hflist);
4319 if(list_empty(&gdiFont->hfontlist)) {
4320 TRACE("Moving to Unused list\n");
4321 list_remove(&gdiFont->entry);
4322 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4327 font_elem_ptr = list_head(&unused_gdi_font_list);
4328 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4329 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4330 while(font_elem_ptr) {
4331 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4332 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4333 TRACE("freeing %p\n", gdiFont);
4334 list_remove(&gdiFont->entry);
4337 LeaveCriticalSection( &freetype_cs );
4341 /***************************************************
4342 * create_enum_charset_list
4344 * This function creates charset enumeration list because in DEFAULT_CHARSET
4345 * case, the ANSI codepage's charset takes precedence over other charsets.
4346 * This function works as a filter other than DEFAULT_CHARSET case.
4348 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4353 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4354 csi.fs.fsCsb[0] != 0) {
4355 list->element[n].mask = csi.fs.fsCsb[0];
4356 list->element[n].charset = csi.ciCharset;
4357 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4360 else { /* charset is DEFAULT_CHARSET or invalid. */
4363 /* Set the current codepage's charset as the first element. */
4365 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4366 csi.fs.fsCsb[0] != 0) {
4367 list->element[n].mask = csi.fs.fsCsb[0];
4368 list->element[n].charset = csi.ciCharset;
4369 list->element[n].name = ElfScriptsW[ffs(csi.fs.fsCsb[0]) - 1];
4373 /* Fill out left elements. */
4374 for (i = 0; i < 32; i++) {
4376 fs.fsCsb[0] = 1L << i;
4378 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4379 continue; /* skip, already added. */
4380 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4381 continue; /* skip, this is an invalid fsCsb bit. */
4383 list->element[n].mask = fs.fsCsb[0];
4384 list->element[n].charset = csi.ciCharset;
4385 list->element[n].name = ElfScriptsW[i];
4394 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4395 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4400 if (face->cached_enum_data)
4403 *pelf = face->cached_enum_data->elf;
4404 *pntm = face->cached_enum_data->ntm;
4405 *ptype = face->cached_enum_data->type;
4409 font = alloc_font();
4411 if(face->scalable) {
4412 height = -2048; /* 2048 is the most common em size */
4415 height = face->size.y_ppem >> 6;
4416 width = face->size.x_ppem >> 6;
4418 font->scale_y = 1.0;
4420 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4426 font->name = strdupW(face->family->FamilyName);
4427 font->ntmFlags = face->ntmFlags;
4429 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
4431 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4433 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4435 lstrcpynW(pelf->elfLogFont.lfFaceName,
4436 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4438 lstrcpynW(pelf->elfFullName,
4439 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4441 lstrcpynW(pelf->elfStyle,
4442 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4447 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4449 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4451 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4453 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4455 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4456 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4459 pntm->ntmTm.ntmFlags = face->ntmFlags;
4460 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4461 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4462 pntm->ntmFontSig = face->fs;
4464 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4466 pelf->elfLogFont.lfEscapement = 0;
4467 pelf->elfLogFont.lfOrientation = 0;
4468 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4469 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4470 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4471 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4472 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4473 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4474 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4475 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4476 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4477 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4478 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4481 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4482 *ptype |= TRUETYPE_FONTTYPE;
4483 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4484 *ptype |= DEVICE_FONTTYPE;
4485 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4486 *ptype |= RASTER_FONTTYPE;
4488 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4489 if (face->cached_enum_data)
4491 face->cached_enum_data->elf = *pelf;
4492 face->cached_enum_data->ntm = *pntm;
4493 face->cached_enum_data->type = *ptype;
4499 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4501 struct list *face_elem_ptr;
4503 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4505 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4507 static const WCHAR spaceW[] = { ' ',0 };
4508 WCHAR full_family_name[LF_FULLFACESIZE];
4509 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4511 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4513 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4514 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4518 strcpyW(full_family_name, family->FamilyName);
4519 strcatW(full_family_name, spaceW);
4520 strcatW(full_family_name, face->StyleName);
4521 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4527 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4529 static const WCHAR spaceW[] = { ' ',0 };
4530 WCHAR full_family_name[LF_FULLFACESIZE];
4532 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4534 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4536 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4537 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4541 strcpyW(full_family_name, face->family->FamilyName);
4542 strcatW(full_family_name, spaceW);
4543 strcatW(full_family_name, face->StyleName);
4544 return !strcmpiW(lf->lfFaceName, full_family_name);
4547 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4548 FONTENUMPROCW proc, LPARAM lparam)
4551 NEWTEXTMETRICEXW ntm;
4555 GetEnumStructs(face, &elf, &ntm, &type);
4556 for(i = 0; i < list->total; i++) {
4557 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4558 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4559 strcpyW(elf.elfScript, OEM_DOSW);
4560 i = 32; /* break out of loop */
4561 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4564 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4565 if(list->element[i].name)
4566 strcpyW(elf.elfScript, list->element[i].name);
4568 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4570 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4571 debugstr_w(elf.elfLogFont.lfFaceName),
4572 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4573 list->element[i].charset, type, debugstr_w(elf.elfScript),
4574 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4575 ntm.ntmTm.ntmFlags);
4576 /* release section before callback (FIXME) */
4577 LeaveCriticalSection( &freetype_cs );
4578 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4579 EnterCriticalSection( &freetype_cs );
4584 /*************************************************************
4588 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4592 struct list *family_elem_ptr, *face_elem_ptr;
4594 struct enum_charset_list enum_charsets;
4598 lf.lfCharSet = DEFAULT_CHARSET;
4599 lf.lfPitchAndFamily = 0;
4600 lf.lfFaceName[0] = 0;
4604 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4606 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4609 EnterCriticalSection( &freetype_cs );
4610 if(plf->lfFaceName[0]) {
4612 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4615 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4616 debugstr_w(psub->to.name));
4618 strcpyW(lf.lfFaceName, psub->to.name);
4622 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4623 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4624 if(family_matches(family, plf)) {
4625 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4626 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4627 if (!face_matches(face, plf)) continue;
4628 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return 0;
4633 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4634 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4635 face_elem_ptr = list_head(&family->faces);
4636 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4637 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return 0;
4640 LeaveCriticalSection( &freetype_cs );
4644 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4646 pt->x.value = vec->x >> 6;
4647 pt->x.fract = (vec->x & 0x3f) << 10;
4648 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4649 pt->y.value = vec->y >> 6;
4650 pt->y.fract = (vec->y & 0x3f) << 10;
4651 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4655 /***************************************************
4656 * According to the MSDN documentation on WideCharToMultiByte,
4657 * certain codepages cannot set the default_used parameter.
4658 * This returns TRUE if the codepage can set that parameter, false else
4659 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4661 static BOOL codepage_sets_default_used(UINT codepage)
4675 * GSUB Table handling functions
4678 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4680 const GSUB_CoverageFormat1* cf1;
4684 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4686 int count = GET_BE_WORD(cf1->GlyphCount);
4688 TRACE("Coverage Format 1, %i glyphs\n",count);
4689 for (i = 0; i < count; i++)
4690 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4694 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4696 const GSUB_CoverageFormat2* cf2;
4699 cf2 = (const GSUB_CoverageFormat2*)cf1;
4701 count = GET_BE_WORD(cf2->RangeCount);
4702 TRACE("Coverage Format 2, %i ranges\n",count);
4703 for (i = 0; i < count; i++)
4705 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4707 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4708 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4710 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4711 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4717 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4722 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4724 const GSUB_ScriptList *script;
4725 const GSUB_Script *deflt = NULL;
4727 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4729 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4730 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4732 const GSUB_Script *scr;
4735 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4736 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4738 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4740 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4746 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4750 const GSUB_LangSys *Lang;
4752 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4754 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4756 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4757 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4759 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4762 offset = GET_BE_WORD(script->DefaultLangSys);
4765 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4771 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4774 const GSUB_FeatureList *feature;
4775 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4777 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4778 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4780 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4781 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4783 const GSUB_Feature *feat;
4784 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4791 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4795 const GSUB_LookupList *lookup;
4796 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4798 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4799 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4801 const GSUB_LookupTable *look;
4802 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4803 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4804 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4805 if (GET_BE_WORD(look->LookupType) != 1)
4806 FIXME("We only handle SubType 1\n");
4811 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4813 const GSUB_SingleSubstFormat1 *ssf1;
4814 offset = GET_BE_WORD(look->SubTable[j]);
4815 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4816 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4818 int offset = GET_BE_WORD(ssf1->Coverage);
4819 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4820 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4822 TRACE(" Glyph 0x%x ->",glyph);
4823 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4824 TRACE(" 0x%x\n",glyph);
4829 const GSUB_SingleSubstFormat2 *ssf2;
4833 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4834 offset = GET_BE_WORD(ssf1->Coverage);
4835 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4836 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4837 TRACE(" Coverage index %i\n",index);
4840 TRACE(" Glyph is 0x%x ->",glyph);
4841 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4842 TRACE("0x%x\n",glyph);
4851 static const char* get_opentype_script(const GdiFont *font)
4854 * I am not sure if this is the correct way to generate our script tag
4857 switch (font->charset)
4859 case ANSI_CHARSET: return "latn";
4860 case BALTIC_CHARSET: return "latn"; /* ?? */
4861 case CHINESEBIG5_CHARSET: return "hani";
4862 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4863 case GB2312_CHARSET: return "hani";
4864 case GREEK_CHARSET: return "grek";
4865 case HANGUL_CHARSET: return "hang";
4866 case RUSSIAN_CHARSET: return "cyrl";
4867 case SHIFTJIS_CHARSET: return "kana";
4868 case TURKISH_CHARSET: return "latn"; /* ?? */
4869 case VIETNAMESE_CHARSET: return "latn";
4870 case JOHAB_CHARSET: return "latn"; /* ?? */
4871 case ARABIC_CHARSET: return "arab";
4872 case HEBREW_CHARSET: return "hebr";
4873 case THAI_CHARSET: return "thai";
4874 default: return "latn";
4878 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4880 const GSUB_Header *header;
4881 const GSUB_Script *script;
4882 const GSUB_LangSys *language;
4883 const GSUB_Feature *feature;
4885 if (!font->GSUB_Table)
4888 header = font->GSUB_Table;
4890 script = GSUB_get_script_table(header, get_opentype_script(font));
4893 TRACE("Script not found\n");
4896 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4899 TRACE("Language not found\n");
4902 feature = GSUB_get_feature(header, language, "vrt2");
4904 feature = GSUB_get_feature(header, language, "vert");
4907 TRACE("vrt2/vert feature not found\n");
4910 return GSUB_apply_feature(header, feature, glyph);
4913 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4917 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4918 WCHAR wc = (WCHAR)glyph;
4920 BOOL *default_used_pointer;
4923 default_used_pointer = NULL;
4924 default_used = FALSE;
4925 if (codepage_sets_default_used(font->codepage))
4926 default_used_pointer = &default_used;
4927 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4930 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4931 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4932 return get_GSUB_vert_glyph(font,ret);
4935 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
4937 if (glyph < 0x100) glyph += 0xf000;
4938 /* there is a number of old pre-Unicode "broken" TTFs, which
4939 do have symbols at U+00XX instead of U+f0XX */
4940 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
4941 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
4943 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4945 return get_GSUB_vert_glyph(font,glyphId);
4948 /*************************************************************
4949 * WineEngGetGlyphIndices
4952 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4953 LPWORD pgi, DWORD flags)
4957 BOOL got_default = FALSE;
4959 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
4961 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4965 for(i = 0; i < count; i++)
4967 pgi[i] = get_glyph_index(font, lpstr[i]);
4972 if (FT_IS_SFNT(font->ft_face))
4974 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4975 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4980 WineEngGetTextMetrics(font, &textm);
4981 default_char = textm.tmDefaultChar;
4985 pgi[i] = default_char;
4991 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4993 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4994 return !memcmp(matrix, &identity, sizeof(FMAT2));
4997 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4999 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5000 return !memcmp(matrix, &identity, sizeof(MAT2));
5003 /*************************************************************
5004 * WineEngGetGlyphOutline
5006 * Behaves in exactly the same way as the win32 api GetGlyphOutline
5007 * except that the first parameter is the HWINEENGFONT of the font in
5008 * question rather than an HDC.
5011 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
5012 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5015 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5016 FT_Face ft_face = incoming_font->ft_face;
5017 GdiFont *font = incoming_font;
5018 FT_UInt glyph_index;
5019 DWORD width, height, pitch, needed = 0;
5020 FT_Bitmap ft_bitmap;
5022 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5024 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5025 double widthRatio = 1.0;
5026 FT_Matrix transMat = identityMat;
5027 FT_Matrix transMatUnrotated;
5028 BOOL needsTransform = FALSE;
5029 BOOL tategaki = (font->GSUB_Table != NULL);
5030 UINT original_index;
5032 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5033 buflen, buf, lpmat);
5035 TRACE("font transform %f %f %f %f\n",
5036 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5037 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5040 EnterCriticalSection( &freetype_cs );
5042 if(format & GGO_GLYPH_INDEX) {
5043 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5044 original_index = glyph;
5045 format &= ~GGO_GLYPH_INDEX;
5047 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5048 ft_face = font->ft_face;
5049 original_index = glyph_index;
5052 if(format & GGO_UNHINTED) {
5053 load_flags |= FT_LOAD_NO_HINTING;
5054 format &= ~GGO_UNHINTED;
5057 /* tategaki never appears to happen to lower glyph index */
5058 if (glyph_index < TATEGAKI_LOWER_BOUND )
5061 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5062 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5063 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5064 font->gmsize * sizeof(GM*));
5066 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5067 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5069 *lpgm = FONT_GM(font,original_index)->gm;
5070 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5071 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5072 lpgm->gmCellIncX, lpgm->gmCellIncY);
5073 LeaveCriticalSection( &freetype_cs );
5074 return 1; /* FIXME */
5078 if (!font->gm[original_index / GM_BLOCK_SIZE])
5079 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5081 /* Scaling factor */
5086 WineEngGetTextMetrics(font, &tm);
5088 widthRatio = (double)font->aveWidth;
5089 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5092 widthRatio = font->scale_y;
5094 /* Scaling transform */
5095 if (widthRatio != 1.0 || font->scale_y != 1.0)
5098 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5101 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5103 pFT_Matrix_Multiply(&scaleMat, &transMat);
5104 needsTransform = TRUE;
5107 /* Slant transform */
5108 if (font->fake_italic) {
5111 slantMat.xx = (1 << 16);
5112 slantMat.xy = ((1 << 16) >> 2);
5114 slantMat.yy = (1 << 16);
5115 pFT_Matrix_Multiply(&slantMat, &transMat);
5116 needsTransform = TRUE;
5119 /* Rotation transform */
5120 transMatUnrotated = transMat;
5121 if(font->orientation && !tategaki) {
5122 FT_Matrix rotationMat;
5124 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5125 pFT_Vector_Unit(&vecAngle, angle);
5126 rotationMat.xx = vecAngle.x;
5127 rotationMat.xy = -vecAngle.y;
5128 rotationMat.yx = -rotationMat.xy;
5129 rotationMat.yy = rotationMat.xx;
5131 pFT_Matrix_Multiply(&rotationMat, &transMat);
5132 needsTransform = TRUE;
5135 /* World transform */
5136 if (!is_identity_FMAT2(&font->font_desc.matrix))
5139 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5140 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5141 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5142 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5143 pFT_Matrix_Multiply(&worldMat, &transMat);
5144 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5145 needsTransform = TRUE;
5148 /* Extra transformation specified by caller */
5149 if (!is_identity_MAT2(lpmat))
5152 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5153 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5154 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5155 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5156 pFT_Matrix_Multiply(&extraMat, &transMat);
5157 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5158 needsTransform = TRUE;
5161 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5162 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5163 format == GGO_GRAY8_BITMAP))
5165 load_flags |= FT_LOAD_NO_BITMAP;
5168 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5171 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5172 LeaveCriticalSection( &freetype_cs );
5176 if(!needsTransform) {
5177 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5178 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5179 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5181 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5182 bottom = (ft_face->glyph->metrics.horiBearingY -
5183 ft_face->glyph->metrics.height) & -64;
5184 lpgm->gmCellIncX = adv;
5185 lpgm->gmCellIncY = 0;
5192 for(xc = 0; xc < 2; xc++) {
5193 for(yc = 0; yc < 2; yc++) {
5194 vec.x = (ft_face->glyph->metrics.horiBearingX +
5195 xc * ft_face->glyph->metrics.width);
5196 vec.y = ft_face->glyph->metrics.horiBearingY -
5197 yc * ft_face->glyph->metrics.height;
5198 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5199 pFT_Vector_Transform(&vec, &transMat);
5200 if(xc == 0 && yc == 0) {
5201 left = right = vec.x;
5202 top = bottom = vec.y;
5204 if(vec.x < left) left = vec.x;
5205 else if(vec.x > right) right = vec.x;
5206 if(vec.y < bottom) bottom = vec.y;
5207 else if(vec.y > top) top = vec.y;
5212 right = (right + 63) & -64;
5213 bottom = bottom & -64;
5214 top = (top + 63) & -64;
5216 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5217 vec.x = ft_face->glyph->metrics.horiAdvance;
5219 pFT_Vector_Transform(&vec, &transMat);
5220 lpgm->gmCellIncX = (vec.x+63) >> 6;
5221 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5223 vec.x = ft_face->glyph->metrics.horiAdvance;
5225 pFT_Vector_Transform(&vec, &transMatUnrotated);
5226 adv = (vec.x+63) >> 6;
5230 bbx = (right - left) >> 6;
5231 lpgm->gmBlackBoxX = (right - left) >> 6;
5232 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5233 lpgm->gmptGlyphOrigin.x = left >> 6;
5234 lpgm->gmptGlyphOrigin.y = top >> 6;
5236 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5237 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5238 lpgm->gmCellIncX, lpgm->gmCellIncY);
5240 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5241 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5243 FONT_GM(font,original_index)->gm = *lpgm;
5244 FONT_GM(font,original_index)->adv = adv;
5245 FONT_GM(font,original_index)->lsb = lsb;
5246 FONT_GM(font,original_index)->bbx = bbx;
5247 FONT_GM(font,original_index)->init = TRUE;
5250 if(format == GGO_METRICS)
5252 LeaveCriticalSection( &freetype_cs );
5253 return 1; /* FIXME */
5256 if(ft_face->glyph->format != ft_glyph_format_outline &&
5257 (format == GGO_NATIVE || format == GGO_BEZIER ||
5258 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5259 format == GGO_GRAY8_BITMAP))
5261 TRACE("loaded a bitmap\n");
5262 LeaveCriticalSection( &freetype_cs );
5268 width = lpgm->gmBlackBoxX;
5269 height = lpgm->gmBlackBoxY;
5270 pitch = ((width + 31) >> 5) << 2;
5271 needed = pitch * height;
5273 if(!buf || !buflen) break;
5275 switch(ft_face->glyph->format) {
5276 case ft_glyph_format_bitmap:
5278 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5279 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5280 INT h = ft_face->glyph->bitmap.rows;
5282 memcpy(dst, src, w);
5283 src += ft_face->glyph->bitmap.pitch;
5289 case ft_glyph_format_outline:
5290 ft_bitmap.width = width;
5291 ft_bitmap.rows = height;
5292 ft_bitmap.pitch = pitch;
5293 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5294 ft_bitmap.buffer = buf;
5297 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5299 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5301 /* Note: FreeType will only set 'black' bits for us. */
5302 memset(buf, 0, needed);
5303 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5307 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5308 LeaveCriticalSection( &freetype_cs );
5313 case GGO_GRAY2_BITMAP:
5314 case GGO_GRAY4_BITMAP:
5315 case GGO_GRAY8_BITMAP:
5316 case WINE_GGO_GRAY16_BITMAP:
5318 unsigned int mult, row, col;
5321 width = lpgm->gmBlackBoxX;
5322 height = lpgm->gmBlackBoxY;
5323 pitch = (width + 3) / 4 * 4;
5324 needed = pitch * height;
5326 if(!buf || !buflen) break;
5328 switch(ft_face->glyph->format) {
5329 case ft_glyph_format_bitmap:
5331 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5332 INT h = ft_face->glyph->bitmap.rows;
5334 memset( buf, 0, needed );
5336 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5337 if (src[x / 8] & (1 << ( (7 - (x % 8))))) dst[x] = 0xff;
5338 src += ft_face->glyph->bitmap.pitch;
5341 LeaveCriticalSection( &freetype_cs );
5344 case ft_glyph_format_outline:
5346 ft_bitmap.width = width;
5347 ft_bitmap.rows = height;
5348 ft_bitmap.pitch = pitch;
5349 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5350 ft_bitmap.buffer = buf;
5353 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5355 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5357 memset(ft_bitmap.buffer, 0, buflen);
5359 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5361 if(format == GGO_GRAY2_BITMAP)
5363 else if(format == GGO_GRAY4_BITMAP)
5365 else if(format == GGO_GRAY8_BITMAP)
5367 else /* format == WINE_GGO_GRAY16_BITMAP */
5369 LeaveCriticalSection( &freetype_cs );
5375 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5376 LeaveCriticalSection( &freetype_cs );
5381 for(row = 0; row < height; row++) {
5383 for(col = 0; col < width; col++, ptr++) {
5384 *ptr = (((int)*ptr) * mult + 128) / 256;
5391 case WINE_GGO_HRGB_BITMAP:
5392 case WINE_GGO_HBGR_BITMAP:
5393 case WINE_GGO_VRGB_BITMAP:
5394 case WINE_GGO_VBGR_BITMAP:
5395 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5397 switch (ft_face->glyph->format)
5399 case FT_GLYPH_FORMAT_BITMAP:
5404 width = lpgm->gmBlackBoxX;
5405 height = lpgm->gmBlackBoxY;
5407 needed = pitch * height;
5409 if (!buf || !buflen) break;
5411 memset(buf, 0, buflen);
5413 src = ft_face->glyph->bitmap.buffer;
5414 src_pitch = ft_face->glyph->bitmap.pitch;
5416 height = min( height, ft_face->glyph->bitmap.rows );
5419 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5421 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
5422 ((unsigned int *)dst)[x] = ~0u;
5431 case FT_GLYPH_FORMAT_OUTLINE:
5435 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5436 INT x_shift, y_shift;
5438 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5439 FT_Render_Mode render_mode =
5440 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5441 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5443 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5445 if ( render_mode == FT_RENDER_MODE_LCD)
5447 lpgm->gmBlackBoxX += 2;
5448 lpgm->gmptGlyphOrigin.x -= 1;
5452 lpgm->gmBlackBoxY += 2;
5453 lpgm->gmptGlyphOrigin.y += 1;
5457 width = lpgm->gmBlackBoxX;
5458 height = lpgm->gmBlackBoxY;
5460 needed = pitch * height;
5462 if (!buf || !buflen) break;
5464 memset(buf, 0, buflen);
5466 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5468 if ( needsTransform )
5469 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5471 if ( pFT_Library_SetLcdFilter )
5472 pFT_Library_SetLcdFilter( library, lcdfilter );
5473 pFT_Render_Glyph (ft_face->glyph, render_mode);
5475 src = ft_face->glyph->bitmap.buffer;
5476 src_pitch = ft_face->glyph->bitmap.pitch;
5477 src_width = ft_face->glyph->bitmap.width;
5478 src_height = ft_face->glyph->bitmap.rows;
5480 if ( render_mode == FT_RENDER_MODE_LCD)
5488 rgb_interval = src_pitch;
5493 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5494 if ( x_shift < 0 ) x_shift = 0;
5495 if ( x_shift + (src_width / hmul) > width )
5496 x_shift = width - (src_width / hmul);
5498 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5499 if ( y_shift < 0 ) y_shift = 0;
5500 if ( y_shift + (src_height / vmul) > height )
5501 y_shift = height - (src_height / vmul);
5503 dst += x_shift + y_shift * ( pitch / 4 );
5504 while ( src_height )
5506 for ( x = 0; x < src_width / hmul; x++ )
5510 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5511 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5512 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5513 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5517 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5518 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5519 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5520 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5523 src += src_pitch * vmul;
5532 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5533 LeaveCriticalSection ( &freetype_cs );
5540 LeaveCriticalSection( &freetype_cs );
5546 int contour, point = 0, first_pt;
5547 FT_Outline *outline = &ft_face->glyph->outline;
5548 TTPOLYGONHEADER *pph;
5550 DWORD pph_start, cpfx, type;
5552 if(buflen == 0) buf = NULL;
5554 if (needsTransform && buf) {
5555 pFT_Outline_Transform(outline, &transMat);
5558 for(contour = 0; contour < outline->n_contours; contour++) {
5560 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5563 pph->dwType = TT_POLYGON_TYPE;
5564 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5566 needed += sizeof(*pph);
5568 while(point <= outline->contours[contour]) {
5569 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5570 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5571 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5575 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5578 } while(point <= outline->contours[contour] &&
5579 (outline->tags[point] & FT_Curve_Tag_On) ==
5580 (outline->tags[point-1] & FT_Curve_Tag_On));
5581 /* At the end of a contour Windows adds the start point, but
5583 if(point > outline->contours[contour] &&
5584 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5586 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5588 } else if(point <= outline->contours[contour] &&
5589 outline->tags[point] & FT_Curve_Tag_On) {
5590 /* add closing pt for bezier */
5592 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5600 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5603 pph->cb = needed - pph_start;
5609 /* Convert the quadratic Beziers to cubic Beziers.
5610 The parametric eqn for a cubic Bezier is, from PLRM:
5611 r(t) = at^3 + bt^2 + ct + r0
5612 with the control points:
5617 A quadratic Bezier has the form:
5618 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5620 So equating powers of t leads to:
5621 r1 = 2/3 p1 + 1/3 p0
5622 r2 = 2/3 p1 + 1/3 p2
5623 and of course r0 = p0, r3 = p2
5626 int contour, point = 0, first_pt;
5627 FT_Outline *outline = &ft_face->glyph->outline;
5628 TTPOLYGONHEADER *pph;
5630 DWORD pph_start, cpfx, type;
5631 FT_Vector cubic_control[4];
5632 if(buflen == 0) buf = NULL;
5634 if (needsTransform && buf) {
5635 pFT_Outline_Transform(outline, &transMat);
5638 for(contour = 0; contour < outline->n_contours; contour++) {
5640 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5643 pph->dwType = TT_POLYGON_TYPE;
5644 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5646 needed += sizeof(*pph);
5648 while(point <= outline->contours[contour]) {
5649 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5650 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5651 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5654 if(type == TT_PRIM_LINE) {
5656 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5660 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5663 /* FIXME: Possible optimization in endpoint calculation
5664 if there are two consecutive curves */
5665 cubic_control[0] = outline->points[point-1];
5666 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5667 cubic_control[0].x += outline->points[point].x + 1;
5668 cubic_control[0].y += outline->points[point].y + 1;
5669 cubic_control[0].x >>= 1;
5670 cubic_control[0].y >>= 1;
5672 if(point+1 > outline->contours[contour])
5673 cubic_control[3] = outline->points[first_pt];
5675 cubic_control[3] = outline->points[point+1];
5676 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5677 cubic_control[3].x += outline->points[point].x + 1;
5678 cubic_control[3].y += outline->points[point].y + 1;
5679 cubic_control[3].x >>= 1;
5680 cubic_control[3].y >>= 1;
5683 /* r1 = 1/3 p0 + 2/3 p1
5684 r2 = 1/3 p2 + 2/3 p1 */
5685 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5686 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5687 cubic_control[2] = cubic_control[1];
5688 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5689 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5690 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5691 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5693 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5694 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5695 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5700 } while(point <= outline->contours[contour] &&
5701 (outline->tags[point] & FT_Curve_Tag_On) ==
5702 (outline->tags[point-1] & FT_Curve_Tag_On));
5703 /* At the end of a contour Windows adds the start point,
5704 but only for Beziers and we've already done that.
5706 if(point <= outline->contours[contour] &&
5707 outline->tags[point] & FT_Curve_Tag_On) {
5708 /* This is the closing pt of a bezier, but we've already
5709 added it, so just inc point and carry on */
5716 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5719 pph->cb = needed - pph_start;
5725 FIXME("Unsupported format %d\n", format);
5726 LeaveCriticalSection( &freetype_cs );
5729 LeaveCriticalSection( &freetype_cs );
5733 static BOOL get_bitmap_text_metrics(GdiFont *font)
5735 FT_Face ft_face = font->ft_face;
5736 FT_WinFNT_HeaderRec winfnt_header;
5737 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5738 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5739 font->potm->otmSize = size;
5741 #define TM font->potm->otmTextMetrics
5742 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5744 TM.tmHeight = winfnt_header.pixel_height;
5745 TM.tmAscent = winfnt_header.ascent;
5746 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5747 TM.tmInternalLeading = winfnt_header.internal_leading;
5748 TM.tmExternalLeading = winfnt_header.external_leading;
5749 TM.tmAveCharWidth = winfnt_header.avg_width;
5750 TM.tmMaxCharWidth = winfnt_header.max_width;
5751 TM.tmWeight = winfnt_header.weight;
5753 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5754 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5755 TM.tmFirstChar = winfnt_header.first_char;
5756 TM.tmLastChar = winfnt_header.last_char;
5757 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5758 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5759 TM.tmItalic = winfnt_header.italic;
5760 TM.tmUnderlined = font->underline;
5761 TM.tmStruckOut = font->strikeout;
5762 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5763 TM.tmCharSet = winfnt_header.charset;
5767 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5768 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5769 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5770 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5771 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5772 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5773 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5774 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5776 TM.tmDigitizedAspectX = 96; /* FIXME */
5777 TM.tmDigitizedAspectY = 96; /* FIXME */
5779 TM.tmLastChar = 255;
5780 TM.tmDefaultChar = 32;
5781 TM.tmBreakChar = 32;
5782 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5783 TM.tmUnderlined = font->underline;
5784 TM.tmStruckOut = font->strikeout;
5785 /* NB inverted meaning of TMPF_FIXED_PITCH */
5786 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5787 TM.tmCharSet = font->charset;
5795 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5797 double scale_x, scale_y;
5801 scale_x = (double)font->aveWidth;
5802 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5805 scale_x = font->scale_y;
5807 scale_x *= fabs(font->font_desc.matrix.eM11);
5808 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5810 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5811 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5813 SCALE_Y(ptm->tmHeight);
5814 SCALE_Y(ptm->tmAscent);
5815 SCALE_Y(ptm->tmDescent);
5816 SCALE_Y(ptm->tmInternalLeading);
5817 SCALE_Y(ptm->tmExternalLeading);
5818 SCALE_Y(ptm->tmOverhang);
5820 SCALE_X(ptm->tmAveCharWidth);
5821 SCALE_X(ptm->tmMaxCharWidth);
5827 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5829 double scale_x, scale_y;
5833 scale_x = (double)font->aveWidth;
5834 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5837 scale_x = font->scale_y;
5839 scale_x *= fabs(font->font_desc.matrix.eM11);
5840 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5842 scale_font_metrics(font, &potm->otmTextMetrics);
5844 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5845 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5847 SCALE_Y(potm->otmAscent);
5848 SCALE_Y(potm->otmDescent);
5849 SCALE_Y(potm->otmLineGap);
5850 SCALE_Y(potm->otmsCapEmHeight);
5851 SCALE_Y(potm->otmsXHeight);
5852 SCALE_Y(potm->otmrcFontBox.top);
5853 SCALE_Y(potm->otmrcFontBox.bottom);
5854 SCALE_X(potm->otmrcFontBox.left);
5855 SCALE_X(potm->otmrcFontBox.right);
5856 SCALE_Y(potm->otmMacAscent);
5857 SCALE_Y(potm->otmMacDescent);
5858 SCALE_Y(potm->otmMacLineGap);
5859 SCALE_X(potm->otmptSubscriptSize.x);
5860 SCALE_Y(potm->otmptSubscriptSize.y);
5861 SCALE_X(potm->otmptSubscriptOffset.x);
5862 SCALE_Y(potm->otmptSubscriptOffset.y);
5863 SCALE_X(potm->otmptSuperscriptSize.x);
5864 SCALE_Y(potm->otmptSuperscriptSize.y);
5865 SCALE_X(potm->otmptSuperscriptOffset.x);
5866 SCALE_Y(potm->otmptSuperscriptOffset.y);
5867 SCALE_Y(potm->otmsStrikeoutSize);
5868 SCALE_Y(potm->otmsStrikeoutPosition);
5869 SCALE_Y(potm->otmsUnderscoreSize);
5870 SCALE_Y(potm->otmsUnderscorePosition);
5876 /*************************************************************
5877 * WineEngGetTextMetrics
5880 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5883 EnterCriticalSection( &freetype_cs );
5885 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5886 if(!get_bitmap_text_metrics(font))
5888 LeaveCriticalSection( &freetype_cs );
5892 /* Make sure that the font has sane width/height ratio */
5895 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5897 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5903 *ptm = font->potm->otmTextMetrics;
5904 scale_font_metrics(font, ptm);
5905 LeaveCriticalSection( &freetype_cs );
5909 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5913 for(i = 0; i < ft_face->num_charmaps; i++)
5915 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5921 /*************************************************************
5922 * WineEngGetOutlineTextMetrics
5925 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5926 OUTLINETEXTMETRICW *potm)
5928 FT_Face ft_face = font->ft_face;
5929 UINT needed, lenfam, lensty, ret;
5931 TT_HoriHeader *pHori;
5932 TT_Postscript *pPost;
5933 FT_Fixed x_scale, y_scale;
5934 WCHAR *family_nameW, *style_nameW;
5935 static const WCHAR spaceW[] = {' ', '\0'};
5937 INT ascent, descent;
5939 TRACE("font=%p\n", font);
5941 if(!FT_IS_SCALABLE(ft_face))
5945 EnterCriticalSection( &freetype_cs );
5948 if(cbSize >= font->potm->otmSize)
5950 memcpy(potm, font->potm, font->potm->otmSize);
5951 scale_outline_font_metrics(font, potm);
5953 LeaveCriticalSection( &freetype_cs );
5954 return font->potm->otmSize;
5958 needed = sizeof(*potm);
5960 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5961 family_nameW = strdupW(font->name);
5963 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5965 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5966 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5967 style_nameW, lensty/sizeof(WCHAR));
5969 /* These names should be read from the TT name table */
5971 /* length of otmpFamilyName */
5974 /* length of otmpFaceName */
5975 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5976 needed += lenfam; /* just the family name */
5978 needed += lenfam + lensty; /* family + " " + style */
5981 /* length of otmpStyleName */
5984 /* length of otmpFullName */
5985 needed += lenfam + lensty;
5988 x_scale = ft_face->size->metrics.x_scale;
5989 y_scale = ft_face->size->metrics.y_scale;
5991 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5993 FIXME("Can't find OS/2 table - not TT font?\n");
5998 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6000 FIXME("Can't find HHEA table - not TT font?\n");
6005 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6007 TRACE("OS/2 winA = %d winD = %d typoA = %d typoD = %d typoLG = %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
6008 pOS2->usWinAscent, pOS2->usWinDescent,
6009 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6010 ft_face->ascender, ft_face->descender, ft_face->height,
6011 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6012 ft_face->bbox.yMax, ft_face->bbox.yMin);
6014 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6015 font->potm->otmSize = needed;
6017 #define TM font->potm->otmTextMetrics
6019 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6020 ascent = pHori->Ascender;
6021 descent = -pHori->Descender;
6023 ascent = pOS2->usWinAscent;
6024 descent = pOS2->usWinDescent;
6028 TM.tmAscent = font->yMax;
6029 TM.tmDescent = -font->yMin;
6030 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6032 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6033 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6034 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6035 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6038 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6041 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6043 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6044 ((ascent + descent) -
6045 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6047 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6048 if (TM.tmAveCharWidth == 0) {
6049 TM.tmAveCharWidth = 1;
6051 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6052 TM.tmWeight = FW_REGULAR;
6053 if (font->fake_bold)
6054 TM.tmWeight = FW_BOLD;
6057 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6059 if (pOS2->usWeightClass > FW_MEDIUM)
6060 TM.tmWeight = pOS2->usWeightClass;
6062 else if (pOS2->usWeightClass <= FW_MEDIUM)
6063 TM.tmWeight = pOS2->usWeightClass;
6066 TM.tmDigitizedAspectX = 300;
6067 TM.tmDigitizedAspectY = 300;
6068 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6069 * symbol range to 0 - f0ff
6072 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6077 case 1257: /* Baltic */
6078 TM.tmLastChar = 0xf8fd;
6081 TM.tmLastChar = 0xf0ff;
6083 TM.tmBreakChar = 0x20;
6084 TM.tmDefaultChar = 0x1f;
6088 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6089 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6091 if(pOS2->usFirstCharIndex <= 1)
6092 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6093 else if (pOS2->usFirstCharIndex > 0xff)
6094 TM.tmBreakChar = 0x20;
6096 TM.tmBreakChar = pOS2->usFirstCharIndex;
6097 TM.tmDefaultChar = TM.tmBreakChar - 1;
6099 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6100 TM.tmUnderlined = font->underline;
6101 TM.tmStruckOut = font->strikeout;
6103 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6104 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6105 (pOS2->version == 0xFFFFU ||
6106 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6107 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6109 TM.tmPitchAndFamily = 0;
6111 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6113 case PAN_FAMILY_SCRIPT:
6114 TM.tmPitchAndFamily |= FF_SCRIPT;
6117 case PAN_FAMILY_DECORATIVE:
6118 TM.tmPitchAndFamily |= FF_DECORATIVE;
6123 case PAN_FAMILY_TEXT_DISPLAY:
6124 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6125 /* which is clearly not what the panose spec says. */
6127 if(TM.tmPitchAndFamily == 0 || /* fixed */
6128 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6129 TM.tmPitchAndFamily = FF_MODERN;
6132 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6137 TM.tmPitchAndFamily |= FF_DONTCARE;
6140 case PAN_SERIF_COVE:
6141 case PAN_SERIF_OBTUSE_COVE:
6142 case PAN_SERIF_SQUARE_COVE:
6143 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6144 case PAN_SERIF_SQUARE:
6145 case PAN_SERIF_THIN:
6146 case PAN_SERIF_BONE:
6147 case PAN_SERIF_EXAGGERATED:
6148 case PAN_SERIF_TRIANGLE:
6149 TM.tmPitchAndFamily |= FF_ROMAN;
6152 case PAN_SERIF_NORMAL_SANS:
6153 case PAN_SERIF_OBTUSE_SANS:
6154 case PAN_SERIF_PERP_SANS:
6155 case PAN_SERIF_FLARED:
6156 case PAN_SERIF_ROUNDED:
6157 TM.tmPitchAndFamily |= FF_SWISS;
6164 if(FT_IS_SCALABLE(ft_face))
6165 TM.tmPitchAndFamily |= TMPF_VECTOR;
6167 if(FT_IS_SFNT(ft_face))
6169 if (font->ntmFlags & NTM_PS_OPENTYPE)
6170 TM.tmPitchAndFamily |= TMPF_DEVICE;
6172 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6175 TM.tmCharSet = font->charset;
6177 font->potm->otmFiller = 0;
6178 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6179 font->potm->otmfsSelection = pOS2->fsSelection;
6180 font->potm->otmfsType = pOS2->fsType;
6181 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6182 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6183 font->potm->otmItalicAngle = 0; /* POST table */
6184 font->potm->otmEMSquare = ft_face->units_per_EM;
6185 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6186 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6187 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6188 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6189 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6190 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6191 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6192 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6193 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6194 font->potm->otmMacAscent = TM.tmAscent;
6195 font->potm->otmMacDescent = -TM.tmDescent;
6196 font->potm->otmMacLineGap = font->potm->otmLineGap;
6197 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6198 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6199 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6200 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6201 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6202 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6203 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6204 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6205 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6206 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6207 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6209 font->potm->otmsUnderscoreSize = 0;
6210 font->potm->otmsUnderscorePosition = 0;
6212 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6213 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6217 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6218 cp = (char*)font->potm + sizeof(*font->potm);
6219 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6220 strcpyW((WCHAR*)cp, family_nameW);
6222 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6223 strcpyW((WCHAR*)cp, style_nameW);
6225 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6226 strcpyW((WCHAR*)cp, family_nameW);
6227 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6228 strcatW((WCHAR*)cp, spaceW);
6229 strcatW((WCHAR*)cp, style_nameW);
6230 cp += lenfam + lensty;
6233 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6234 strcpyW((WCHAR*)cp, family_nameW);
6235 strcatW((WCHAR*)cp, spaceW);
6236 strcatW((WCHAR*)cp, style_nameW);
6239 if(potm && needed <= cbSize)
6241 memcpy(potm, font->potm, font->potm->otmSize);
6242 scale_outline_font_metrics(font, potm);
6246 HeapFree(GetProcessHeap(), 0, style_nameW);
6247 HeapFree(GetProcessHeap(), 0, family_nameW);
6249 LeaveCriticalSection( &freetype_cs );
6253 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6255 HFONTLIST *hfontlist;
6256 child->font = alloc_font();
6257 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6258 if(!child->font->ft_face)
6260 free_font(child->font);
6265 child->font->font_desc = font->font_desc;
6266 child->font->ntmFlags = child->face->ntmFlags;
6267 child->font->orientation = font->orientation;
6268 child->font->scale_y = font->scale_y;
6269 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6270 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6271 child->font->name = strdupW(child->face->family->FamilyName);
6272 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6273 child->font->base_font = font;
6274 list_add_head(&child_font_list, &child->font->entry);
6275 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6279 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6282 CHILD_FONT *child_font;
6285 font = font->base_font;
6287 *linked_font = font;
6289 if((*glyph = get_glyph_index(font, c)))
6292 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6294 if(!child_font->font)
6295 if(!load_child_font(font, child_font))
6298 if(!child_font->font->ft_face)
6300 g = get_glyph_index(child_font->font, c);
6304 *linked_font = child_font->font;
6311 /*************************************************************
6312 * WineEngGetCharWidth
6315 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6318 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6321 FT_UInt glyph_index;
6322 GdiFont *linked_font;
6324 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
6327 EnterCriticalSection( &freetype_cs );
6328 for(c = firstChar; c <= lastChar; c++) {
6329 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6330 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6331 &gm, 0, NULL, &identity);
6332 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6334 LeaveCriticalSection( &freetype_cs );
6338 /*************************************************************
6339 * WineEngGetCharABCWidths
6342 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6345 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6348 FT_UInt glyph_index;
6349 GdiFont *linked_font;
6351 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
6353 if(!FT_IS_SCALABLE(font->ft_face))
6357 EnterCriticalSection( &freetype_cs );
6359 for(c = firstChar; c <= lastChar; c++) {
6360 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6361 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6362 &gm, 0, NULL, &identity);
6363 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6364 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6365 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6366 FONT_GM(linked_font,glyph_index)->bbx;
6368 LeaveCriticalSection( &freetype_cs );
6372 /*************************************************************
6373 * WineEngGetCharABCWidthsFloat
6376 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
6378 static const MAT2 identity = {{0,1}, {0,0}, {0,0}, {0,1}};
6381 FT_UInt glyph_index;
6382 GdiFont *linked_font;
6384 TRACE("%p, %d, %d, %p\n", font, first, last, buffer);
6387 EnterCriticalSection( &freetype_cs );
6389 for (c = first; c <= last; c++)
6391 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
6392 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6393 &gm, 0, NULL, &identity);
6394 buffer[c - first].abcfA = FONT_GM(linked_font, glyph_index)->lsb;
6395 buffer[c - first].abcfB = FONT_GM(linked_font, glyph_index)->bbx;
6396 buffer[c - first].abcfC = FONT_GM(linked_font, glyph_index)->adv -
6397 FONT_GM(linked_font, glyph_index)->lsb -
6398 FONT_GM(linked_font, glyph_index)->bbx;
6400 LeaveCriticalSection( &freetype_cs );
6404 /*************************************************************
6405 * WineEngGetCharABCWidthsI
6408 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6411 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6414 FT_UInt glyph_index;
6415 GdiFont *linked_font;
6417 if(!FT_HAS_HORIZONTAL(font->ft_face))
6421 EnterCriticalSection( &freetype_cs );
6423 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
6425 for(c = firstChar; c < firstChar+count; c++) {
6426 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6427 &gm, 0, NULL, &identity);
6428 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6429 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6430 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6431 - FONT_GM(linked_font,c)->bbx;
6434 for(c = 0; c < count; c++) {
6435 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6436 &gm, 0, NULL, &identity);
6437 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6438 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6439 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6440 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6443 LeaveCriticalSection( &freetype_cs );
6447 /*************************************************************
6448 * WineEngGetTextExtentExPoint
6451 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6452 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6454 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6459 FT_UInt glyph_index;
6460 GdiFont *linked_font;
6462 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
6466 EnterCriticalSection( &freetype_cs );
6469 WineEngGetTextMetrics(font, &tm);
6470 size->cy = tm.tmHeight;
6472 for(idx = 0; idx < count; idx++) {
6473 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
6474 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6475 &gm, 0, NULL, &identity);
6476 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6478 if (! pnfit || ext <= max_ext) {
6488 LeaveCriticalSection( &freetype_cs );
6489 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6493 /*************************************************************
6494 * WineEngGetTextExtentExPointI
6497 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6498 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6500 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6506 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
6509 EnterCriticalSection( &freetype_cs );
6512 WineEngGetTextMetrics(font, &tm);
6513 size->cy = tm.tmHeight;
6515 for(idx = 0; idx < count; idx++) {
6516 WineEngGetGlyphOutline(font, indices[idx],
6517 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
6519 size->cx += FONT_GM(font,indices[idx])->adv;
6521 if (! pnfit || ext <= max_ext) {
6531 LeaveCriticalSection( &freetype_cs );
6532 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6536 /*************************************************************
6537 * WineEngGetFontData
6540 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6543 FT_Face ft_face = font->ft_face;
6547 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6548 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6549 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6551 if(!FT_IS_SFNT(ft_face))
6559 if(table) { /* MS tags differ in endianness from FT ones */
6560 table = table >> 24 | table << 24 |
6561 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
6564 /* make sure value of len is the value freetype says it needs */
6567 FT_ULong needed = 0;
6568 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
6569 if( !err && needed < len) len = needed;
6571 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
6574 TRACE("Can't find table %c%c%c%c\n",
6575 /* bytes were reversed */
6576 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
6577 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
6583 /*************************************************************
6584 * WineEngGetTextFace
6587 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6589 INT n = strlenW(font->name) + 1;
6591 lstrcpynW(str, font->name, count);
6592 return min(count, n);
6597 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6599 if (fs) *fs = font->fs;
6600 return font->charset;
6603 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6605 GdiFont *font = dc->gdiFont, *linked_font;
6606 struct list *first_hfont;
6610 EnterCriticalSection( &freetype_cs );
6611 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6612 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6613 if(font == linked_font)
6614 *new_hfont = dc->hFont;
6617 first_hfont = list_head(&linked_font->hfontlist);
6618 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6620 LeaveCriticalSection( &freetype_cs );
6624 /* Retrieve a list of supported Unicode ranges for a given font.
6625 * Can be called with NULL gs to calculate the buffer size. Returns
6626 * the number of ranges found.
6628 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6630 DWORD num_ranges = 0;
6632 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6635 FT_ULong char_code, char_code_prev;
6638 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6640 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6641 face->num_glyphs, glyph_code, char_code);
6643 if (!glyph_code) return 0;
6647 gs->ranges[0].wcLow = (USHORT)char_code;
6648 gs->ranges[0].cGlyphs = 0;
6649 gs->cGlyphsSupported = 0;
6655 if (char_code < char_code_prev)
6657 ERR("expected increasing char code from FT_Get_Next_Char\n");
6660 if (char_code - char_code_prev > 1)
6665 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6666 gs->ranges[num_ranges - 1].cGlyphs = 1;
6667 gs->cGlyphsSupported++;
6672 gs->ranges[num_ranges - 1].cGlyphs++;
6673 gs->cGlyphsSupported++;
6675 char_code_prev = char_code;
6676 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6680 FIXME("encoding %u not supported\n", face->charmap->encoding);
6685 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6688 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
6690 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6693 glyphset->cbThis = size;
6694 glyphset->cRanges = num_ranges;
6695 glyphset->flAccel = 0;
6700 /*************************************************************
6703 BOOL WineEngFontIsLinked(GdiFont *font)
6707 EnterCriticalSection( &freetype_cs );
6708 ret = !list_empty(&font->child_fonts);
6709 LeaveCriticalSection( &freetype_cs );
6713 static BOOL is_hinting_enabled(void)
6715 /* Use the >= 2.2.0 function if available */
6716 if(pFT_Get_TrueType_Engine_Type)
6718 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6719 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6721 #ifdef FT_DRIVER_HAS_HINTER
6726 /* otherwise if we've been compiled with < 2.2.0 headers
6727 use the internal macro */
6728 mod = pFT_Get_Module(library, "truetype");
6729 if(mod && FT_DRIVER_HAS_HINTER(mod))
6737 static BOOL is_subpixel_rendering_enabled( void )
6739 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6740 return pFT_Library_SetLcdFilter &&
6741 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6747 /*************************************************************************
6748 * GetRasterizerCaps (GDI32.@)
6750 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6752 static int hinting = -1;
6753 static int subpixel = -1;
6757 hinting = is_hinting_enabled();
6758 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6761 if ( subpixel == -1 )
6763 subpixel = is_subpixel_rendering_enabled();
6764 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6767 lprs->nSize = sizeof(RASTERIZER_STATUS);
6768 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6770 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6771 lprs->nLanguageID = 0;
6775 /*************************************************************
6776 * WineEngRealizationInfo
6778 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6780 FIXME("(%p, %p): stub!\n", font, info);
6783 if(FT_IS_SCALABLE(font->ft_face))
6786 info->cache_num = font->cache_num;
6787 info->unknown2 = -1;
6791 /*************************************************************************
6792 * Kerning support for TrueType fonts
6794 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6796 struct TT_kern_table
6802 struct TT_kern_subtable
6811 USHORT horizontal : 1;
6813 USHORT cross_stream: 1;
6814 USHORT override : 1;
6815 USHORT reserved1 : 4;
6821 struct TT_format0_kern_subtable
6825 USHORT entrySelector;
6836 static DWORD parse_format0_kern_subtable(GdiFont *font,
6837 const struct TT_format0_kern_subtable *tt_f0_ks,
6838 const USHORT *glyph_to_char,
6839 KERNINGPAIR *kern_pair, DWORD cPairs)
6842 const struct TT_kern_pair *tt_kern_pair;
6844 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6846 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6848 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6849 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6850 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6852 if (!kern_pair || !cPairs)
6855 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6857 nPairs = min(nPairs, cPairs);
6859 for (i = 0; i < nPairs; i++)
6861 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6862 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6863 /* this algorithm appears to better match what Windows does */
6864 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6865 if (kern_pair->iKernAmount < 0)
6867 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6868 kern_pair->iKernAmount -= font->ppem;
6870 else if (kern_pair->iKernAmount > 0)
6872 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6873 kern_pair->iKernAmount += font->ppem;
6875 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6877 TRACE("left %u right %u value %d\n",
6878 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6882 TRACE("copied %u entries\n", nPairs);
6886 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6890 const struct TT_kern_table *tt_kern_table;
6891 const struct TT_kern_subtable *tt_kern_subtable;
6893 USHORT *glyph_to_char;
6896 EnterCriticalSection( &freetype_cs );
6897 if (font->total_kern_pairs != (DWORD)-1)
6899 if (cPairs && kern_pair)
6901 cPairs = min(cPairs, font->total_kern_pairs);
6902 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6903 LeaveCriticalSection( &freetype_cs );
6906 LeaveCriticalSection( &freetype_cs );
6907 return font->total_kern_pairs;
6910 font->total_kern_pairs = 0;
6912 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6914 if (length == GDI_ERROR)
6916 TRACE("no kerning data in the font\n");
6917 LeaveCriticalSection( &freetype_cs );
6921 buf = HeapAlloc(GetProcessHeap(), 0, length);
6924 WARN("Out of memory\n");
6925 LeaveCriticalSection( &freetype_cs );
6929 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6931 /* build a glyph index to char code map */
6932 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6935 WARN("Out of memory allocating a glyph index to char code map\n");
6936 HeapFree(GetProcessHeap(), 0, buf);
6937 LeaveCriticalSection( &freetype_cs );
6941 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
6947 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6949 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6950 font->ft_face->num_glyphs, glyph_code, char_code);
6954 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6956 /* FIXME: This doesn't match what Windows does: it does some fancy
6957 * things with duplicate glyph index to char code mappings, while
6958 * we just avoid overriding existing entries.
6960 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6961 glyph_to_char[glyph_code] = (USHORT)char_code;
6963 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6970 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6971 for (n = 0; n <= 65535; n++)
6972 glyph_to_char[n] = (USHORT)n;
6975 tt_kern_table = buf;
6976 nTables = GET_BE_WORD(tt_kern_table->nTables);
6977 TRACE("version %u, nTables %u\n",
6978 GET_BE_WORD(tt_kern_table->version), nTables);
6980 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6982 for (i = 0; i < nTables; i++)
6984 struct TT_kern_subtable tt_kern_subtable_copy;
6986 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6987 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6988 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6990 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6991 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6992 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6994 /* According to the TrueType specification this is the only format
6995 * that will be properly interpreted by Windows and OS/2
6997 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6999 DWORD new_chunk, old_total = font->total_kern_pairs;
7001 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7002 glyph_to_char, NULL, 0);
7003 font->total_kern_pairs += new_chunk;
7005 if (!font->kern_pairs)
7006 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7007 font->total_kern_pairs * sizeof(*font->kern_pairs));
7009 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7010 font->total_kern_pairs * sizeof(*font->kern_pairs));
7012 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7013 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7016 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7018 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7021 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7022 HeapFree(GetProcessHeap(), 0, buf);
7024 if (cPairs && kern_pair)
7026 cPairs = min(cPairs, font->total_kern_pairs);
7027 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7028 LeaveCriticalSection( &freetype_cs );
7031 LeaveCriticalSection( &freetype_cs );
7032 return font->total_kern_pairs;
7035 static const struct gdi_dc_funcs freetype_funcs =
7037 NULL, /* pAbortDoc */
7038 NULL, /* pAbortPath */
7039 NULL, /* pAlphaBlend */
7040 NULL, /* pAngleArc */
7043 NULL, /* pBeginPath */
7044 NULL, /* pBlendImage */
7045 NULL, /* pChoosePixelFormat */
7047 NULL, /* pCloseFigure */
7048 NULL, /* pCreateBitmap */
7049 NULL, /* pCreateCompatibleDC */
7050 freetype_CreateDC, /* pCreateDC */
7051 NULL, /* pCreateDIBSection */
7052 NULL, /* pDeleteBitmap */
7053 freetype_DeleteDC, /* pDeleteDC */
7054 NULL, /* pDeleteObject */
7055 NULL, /* pDescribePixelFormat */
7056 NULL, /* pDeviceCapabilities */
7057 NULL, /* pEllipse */
7059 NULL, /* pEndPage */
7060 NULL, /* pEndPath */
7061 NULL, /* pEnumDeviceFonts */
7062 NULL, /* pEnumICMProfiles */
7063 NULL, /* pExcludeClipRect */
7064 NULL, /* pExtDeviceMode */
7065 NULL, /* pExtEscape */
7066 NULL, /* pExtFloodFill */
7067 NULL, /* pExtSelectClipRgn */
7068 NULL, /* pExtTextOut */
7069 NULL, /* pFillPath */
7070 NULL, /* pFillRgn */
7071 NULL, /* pFlattenPath */
7072 NULL, /* pFrameRgn */
7073 NULL, /* pGdiComment */
7074 NULL, /* pGetCharWidth */
7075 NULL, /* pGetDeviceCaps */
7076 NULL, /* pGetDeviceGammaRamp */
7077 NULL, /* pGetICMProfile */
7078 NULL, /* pGetImage */
7079 NULL, /* pGetNearestColor */
7080 NULL, /* pGetPixel */
7081 NULL, /* pGetPixelFormat */
7082 NULL, /* pGetSystemPaletteEntries */
7083 NULL, /* pGetTextExtentExPoint */
7084 NULL, /* pGetTextMetrics */
7085 NULL, /* pIntersectClipRect */
7086 NULL, /* pInvertRgn */
7088 NULL, /* pModifyWorldTransform */
7090 NULL, /* pOffsetClipRgn */
7091 NULL, /* pOffsetViewportOrg */
7092 NULL, /* pOffsetWindowOrg */
7093 NULL, /* pPaintRgn */
7096 NULL, /* pPolyBezier */
7097 NULL, /* pPolyBezierTo */
7098 NULL, /* pPolyDraw */
7099 NULL, /* pPolyPolygon */
7100 NULL, /* pPolyPolyline */
7101 NULL, /* pPolygon */
7102 NULL, /* pPolyline */
7103 NULL, /* pPolylineTo */
7104 NULL, /* pPutImage */
7105 NULL, /* pRealizeDefaultPalette */
7106 NULL, /* pRealizePalette */
7107 NULL, /* pRectangle */
7108 NULL, /* pResetDC */
7109 NULL, /* pRestoreDC */
7110 NULL, /* pRoundRect */
7112 NULL, /* pScaleViewportExt */
7113 NULL, /* pScaleWindowExt */
7114 NULL, /* pSelectBitmap */
7115 NULL, /* pSelectBrush */
7116 NULL, /* pSelectClipPath */
7117 freetype_SelectFont, /* pSelectFont */
7118 NULL, /* pSelectPalette */
7119 NULL, /* pSelectPen */
7120 NULL, /* pSetArcDirection */
7121 NULL, /* pSetBkColor */
7122 NULL, /* pSetBkMode */
7123 NULL, /* pSetDCBrushColor */
7124 NULL, /* pSetDCPenColor */
7125 NULL, /* pSetDIBColorTable */
7126 NULL, /* pSetDIBitsToDevice */
7127 NULL, /* pSetDeviceClipping */
7128 NULL, /* pSetDeviceGammaRamp */
7129 NULL, /* pSetLayout */
7130 NULL, /* pSetMapMode */
7131 NULL, /* pSetMapperFlags */
7132 NULL, /* pSetPixel */
7133 NULL, /* pSetPixelFormat */
7134 NULL, /* pSetPolyFillMode */
7135 NULL, /* pSetROP2 */
7136 NULL, /* pSetRelAbs */
7137 NULL, /* pSetStretchBltMode */
7138 NULL, /* pSetTextAlign */
7139 NULL, /* pSetTextCharacterExtra */
7140 NULL, /* pSetTextColor */
7141 NULL, /* pSetTextJustification */
7142 NULL, /* pSetViewportExt */
7143 NULL, /* pSetViewportOrg */
7144 NULL, /* pSetWindowExt */
7145 NULL, /* pSetWindowOrg */
7146 NULL, /* pSetWorldTransform */
7147 NULL, /* pStartDoc */
7148 NULL, /* pStartPage */
7149 NULL, /* pStretchBlt */
7150 NULL, /* pStretchDIBits */
7151 NULL, /* pStrokeAndFillPath */
7152 NULL, /* pStrokePath */
7153 NULL, /* pSwapBuffers */
7154 NULL, /* pUnrealizePalette */
7155 NULL, /* pWidenPath */
7156 /* OpenGL not supported */
7159 #else /* HAVE_FREETYPE */
7161 /*************************************************************************/
7163 BOOL WineEngInit(void)
7167 BOOL WineEngDestroyFontInstance(HFONT hfont)
7172 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
7177 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
7178 LPWORD pgi, DWORD flags)
7183 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
7184 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
7187 ERR("called but we don't have FreeType\n");
7191 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
7193 ERR("called but we don't have FreeType\n");
7197 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
7198 OUTLINETEXTMETRICW *potm)
7200 ERR("called but we don't have FreeType\n");
7204 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
7207 ERR("called but we don't have FreeType\n");
7211 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
7214 ERR("called but we don't have FreeType\n");
7218 BOOL WineEngGetCharABCWidthsFloat(GdiFont *font, UINT first, UINT last, LPABCFLOAT buffer)
7220 ERR("called but we don't have FreeType\n");
7224 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
7227 ERR("called but we don't have FreeType\n");
7231 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
7232 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
7234 ERR("called but we don't have FreeType\n");
7238 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
7239 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
7241 ERR("called but we don't have FreeType\n");
7245 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
7248 ERR("called but we don't have FreeType\n");
7252 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
7254 ERR("called but we don't have FreeType\n");
7258 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7260 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7264 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7266 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7270 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7272 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7276 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
7278 FIXME("(%p, %p, %u): stub\n", font, fs, flags);
7279 return DEFAULT_CHARSET;
7282 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7287 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
7289 FIXME("(%p, %p): stub\n", font, glyphset);
7293 BOOL WineEngFontIsLinked(GdiFont *font)
7298 /*************************************************************************
7299 * GetRasterizerCaps (GDI32.@)
7301 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7303 lprs->nSize = sizeof(RASTERIZER_STATUS);
7305 lprs->nLanguageID = 0;
7309 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
7311 ERR("called but we don't have FreeType\n");
7315 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
7317 ERR("called but we don't have FreeType\n");
7321 #endif /* HAVE_FREETYPE */