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>
46 #include "gdi_private.h"
47 #include "wine/unicode.h"
48 #include "wine/debug.h"
49 #include "wine/list.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(font);
55 #ifdef HAVE_FT2BUILD_H
58 #ifdef HAVE_FREETYPE_FREETYPE_H
59 #include <freetype/freetype.h>
61 #ifdef HAVE_FREETYPE_FTGLYPH_H
62 #include <freetype/ftglyph.h>
64 #ifdef HAVE_FREETYPE_TTTABLES_H
65 #include <freetype/tttables.h>
67 #ifdef HAVE_FREETYPE_FTSNAMES_H
68 #include <freetype/ftsnames.h>
70 # ifdef HAVE_FREETYPE_FTNAMES_H
71 # include <freetype/ftnames.h>
74 #ifdef HAVE_FREETYPE_TTNAMEID_H
75 #include <freetype/ttnameid.h>
77 #ifdef HAVE_FREETYPE_FTOUTLN_H
78 #include <freetype/ftoutln.h>
80 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
81 #include <freetype/internal/sfnt.h>
83 #ifdef HAVE_FREETYPE_FTTRIGON_H
84 #include <freetype/fttrigon.h>
86 #ifdef HAVE_FREETYPE_FTWINFNT_H
87 #include <freetype/ftwinfnt.h>
89 #ifdef HAVE_FREETYPE_FTMODAPI_H
90 #include <freetype/ftmodapi.h>
93 #ifndef SONAME_LIBFREETYPE
94 #define SONAME_LIBFREETYPE "libfreetype.so"
97 #ifndef HAVE_FT_TRUETYPEENGINETYPE
100 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
101 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
102 FT_TRUETYPE_ENGINE_TYPE_PATENTED
103 } FT_TrueTypeEngineType;
106 static FT_Library library = 0;
113 static FT_Version_t FT_Version;
114 static DWORD FT_SimpleVersion;
116 static void *ft_handle = NULL;
118 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
119 MAKE_FUNCPTR(FT_Vector_Unit);
120 MAKE_FUNCPTR(FT_Done_Face);
121 MAKE_FUNCPTR(FT_Get_Char_Index);
122 MAKE_FUNCPTR(FT_Get_Module);
123 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
124 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
125 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
126 MAKE_FUNCPTR(FT_Init_FreeType);
127 MAKE_FUNCPTR(FT_Load_Glyph);
128 MAKE_FUNCPTR(FT_Matrix_Multiply);
129 MAKE_FUNCPTR(FT_MulFix);
130 MAKE_FUNCPTR(FT_New_Face);
131 MAKE_FUNCPTR(FT_New_Memory_Face);
132 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
133 MAKE_FUNCPTR(FT_Outline_Transform);
134 MAKE_FUNCPTR(FT_Outline_Translate);
135 MAKE_FUNCPTR(FT_Select_Charmap);
136 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
137 MAKE_FUNCPTR(FT_Vector_Transform);
138 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
139 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
140 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
141 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
142 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
143 #ifdef HAVE_FREETYPE_FTWINFNT_H
144 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
147 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
148 #include <fontconfig/fontconfig.h>
149 MAKE_FUNCPTR(FcConfigGetCurrent);
150 MAKE_FUNCPTR(FcFontList);
151 MAKE_FUNCPTR(FcFontSetDestroy);
152 MAKE_FUNCPTR(FcInit);
153 MAKE_FUNCPTR(FcObjectSetAdd);
154 MAKE_FUNCPTR(FcObjectSetCreate);
155 MAKE_FUNCPTR(FcObjectSetDestroy);
156 MAKE_FUNCPTR(FcPatternCreate);
157 MAKE_FUNCPTR(FcPatternDestroy);
158 MAKE_FUNCPTR(FcPatternGetString);
159 #ifndef SONAME_LIBFONTCONFIG
160 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
166 #ifndef ft_encoding_none
167 #define FT_ENCODING_NONE ft_encoding_none
169 #ifndef ft_encoding_ms_symbol
170 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
172 #ifndef ft_encoding_unicode
173 #define FT_ENCODING_UNICODE ft_encoding_unicode
175 #ifndef ft_encoding_apple_roman
176 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
179 #ifdef WORDS_BIGENDIAN
180 #define GET_BE_WORD(x) (x)
182 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
185 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
192 FT_Short internal_leading;
195 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
196 So to let this compile on older versions of FreeType we'll define the
197 new structure here. */
199 FT_Short height, width;
200 FT_Pos size, x_ppem, y_ppem;
203 typedef struct tagFace {
211 FONTSIGNATURE fs_links;
212 FT_Fixed font_version;
214 Bitmap_Size size; /* set if face is a bitmap */
215 BOOL external; /* TRUE if we should manually add this font to the registry */
216 struct tagFamily *family;
219 typedef struct tagFamily {
221 const WCHAR *FamilyName;
227 INT adv; /* These three hold to widths of the unrotated chars */
245 typedef struct tagHFONTLIST {
260 struct font_mapping *mapping;
271 struct list hfontlist;
276 OUTLINETEXTMETRICW *potm;
277 DWORD total_kern_pairs;
278 KERNINGPAIR *kern_pairs;
281 struct list child_fonts;
287 const WCHAR *font_name;
291 #define INIT_GM_SIZE 128
293 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
294 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
295 #define UNUSED_CACHE_SIZE 10
296 static struct list child_font_list = LIST_INIT(child_font_list);
297 static struct list system_links = LIST_INIT(system_links);
299 static struct list font_subst_list = LIST_INIT(font_subst_list);
301 static struct list font_list = LIST_INIT(font_list);
303 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
304 'R','o','m','a','n','\0'};
305 static const WCHAR defSans[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
306 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
308 static const WCHAR defSystem[] = {'S','y','s','t','e','m','\0'};
309 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
310 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
311 'S','e','r','i','f','\0'};
312 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
313 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
315 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
316 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
317 'W','i','n','d','o','w','s','\\',
318 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
319 'F','o','n','t','s','\0'};
321 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
322 'W','i','n','d','o','w','s',' ','N','T','\\',
323 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
324 'F','o','n','t','s','\0'};
326 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
327 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
328 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
329 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
331 static const WCHAR * const SystemFontValues[4] = {
338 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
339 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
341 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
342 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
343 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
344 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
345 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
346 'E','u','r','o','p','e','a','n','\0'};
347 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
348 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
349 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
350 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
351 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
352 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
353 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
354 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
355 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
356 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
357 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
358 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
360 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
370 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
378 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
387 typedef struct tagFontSubst {
403 static struct list mappings_list = LIST_INIT( mappings_list );
405 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
407 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
410 /****************************************
411 * Notes on .fon files
413 * The fonts System, FixedSys and Terminal are special. There are typically multiple
414 * versions installed for different resolutions and codepages. Windows stores which one to use
415 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
417 * FIXEDFON.FON FixedSys
419 * OEMFONT.FON Terminal
420 * LogPixels Current dpi set by the display control panel applet
421 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
422 * also has a LogPixels value that appears to mirror this)
424 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
425 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
426 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
427 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
428 * so that makes sense.
430 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
431 * to be mapped into the registry on Windows 2000 at least).
434 * ega80woa.fon=ega80850.fon
435 * ega40woa.fon=ega40850.fon
436 * cga80woa.fon=cga80850.fon
437 * cga40woa.fon=cga40850.fon
441 static inline BOOL is_win9x(void)
443 return GetVersion() & 0x80000000;
446 This function builds an FT_Fixed from a float. It puts the integer part
447 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
448 It fails if the integer part of the float number is greater than SHORT_MAX.
450 static inline FT_Fixed FT_FixedFromFloat(float f)
453 unsigned short fract = (f - value) * 0xFFFF;
454 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
458 This function builds an FT_Fixed from a FIXED. It simply put f.value
459 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
461 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
463 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
467 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
472 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
473 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
475 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
476 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
478 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
480 if(face_name && strcmpiW(face_name, family->FamilyName))
482 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
484 file = strrchr(face->file, '/');
489 if(!strcasecmp(file, file_nameA))
491 HeapFree(GetProcessHeap(), 0, file_nameA);
496 HeapFree(GetProcessHeap(), 0, file_nameA);
500 static Family *find_family_from_name(const WCHAR *name)
504 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
506 if(!strcmpiW(family->FamilyName, name))
513 static void DumpSubstList(void)
517 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
519 if(psub->from.charset != -1 || psub->to.charset != -1)
520 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
521 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
523 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
524 debugstr_w(psub->to.name));
529 static LPWSTR strdupW(LPCWSTR p)
532 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
533 ret = HeapAlloc(GetProcessHeap(), 0, len);
538 static LPSTR strdupA(LPCSTR p)
541 DWORD len = (strlen(p) + 1);
542 ret = HeapAlloc(GetProcessHeap(), 0, len);
547 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
552 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
554 if(!strcmpiW(element->from.name, from_name) &&
555 (element->from.charset == from_charset ||
556 element->from.charset == -1))
563 #define ADD_FONT_SUBST_FORCE 1
565 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
567 FontSubst *from_exist, *to_exist;
569 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
571 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
573 list_remove(&from_exist->entry);
574 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
575 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
576 HeapFree(GetProcessHeap(), 0, from_exist);
582 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
586 HeapFree(GetProcessHeap(), 0, subst->to.name);
587 subst->to.name = strdupW(to_exist->to.name);
590 list_add_tail(subst_list, &subst->entry);
595 HeapFree(GetProcessHeap(), 0, subst->from.name);
596 HeapFree(GetProcessHeap(), 0, subst->to.name);
597 HeapFree(GetProcessHeap(), 0, subst);
601 static void split_subst_info(NameCs *nc, LPSTR str)
603 CHAR *p = strrchr(str, ',');
608 nc->charset = strtol(p+1, NULL, 10);
611 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
612 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
613 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
616 static void LoadSubstList(void)
620 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
624 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
625 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
626 &hkey) == ERROR_SUCCESS) {
628 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
629 &valuelen, &datalen, NULL, NULL);
631 valuelen++; /* returned value doesn't include room for '\0' */
632 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
633 data = HeapAlloc(GetProcessHeap(), 0, datalen);
637 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
638 &dlen) == ERROR_SUCCESS) {
639 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
641 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
642 split_subst_info(&psub->from, value);
643 split_subst_info(&psub->to, data);
645 /* Win 2000 doesn't allow mapping between different charsets
646 or mapping of DEFAULT_CHARSET */
647 if((psub->to.charset != psub->from.charset) ||
648 psub->to.charset == DEFAULT_CHARSET) {
649 HeapFree(GetProcessHeap(), 0, psub->to.name);
650 HeapFree(GetProcessHeap(), 0, psub->from.name);
651 HeapFree(GetProcessHeap(), 0, psub);
653 add_font_subst(&font_subst_list, psub, 0);
655 /* reset dlen and vlen */
659 HeapFree(GetProcessHeap(), 0, data);
660 HeapFree(GetProcessHeap(), 0, value);
665 static WCHAR *get_familyname(FT_Face ft_face)
667 WCHAR *family = NULL;
669 FT_UInt num_names, name_index, i;
671 if(FT_IS_SFNT(ft_face))
673 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
675 for(name_index = 0; name_index < num_names; name_index++)
677 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
679 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
680 (name.language_id == GetUserDefaultLCID()) &&
681 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
682 (name.encoding_id == TT_MS_ID_UNICODE_CS))
684 /* String is not nul terminated and string_len is a byte length. */
685 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
686 for(i = 0; i < name.string_len / 2; i++)
688 WORD *tmp = (WORD *)&name.string[i * 2];
689 family[i] = GET_BE_WORD(*tmp);
693 TRACE("Got localised name %s\n", debugstr_w(family));
704 #define ADDFONT_EXTERNAL_FONT 0x01
705 #define ADDFONT_FORCE_BITMAP 0x02
706 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
710 TT_Header *pHeader = NULL;
711 WCHAR *english_family, *localised_family, *StyleW;
715 struct list *family_elem_ptr, *face_elem_ptr;
717 FT_Long face_index = 0, num_faces;
718 #ifdef HAVE_FREETYPE_FTWINFNT_H
719 FT_WinFNT_HeaderRec winfnt_header;
721 int i, bitmap_num, internal_leading;
725 char *family_name = fake_family;
727 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
728 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
729 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
733 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*/
734 WARN("Ignoring font %s\n", debugstr_a(file));
735 pFT_Done_Face(ft_face);
739 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
740 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
741 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file));
742 pFT_Done_Face(ft_face);
746 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
747 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
748 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
749 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
750 "Skipping this font.\n", debugstr_a(file));
751 pFT_Done_Face(ft_face);
755 if(!ft_face->family_name || !ft_face->style_name) {
756 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
757 pFT_Done_Face(ft_face);
762 family_name = ft_face->family_name;
766 My_FT_Bitmap_Size *size = NULL;
768 if(!FT_IS_SCALABLE(ft_face))
769 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
771 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
772 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
773 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
775 localised_family = NULL;
777 localised_family = get_familyname(ft_face);
778 if(localised_family && !strcmpW(localised_family, english_family)) {
779 HeapFree(GetProcessHeap(), 0, localised_family);
780 localised_family = NULL;
785 LIST_FOR_EACH(family_elem_ptr, &font_list) {
786 family = LIST_ENTRY(family_elem_ptr, Family, entry);
787 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
792 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
793 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
794 list_init(&family->faces);
795 list_add_tail(&font_list, &family->entry);
797 if(localised_family) {
798 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
799 subst->from.name = strdupW(english_family);
800 subst->from.charset = -1;
801 subst->to.name = strdupW(localised_family);
802 subst->to.charset = -1;
803 add_font_subst(&font_subst_list, subst, 0);
806 HeapFree(GetProcessHeap(), 0, localised_family);
807 HeapFree(GetProcessHeap(), 0, english_family);
809 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
810 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
811 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
813 internal_leading = 0;
814 memset(&fs, 0, sizeof(fs));
816 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
818 fs.fsCsb[0] = pOS2->ulCodePageRange1;
819 fs.fsCsb[1] = pOS2->ulCodePageRange2;
820 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
821 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
822 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
823 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
824 if(pOS2->version == 0) {
827 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
830 fs.fsCsb[0] |= 1L << 31;
833 #ifdef HAVE_FREETYPE_FTWINFNT_H
834 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
836 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
837 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
838 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
839 memcpy(&fs, &csi.fs, sizeof(csi.fs));
840 internal_leading = winfnt_header.internal_leading;
844 face_elem_ptr = list_head(&family->faces);
845 while(face_elem_ptr) {
846 face = LIST_ENTRY(face_elem_ptr, Face, entry);
847 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
848 if(!strcmpW(face->StyleName, StyleW) &&
849 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
850 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
851 debugstr_w(family->FamilyName), debugstr_w(StyleW),
852 face->font_version, pHeader ? pHeader->Font_Revision : 0);
855 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
856 HeapFree(GetProcessHeap(), 0, StyleW);
857 pFT_Done_Face(ft_face);
860 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
861 TRACE("Original font is newer so skipping this one\n");
862 HeapFree(GetProcessHeap(), 0, StyleW);
863 pFT_Done_Face(ft_face);
866 TRACE("Replacing original with this one\n");
867 list_remove(&face->entry);
868 HeapFree(GetProcessHeap(), 0, face->file);
869 HeapFree(GetProcessHeap(), 0, face->StyleName);
870 HeapFree(GetProcessHeap(), 0, face);
875 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
876 list_add_tail(&family->faces, &face->entry);
877 face->StyleName = StyleW;
878 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
879 strcpy(face->file, file);
880 face->face_index = face_index;
881 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
882 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
883 face->font_version = pHeader ? pHeader->Font_Revision : 0;
884 face->family = family;
885 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
886 memcpy(&face->fs, &fs, sizeof(face->fs));
887 memset(&face->fs_links, 0, sizeof(face->fs_links));
889 if(FT_IS_SCALABLE(ft_face)) {
890 memset(&face->size, 0, sizeof(face->size));
891 face->scalable = TRUE;
893 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
894 size->height, size->width, size->size >> 6,
895 size->x_ppem >> 6, size->y_ppem >> 6);
896 face->size.height = size->height;
897 face->size.width = size->width;
898 face->size.size = size->size;
899 face->size.x_ppem = size->x_ppem;
900 face->size.y_ppem = size->y_ppem;
901 face->size.internal_leading = internal_leading;
902 face->scalable = FALSE;
905 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
906 face->fs.fsCsb[0], face->fs.fsCsb[1],
907 face->fs.fsUsb[0], face->fs.fsUsb[1],
908 face->fs.fsUsb[2], face->fs.fsUsb[3]);
911 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
912 for(i = 0; i < ft_face->num_charmaps; i++) {
913 switch(ft_face->charmaps[i]->encoding) {
914 case FT_ENCODING_UNICODE:
915 case FT_ENCODING_APPLE_ROMAN:
916 face->fs.fsCsb[0] |= 1;
918 case FT_ENCODING_MS_SYMBOL:
919 face->fs.fsCsb[0] |= 1L << 31;
927 if(face->fs.fsCsb[0] & ~(1L << 31))
928 have_installed_roman_font = TRUE;
929 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
931 num_faces = ft_face->num_faces;
932 pFT_Done_Face(ft_face);
933 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
935 } while(num_faces > ++face_index);
939 static void DumpFontList(void)
943 struct list *family_elem_ptr, *face_elem_ptr;
945 LIST_FOR_EACH(family_elem_ptr, &font_list) {
946 family = LIST_ENTRY(family_elem_ptr, Family, entry);
947 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
948 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
949 face = LIST_ENTRY(face_elem_ptr, Face, entry);
950 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
952 TRACE(" %d", face->size.height);
959 /***********************************************************
960 * The replacement list is a way to map an entire font
961 * family onto another family. For example adding
963 * [HKCU\Software\Wine\Fonts\Replacements]
964 * "Wingdings"="Winedings"
966 * would enumerate the Winedings font both as Winedings and
967 * Wingdings. However if a real Wingdings font is present the
968 * replacement does not take place.
971 static void LoadReplaceList(void)
974 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
979 struct list *family_elem_ptr, *face_elem_ptr;
980 WCHAR old_nameW[200];
982 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
983 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
985 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
986 &valuelen, &datalen, NULL, NULL);
988 valuelen++; /* returned value doesn't include room for '\0' */
989 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
990 data = HeapAlloc(GetProcessHeap(), 0, datalen);
994 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
995 &dlen) == ERROR_SUCCESS) {
996 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
997 /* "NewName"="Oldname" */
998 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)/sizeof(WCHAR)))
1001 /* Find the old family and hence all of the font files
1003 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1004 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1005 if(!strcmpiW(family->FamilyName, old_nameW)) {
1006 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1007 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1008 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1009 debugstr_w(face->StyleName), value);
1010 /* Now add a new entry with the new family name */
1011 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1016 /* reset dlen and vlen */
1020 HeapFree(GetProcessHeap(), 0, data);
1021 HeapFree(GetProcessHeap(), 0, value);
1026 /*************************************************************
1029 static BOOL init_system_links(void)
1031 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1032 'W','i','n','d','o','w','s',' ','N','T','\\',
1033 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1034 'S','y','s','t','e','m','L','i','n','k',0};
1037 DWORD type, max_val, max_data, val_len, data_len, index;
1038 WCHAR *value, *data;
1039 WCHAR *entry, *next;
1040 SYSTEM_LINKS *font_link, *system_font_link;
1041 CHILD_FONT *child_font;
1042 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1043 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1044 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1050 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1052 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1053 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1054 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1055 val_len = max_val + 1;
1056 data_len = max_data;
1058 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1060 TRACE("%s:\n", debugstr_w(value));
1062 memset(&fs, 0, sizeof(fs));
1063 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1064 psub = get_font_subst(&font_subst_list, value, -1);
1065 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1066 list_init(&font_link->links);
1067 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1070 CHILD_FONT *child_font;
1072 TRACE("\t%s\n", debugstr_w(entry));
1074 next = entry + strlenW(entry) + 1;
1076 face_name = strchrW(entry, ',');
1080 while(isspaceW(*face_name))
1083 psub = get_font_subst(&font_subst_list, face_name, -1);
1085 face_name = psub->to.name;
1087 face = find_face_from_filename(entry, face_name);
1090 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1094 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1095 child_font->file_name = strdupA(face->file);
1096 child_font->index = face->face_index;
1097 child_font->font = NULL;
1098 fs.fsCsb[0] |= face->fs.fsCsb[0];
1099 fs.fsCsb[1] |= face->fs.fsCsb[1];
1100 TRACE("Adding file %s index %d\n", child_font->file_name, child_font->index);
1101 list_add_tail(&font_link->links, &child_font->entry);
1103 family = find_family_from_name(font_link->font_name);
1106 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1108 memcpy(&face->fs_links, &fs, sizeof(fs));
1111 list_add_tail(&system_links, &font_link->entry);
1112 val_len = max_val + 1;
1113 data_len = max_data;
1116 HeapFree(GetProcessHeap(), 0, value);
1117 HeapFree(GetProcessHeap(), 0, data);
1121 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1124 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1125 system_font_link->font_name = strdupW(System);
1126 list_init(&system_font_link->links);
1128 face = find_face_from_filename(tahoma_ttf, Tahoma);
1131 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1132 child_font->file_name = strdupA(face->file);
1133 child_font->index = face->face_index;
1134 child_font->font = NULL;
1135 TRACE("Found Tahoma in %s index %d\n", child_font->file_name, child_font->index);
1136 list_add_tail(&system_font_link->links, &child_font->entry);
1138 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1140 if(!strcmpiW(font_link->font_name, Tahoma))
1142 CHILD_FONT *font_link_entry;
1143 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1145 CHILD_FONT *new_child;
1146 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1147 new_child->file_name = strdupA(font_link_entry->file_name);
1148 new_child->index = font_link_entry->index;
1149 new_child->font = NULL;
1150 list_add_tail(&system_font_link->links, &new_child->entry);
1155 list_add_tail(&system_links, &system_font_link->entry);
1159 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1162 struct dirent *dent;
1163 char path[MAX_PATH];
1165 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1167 dir = opendir(dirname);
1169 WARN("Can't open directory %s\n", debugstr_a(dirname));
1172 while((dent = readdir(dir)) != NULL) {
1173 struct stat statbuf;
1175 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1178 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1180 sprintf(path, "%s/%s", dirname, dent->d_name);
1182 if(stat(path, &statbuf) == -1)
1184 WARN("Can't stat %s\n", debugstr_a(path));
1187 if(S_ISDIR(statbuf.st_mode))
1188 ReadFontDir(path, external_fonts);
1190 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1196 static void load_fontconfig_fonts(void)
1198 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1199 void *fc_handle = NULL;
1208 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1210 TRACE("Wine cannot find the fontconfig library (%s).\n",
1211 SONAME_LIBFONTCONFIG);
1214 #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;}
1215 LOAD_FUNCPTR(FcConfigGetCurrent);
1216 LOAD_FUNCPTR(FcFontList);
1217 LOAD_FUNCPTR(FcFontSetDestroy);
1218 LOAD_FUNCPTR(FcInit);
1219 LOAD_FUNCPTR(FcObjectSetAdd);
1220 LOAD_FUNCPTR(FcObjectSetCreate);
1221 LOAD_FUNCPTR(FcObjectSetDestroy);
1222 LOAD_FUNCPTR(FcPatternCreate);
1223 LOAD_FUNCPTR(FcPatternDestroy);
1224 LOAD_FUNCPTR(FcPatternGetString);
1227 if(!pFcInit()) return;
1229 config = pFcConfigGetCurrent();
1230 pat = pFcPatternCreate();
1231 os = pFcObjectSetCreate();
1232 pFcObjectSetAdd(os, FC_FILE);
1233 fontset = pFcFontList(config, pat, os);
1234 if(!fontset) return;
1235 for(i = 0; i < fontset->nfont; i++) {
1236 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1238 TRACE("fontconfig: %s\n", file);
1240 /* We're just interested in OT/TT fonts for now, so this hack just
1241 picks up the standard extensions to save time loading every other
1243 len = strlen( file );
1244 if(len < 4) continue;
1245 ext = &file[ len - 3 ];
1246 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
1247 AddFontFileToList(file, NULL, ADDFONT_EXTERNAL_FONT);
1249 pFcFontSetDestroy(fontset);
1250 pFcObjectSetDestroy(os);
1251 pFcPatternDestroy(pat);
1257 static BOOL load_font_from_data_dir(LPCWSTR file)
1260 const char *data_dir = wine_get_data_dir();
1262 if (!data_dir) data_dir = wine_get_build_dir();
1269 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1271 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1273 strcpy(unix_name, data_dir);
1274 strcat(unix_name, "/fonts/");
1276 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1278 ret = AddFontFileToList(unix_name, NULL, ADDFONT_FORCE_BITMAP);
1279 HeapFree(GetProcessHeap(), 0, unix_name);
1284 static void load_system_fonts(void)
1287 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1288 const WCHAR * const *value;
1290 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1293 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1294 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1295 strcatW(windowsdir, fontsW);
1296 for(value = SystemFontValues; *value; value++) {
1297 dlen = sizeof(data);
1298 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1302 sprintfW(pathW, fmtW, windowsdir, data);
1303 if((unixname = wine_get_unix_file_name(pathW))) {
1304 added = AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1305 HeapFree(GetProcessHeap(), 0, unixname);
1308 load_font_from_data_dir(data);
1315 /*************************************************************
1317 * This adds registry entries for any externally loaded fonts
1318 * (fonts from fontconfig or FontDirs). It also deletes entries
1319 * of no longer existing fonts.
1322 static void update_reg_entries(void)
1324 HKEY winkey = 0, externalkey = 0;
1327 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1330 struct list *family_elem_ptr, *face_elem_ptr;
1332 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1333 static const WCHAR spaceW[] = {' ', '\0'};
1336 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1337 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1338 ERR("Can't create Windows font reg key\n");
1341 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1342 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1343 ERR("Can't create external font reg key\n");
1347 /* Delete all external fonts added last time */
1349 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1350 &valuelen, &datalen, NULL, NULL);
1351 valuelen++; /* returned value doesn't include room for '\0' */
1352 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1353 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1355 dlen = datalen * sizeof(WCHAR);
1358 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1359 &dlen) == ERROR_SUCCESS) {
1361 RegDeleteValueW(winkey, valueW);
1362 /* reset dlen and vlen */
1366 HeapFree(GetProcessHeap(), 0, data);
1367 HeapFree(GetProcessHeap(), 0, valueW);
1369 /* Delete the old external fonts key */
1370 RegCloseKey(externalkey);
1372 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1374 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1375 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1376 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1377 ERR("Can't create external font reg key\n");
1381 /* enumerate the fonts and add external ones to the two keys */
1383 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1384 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1385 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1386 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1387 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1388 if(!face->external) continue;
1390 if(strcmpiW(face->StyleName, RegularW))
1391 len = len_fam + strlenW(face->StyleName) + 1;
1392 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1393 strcpyW(valueW, family->FamilyName);
1394 if(len != len_fam) {
1395 strcatW(valueW, spaceW);
1396 strcatW(valueW, face->StyleName);
1398 strcatW(valueW, TrueType);
1399 if((path = strrchr(face->file, '/')) == NULL)
1403 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1405 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1406 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1407 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1408 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1410 HeapFree(GetProcessHeap(), 0, file);
1411 HeapFree(GetProcessHeap(), 0, valueW);
1416 RegCloseKey(externalkey);
1418 RegCloseKey(winkey);
1423 /*************************************************************
1424 * WineEngAddFontResourceEx
1427 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1429 if (ft_handle) /* do it only if we have freetype up and running */
1434 FIXME("Ignoring flags %x\n", flags);
1436 if((unixname = wine_get_unix_file_name(file)))
1438 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1439 HeapFree(GetProcessHeap(), 0, unixname);
1445 /*************************************************************
1446 * WineEngRemoveFontResourceEx
1449 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1455 static const struct nls_update_font_list
1457 UINT ansi_cp, oem_cp;
1458 const char *oem, *fixed, *system;
1459 const char *courier, *serif, *small, *sserif;
1460 } nls_update_font_list[] =
1462 /* Latin 1 (United States) */
1463 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1464 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1466 /* Latin 1 (Multilingual) */
1467 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1468 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1470 /* Eastern Europe */
1471 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1472 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1475 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1476 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1479 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1480 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1483 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1484 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1487 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1488 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1491 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1492 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1495 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1496 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1499 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1500 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1503 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1504 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1507 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1508 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1510 /* Chinese Simplified */
1511 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1512 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1515 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1516 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1518 /* Chinese Traditional */
1519 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1520 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1524 inline static HKEY create_fonts_NT_registry_key(void)
1528 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1529 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1533 inline static HKEY create_fonts_9x_registry_key(void)
1537 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1538 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1542 inline static HKEY create_config_fonts_registry_key(void)
1546 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1547 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1551 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1553 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1554 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1555 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1556 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1559 static void update_font_info(void)
1561 char buf[40], cpbuf[40];
1564 UINT i, ansi_cp = 0, oem_cp = 0;
1566 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) != ERROR_SUCCESS)
1569 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1570 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1571 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1572 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1573 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
1576 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1578 if (!strcmp( buf, cpbuf )) /* already set correctly */
1583 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
1585 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
1587 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
1590 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1592 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1593 nls_update_font_list[i].oem_cp == oem_cp)
1597 hkey = create_config_fonts_registry_key();
1598 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1599 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1600 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1603 hkey = create_fonts_NT_registry_key();
1604 add_font_list(hkey, &nls_update_font_list[i]);
1607 hkey = create_fonts_9x_registry_key();
1608 add_font_list(hkey, &nls_update_font_list[i]);
1614 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
1617 /*************************************************************
1620 * Initialize FreeType library and create a list of available faces
1622 BOOL WineEngInit(void)
1624 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1625 static const WCHAR pathW[] = {'P','a','t','h',0};
1627 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1629 WCHAR windowsdir[MAX_PATH];
1632 const char *data_dir;
1636 /* update locale dependent font info in registry */
1639 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1642 "Wine cannot find the FreeType font library. To enable Wine to\n"
1643 "use TrueType fonts please install a version of FreeType greater than\n"
1644 "or equal to 2.0.5.\n"
1645 "http://www.freetype.org\n");
1649 #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;}
1651 LOAD_FUNCPTR(FT_Vector_Unit)
1652 LOAD_FUNCPTR(FT_Done_Face)
1653 LOAD_FUNCPTR(FT_Get_Char_Index)
1654 LOAD_FUNCPTR(FT_Get_Module)
1655 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1656 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1657 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1658 LOAD_FUNCPTR(FT_Init_FreeType)
1659 LOAD_FUNCPTR(FT_Load_Glyph)
1660 LOAD_FUNCPTR(FT_Matrix_Multiply)
1661 LOAD_FUNCPTR(FT_MulFix)
1662 LOAD_FUNCPTR(FT_New_Face)
1663 LOAD_FUNCPTR(FT_New_Memory_Face)
1664 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1665 LOAD_FUNCPTR(FT_Outline_Transform)
1666 LOAD_FUNCPTR(FT_Outline_Translate)
1667 LOAD_FUNCPTR(FT_Select_Charmap)
1668 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1669 LOAD_FUNCPTR(FT_Vector_Transform)
1672 /* Don't warn if this one is missing */
1673 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1674 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1675 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1676 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
1677 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
1678 #ifdef HAVE_FREETYPE_FTWINFNT_H
1679 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1681 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1682 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1683 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1684 <= 2.0.3 has FT_Sqrt64 */
1688 if(pFT_Init_FreeType(&library) != 0) {
1689 ERR("Can't init FreeType library\n");
1690 wine_dlclose(ft_handle, NULL, 0);
1694 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1695 if (pFT_Library_Version)
1697 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1699 if (FT_Version.major<=0)
1705 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1706 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1707 ((FT_Version.minor << 8) & 0x00ff00) |
1708 ((FT_Version.patch ) & 0x0000ff);
1710 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1711 ERR("Failed to create font mutex\n");
1714 WaitForSingleObject(font_mutex, INFINITE);
1716 /* load the system bitmap fonts */
1717 load_system_fonts();
1719 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1720 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1721 strcatW(windowsdir, fontsW);
1722 if((unixname = wine_get_unix_file_name(windowsdir)))
1724 ReadFontDir(unixname, FALSE);
1725 HeapFree(GetProcessHeap(), 0, unixname);
1728 /* load the system truetype fonts */
1729 data_dir = wine_get_data_dir();
1730 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
1731 strcpy(unixname, data_dir);
1732 strcat(unixname, "/fonts/");
1733 ReadFontDir(unixname, FALSE);
1734 HeapFree(GetProcessHeap(), 0, unixname);
1737 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1738 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1739 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1741 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1742 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1743 &hkey) == ERROR_SUCCESS) {
1745 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1746 &valuelen, &datalen, NULL, NULL);
1748 valuelen++; /* returned value doesn't include room for '\0' */
1749 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1750 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1753 dlen = datalen * sizeof(WCHAR);
1755 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1756 &dlen) == ERROR_SUCCESS) {
1757 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1759 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1761 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1762 HeapFree(GetProcessHeap(), 0, unixname);
1765 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1767 WCHAR pathW[MAX_PATH];
1768 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1771 sprintfW(pathW, fmtW, windowsdir, data);
1772 if((unixname = wine_get_unix_file_name(pathW)))
1774 added = AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1775 HeapFree(GetProcessHeap(), 0, unixname);
1778 load_font_from_data_dir(data);
1780 /* reset dlen and vlen */
1785 HeapFree(GetProcessHeap(), 0, data);
1786 HeapFree(GetProcessHeap(), 0, valueW);
1790 load_fontconfig_fonts();
1792 /* then look in any directories that we've specified in the config file */
1793 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
1794 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
1800 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
1802 len += sizeof(WCHAR);
1803 valueW = HeapAlloc( GetProcessHeap(), 0, len );
1804 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
1806 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
1807 valueA = HeapAlloc( GetProcessHeap(), 0, len );
1808 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
1809 TRACE( "got font path %s\n", debugstr_a(valueA) );
1813 LPSTR next = strchr( ptr, ':' );
1814 if (next) *next++ = 0;
1815 ReadFontDir( ptr, TRUE );
1818 HeapFree( GetProcessHeap(), 0, valueA );
1820 HeapFree( GetProcessHeap(), 0, valueW );
1829 update_reg_entries();
1831 init_system_links();
1833 ReleaseMutex(font_mutex);
1837 "Wine cannot find certain functions that it needs inside the FreeType\n"
1838 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1839 "FreeType to at least version 2.0.5.\n"
1840 "http://www.freetype.org\n");
1841 wine_dlclose(ft_handle, NULL, 0);
1847 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1850 TT_HoriHeader *pHori;
1854 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1855 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1857 if(height == 0) height = 16;
1859 /* Calc. height of EM square:
1861 * For +ve lfHeight we have
1862 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1863 * Re-arranging gives:
1864 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1866 * For -ve lfHeight we have
1868 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1869 * with il = winAscent + winDescent - units_per_em]
1874 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1875 ppem = ft_face->units_per_EM * height /
1876 (pHori->Ascender - pHori->Descender);
1878 ppem = ft_face->units_per_EM * height /
1879 (pOS2->usWinAscent + pOS2->usWinDescent);
1887 static struct font_mapping *map_font( const char *name )
1889 #ifndef __APPLE__ /* Mac OS fonts use resource forks, we can't simply mmap them */
1890 struct font_mapping *mapping;
1894 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
1895 if (fstat( fd, &st ) == -1) goto error;
1897 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
1899 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
1901 mapping->refcount++;
1906 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
1909 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
1912 if (mapping->data == MAP_FAILED)
1914 HeapFree( GetProcessHeap(), 0, mapping );
1917 mapping->refcount = 1;
1918 mapping->dev = st.st_dev;
1919 mapping->ino = st.st_ino;
1920 mapping->size = st.st_size;
1921 list_add_tail( &mappings_list, &mapping->entry );
1930 static void unmap_font( struct font_mapping *mapping )
1932 if (!--mapping->refcount)
1934 list_remove( &mapping->entry );
1935 munmap( mapping->data, mapping->size );
1936 HeapFree( GetProcessHeap(), 0, mapping );
1940 static LONG load_VDMX(GdiFont*, LONG);
1942 static FT_Face OpenFontFile(GdiFont *font, char *file, FT_Long face_index, LONG width, LONG height)
1947 TRACE("%s, %ld, %d x %d\n", debugstr_a(file), face_index, width, height);
1949 if ((font->mapping = map_font( file )))
1950 err = pFT_New_Memory_Face(library, font->mapping->data, font->mapping->size, face_index, &ft_face);
1952 err = pFT_New_Face(library, file, face_index, &ft_face);
1955 ERR("FT_New_Face rets %d\n", err);
1959 /* set it here, as load_VDMX needs it */
1960 font->ft_face = ft_face;
1962 if(FT_IS_SCALABLE(ft_face)) {
1963 /* load the VDMX table if we have one */
1964 font->ppem = load_VDMX(font, height);
1966 font->ppem = calc_ppem_for_height(ft_face, height);
1968 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
1969 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
1971 font->ppem = height;
1972 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1973 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
1979 static int get_nearest_charset(Face *face, int *cp)
1981 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1982 a single face with the requested charset. The idea is to check if
1983 the selected font supports the current ANSI codepage, if it does
1984 return the corresponding charset, else return the first charset */
1987 int acp = GetACP(), i;
1991 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
1992 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
1993 return csi.ciCharset;
1995 for(i = 0; i < 32; i++) {
1997 if(face->fs.fsCsb[0] & fs0) {
1998 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2000 return csi.ciCharset;
2003 FIXME("TCI failing on %x\n", fs0);
2007 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2008 face->fs.fsCsb[0], face->file);
2010 return DEFAULT_CHARSET;
2013 static GdiFont *alloc_font(void)
2015 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2016 ret->gmsize = INIT_GM_SIZE;
2017 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2018 ret->gmsize * sizeof(*ret->gm));
2020 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2021 ret->total_kern_pairs = (DWORD)-1;
2022 ret->kern_pairs = NULL;
2023 list_init(&ret->hfontlist);
2024 list_init(&ret->child_fonts);
2028 static void free_font(GdiFont *font)
2030 struct list *cursor, *cursor2;
2032 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2034 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2035 struct list *first_hfont;
2036 HFONTLIST *hfontlist;
2037 list_remove(cursor);
2040 first_hfont = list_head(&child->font->hfontlist);
2041 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2042 DeleteObject(hfontlist->hfont);
2043 HeapFree(GetProcessHeap(), 0, hfontlist);
2044 free_font(child->font);
2046 HeapFree(GetProcessHeap(), 0, child->file_name);
2047 HeapFree(GetProcessHeap(), 0, child);
2050 if (font->ft_face) pFT_Done_Face(font->ft_face);
2051 if (font->mapping) unmap_font( font->mapping );
2052 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2053 HeapFree(GetProcessHeap(), 0, font->potm);
2054 HeapFree(GetProcessHeap(), 0, font->name);
2055 HeapFree(GetProcessHeap(), 0, font->gm);
2056 HeapFree(GetProcessHeap(), 0, font);
2060 /*************************************************************
2063 * load the vdmx entry for the specified height
2066 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2067 ( ( (FT_ULong)_x4 << 24 ) | \
2068 ( (FT_ULong)_x3 << 16 ) | \
2069 ( (FT_ULong)_x2 << 8 ) | \
2072 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2087 static LONG load_VDMX(GdiFont *font, LONG height)
2091 BYTE devXRatio, devYRatio;
2092 USHORT numRecs, numRatios;
2093 DWORD result, offset = -1;
2097 /* For documentation on VDMX records, see
2098 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2101 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2103 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2106 /* FIXME: need the real device aspect ratio */
2110 numRecs = GET_BE_WORD(hdr[1]);
2111 numRatios = GET_BE_WORD(hdr[2]);
2113 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2114 for(i = 0; i < numRatios; i++) {
2117 offset = (3 * 2) + (i * sizeof(Ratios));
2118 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2121 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2123 if((ratio.xRatio == 0 &&
2124 ratio.yStartRatio == 0 &&
2125 ratio.yEndRatio == 0) ||
2126 (devXRatio == ratio.xRatio &&
2127 devYRatio >= ratio.yStartRatio &&
2128 devYRatio <= ratio.yEndRatio))
2130 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2131 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2132 offset = GET_BE_WORD(tmp);
2138 FIXME("No suitable ratio found\n");
2142 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2144 BYTE startsz, endsz;
2147 recs = GET_BE_WORD(group.recs);
2148 startsz = group.startsz;
2149 endsz = group.endsz;
2151 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2153 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2154 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2155 if(result == GDI_ERROR) {
2156 FIXME("Failed to retrieve vTable\n");
2161 for(i = 0; i < recs; i++) {
2162 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2163 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2164 ppem = GET_BE_WORD(vTable[i * 3]);
2166 if(yMax + -yMin == height) {
2169 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2172 if(yMax + -yMin > height) {
2175 goto end; /* failed */
2177 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2178 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2179 ppem = GET_BE_WORD(vTable[i * 3]);
2180 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2186 TRACE("ppem not found for height %d\n", height);
2190 if(ppem < startsz || ppem > endsz)
2193 for(i = 0; i < recs; i++) {
2195 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2197 if(yPelHeight > ppem)
2200 if(yPelHeight == ppem) {
2201 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2202 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2203 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2209 HeapFree(GetProcessHeap(), 0, vTable);
2215 static BOOL fontcmp(GdiFont *font, FONT_DESC *fd)
2217 if(font->font_desc.hash != fd->hash) return TRUE;
2218 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2219 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2220 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2221 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2224 static void calc_hash(FONT_DESC *pfd)
2226 DWORD hash = 0, *ptr, two_chars;
2230 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2232 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2234 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2236 pwc = (WCHAR *)&two_chars;
2238 *pwc = toupperW(*pwc);
2240 *pwc = toupperW(*pwc);
2244 hash ^= !pfd->can_use_bitmap;
2249 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2254 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2256 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2257 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2258 fd.can_use_bitmap = can_use_bitmap;
2261 /* try the in-use list */
2262 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2263 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2264 if(!fontcmp(ret, &fd)) {
2265 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2266 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2267 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2268 if(hflist->hfont == hfont)
2271 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2272 hflist->hfont = hfont;
2273 list_add_head(&ret->hfontlist, &hflist->entry);
2278 /* then the unused list */
2279 font_elem_ptr = list_head(&unused_gdi_font_list);
2280 while(font_elem_ptr) {
2281 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2282 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2283 if(!fontcmp(ret, &fd)) {
2284 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2285 assert(list_empty(&ret->hfontlist));
2286 TRACE("Found %p in unused list\n", ret);
2287 list_remove(&ret->entry);
2288 list_add_head(&gdi_font_list, &ret->entry);
2289 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2290 hflist->hfont = hfont;
2291 list_add_head(&ret->hfontlist, &hflist->entry);
2299 /*************************************************************
2300 * create_child_font_list
2302 static BOOL create_child_font_list(GdiFont *font)
2305 SYSTEM_LINKS *font_link;
2306 CHILD_FONT *font_link_entry, *new_child;
2308 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2310 if(!strcmpW(font_link->font_name, font->name))
2312 TRACE("found entry in system list\n");
2313 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2315 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2316 new_child->file_name = strdupA(font_link_entry->file_name);
2317 new_child->index = font_link_entry->index;
2318 new_child->font = NULL;
2319 list_add_tail(&font->child_fonts, &new_child->entry);
2320 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
2330 /*************************************************************
2331 * WineEngCreateFontInstance
2334 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
2337 Face *face, *best, *best_bitmap;
2338 Family *family, *last_resort_family;
2339 struct list *family_elem_ptr, *face_elem_ptr;
2340 INT height, width = 0;
2341 unsigned int score = 0, new_score;
2342 signed int diff = 0, newdiff;
2343 BOOL bd, it, can_use_bitmap;
2348 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2350 struct list *first_hfont = list_head(&ret->hfontlist);
2351 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2352 if(hflist->hfont == hfont)
2356 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2357 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2359 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2360 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2361 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2364 /* check the cache first */
2365 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2366 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2370 TRACE("not in cache\n");
2371 if(list_empty(&font_list)) /* No fonts installed */
2373 TRACE("No fonts installed\n");
2376 if(!have_installed_roman_font)
2378 TRACE("No roman font installed\n");
2384 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2385 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2386 ret->font_desc.can_use_bitmap = can_use_bitmap;
2387 calc_hash(&ret->font_desc);
2388 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2389 hflist->hfont = hfont;
2390 list_add_head(&ret->hfontlist, &hflist->entry);
2393 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2394 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2395 original value lfCharSet. Note this is a special case for
2396 Symbol and doesn't happen at least for "Wingdings*" */
2398 if(!strcmpiW(lf.lfFaceName, SymbolW))
2399 lf.lfCharSet = SYMBOL_CHARSET;
2401 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2402 switch(lf.lfCharSet) {
2403 case DEFAULT_CHARSET:
2404 csi.fs.fsCsb[0] = 0;
2407 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2408 csi.fs.fsCsb[0] = 0;
2414 if(lf.lfFaceName[0] != '\0') {
2416 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2419 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2420 debugstr_w(psub->to.name));
2421 strcpyW(lf.lfFaceName, psub->to.name);
2424 /* We want a match on name and charset or just name if
2425 charset was DEFAULT_CHARSET. If the latter then
2426 we fixup the returned charset later in get_nearest_charset
2427 where we'll either use the charset of the current ansi codepage
2428 or if that's unavailable the first charset that the font supports.
2430 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2431 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2432 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2433 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2434 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2435 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2436 if(face->scalable || can_use_bitmap)
2443 /* If requested charset was DEFAULT_CHARSET then try using charset
2444 corresponding to the current ansi codepage */
2445 if(!csi.fs.fsCsb[0]) {
2447 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
2448 FIXME("TCI failed on codepage %d\n", acp);
2449 csi.fs.fsCsb[0] = 0;
2451 lf.lfCharSet = csi.ciCharset;
2454 /* Face families are in the top 4 bits of lfPitchAndFamily,
2455 so mask with 0xF0 before testing */
2457 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2458 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2459 strcpyW(lf.lfFaceName, defFixed);
2460 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2461 strcpyW(lf.lfFaceName, defSerif);
2462 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2463 strcpyW(lf.lfFaceName, defSans);
2465 strcpyW(lf.lfFaceName, defSans);
2466 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2467 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2468 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2469 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2470 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2471 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2472 if(face->scalable || can_use_bitmap)
2478 last_resort_family = NULL;
2479 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2480 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2481 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2482 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2483 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2486 if(can_use_bitmap && !last_resort_family)
2487 last_resort_family = family;
2492 if(last_resort_family) {
2493 family = last_resort_family;
2494 csi.fs.fsCsb[0] = 0;
2498 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2499 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2500 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2501 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2502 if(face->scalable) {
2503 csi.fs.fsCsb[0] = 0;
2504 WARN("just using first face for now\n");
2507 if(can_use_bitmap && !last_resort_family)
2508 last_resort_family = family;
2511 if(!last_resort_family) {
2512 FIXME("can't find a single appropriate font - bailing\n");
2517 WARN("could only find a bitmap font - this will probably look awful!\n");
2518 family = last_resort_family;
2519 csi.fs.fsCsb[0] = 0;
2522 it = lf.lfItalic ? 1 : 0;
2523 bd = lf.lfWeight > 550 ? 1 : 0;
2525 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2526 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2528 face = best = best_bitmap = NULL;
2529 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2531 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2533 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
2534 if(!best || new_score <= score)
2536 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
2537 face->Italic, face->Bold, it, bd);
2540 if(best->scalable && score == 0) break;
2544 newdiff = height - (signed int)(best->size.height);
2546 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
2547 if(!best_bitmap || new_score < score ||
2548 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
2550 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
2553 if(score == 0 && diff == 0) break;
2560 face = best->scalable ? best : best_bitmap;
2561 ret->fake_italic = (it && !face->Italic);
2562 ret->fake_bold = (bd && !face->Bold);
2564 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2566 if(csi.fs.fsCsb[0]) {
2567 ret->charset = lf.lfCharSet;
2568 ret->codepage = csi.ciACP;
2571 ret->charset = get_nearest_charset(face, &ret->codepage);
2573 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2574 debugstr_w(face->StyleName), face->file, face->face_index);
2576 if(!face->scalable) {
2577 width = face->size.x_ppem >> 6;
2578 height = face->size.y_ppem >> 6;
2580 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2588 if (ret->charset == SYMBOL_CHARSET &&
2589 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2592 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2596 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2599 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2600 ret->name = strdupW(family->FamilyName);
2601 ret->underline = lf.lfUnderline ? 0xff : 0;
2602 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2603 create_child_font_list(ret);
2605 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2607 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
2608 list_add_head(&gdi_font_list, &ret->entry);
2612 static void dump_gdi_font_list(void)
2615 struct list *elem_ptr;
2617 TRACE("---------- gdiFont Cache ----------\n");
2618 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2619 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2620 TRACE("gdiFont=%p %s %d\n",
2621 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2624 TRACE("---------- Unused gdiFont Cache ----------\n");
2625 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2626 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2627 TRACE("gdiFont=%p %s %d\n",
2628 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2632 /*************************************************************
2633 * WineEngDestroyFontInstance
2635 * free the gdiFont associated with this handle
2638 BOOL WineEngDestroyFontInstance(HFONT handle)
2643 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2646 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
2648 struct list *first_hfont = list_head(&gdiFont->hfontlist);
2649 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2650 if(hflist->hfont == handle)
2652 TRACE("removing child font %p from child list\n", gdiFont);
2653 list_remove(&gdiFont->entry);
2658 TRACE("destroying hfont=%p\n", handle);
2660 dump_gdi_font_list();
2662 font_elem_ptr = list_head(&gdi_font_list);
2663 while(font_elem_ptr) {
2664 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2665 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
2667 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
2668 while(hfontlist_elem_ptr) {
2669 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2670 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
2671 if(hflist->hfont == handle) {
2672 list_remove(&hflist->entry);
2673 HeapFree(GetProcessHeap(), 0, hflist);
2677 if(list_empty(&gdiFont->hfontlist)) {
2678 TRACE("Moving to Unused list\n");
2679 list_remove(&gdiFont->entry);
2680 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
2685 font_elem_ptr = list_head(&unused_gdi_font_list);
2686 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
2687 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2688 while(font_elem_ptr) {
2689 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2690 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2691 TRACE("freeing %p\n", gdiFont);
2692 list_remove(&gdiFont->entry);
2698 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2699 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
2701 OUTLINETEXTMETRICW *potm = NULL;
2703 TEXTMETRICW tm, *ptm;
2704 GdiFont *font = alloc_font();
2707 if(face->scalable) {
2711 height = face->size.y_ppem >> 6;
2712 width = face->size.x_ppem >> 6;
2715 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
2721 font->name = strdupW(face->family->FamilyName);
2723 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
2725 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
2727 potm = HeapAlloc(GetProcessHeap(), 0, size);
2728 WineEngGetOutlineTextMetrics(font, size, potm);
2729 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
2731 WineEngGetTextMetrics(font, &tm);
2735 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
2736 pntm->ntmTm.tmAscent = ptm->tmAscent;
2737 pntm->ntmTm.tmDescent = ptm->tmDescent;
2738 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
2739 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
2740 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
2741 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
2742 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
2743 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
2744 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
2745 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
2746 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
2747 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
2748 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
2749 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
2750 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
2751 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
2752 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
2753 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
2754 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
2755 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
2756 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2757 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2758 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
2760 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
2761 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
2762 *ptype |= RASTER_FONTTYPE;
2764 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2765 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2766 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2768 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
2769 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
2770 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2773 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
2775 lstrcpynW(pelf->elfLogFont.lfFaceName,
2776 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
2778 lstrcpynW(pelf->elfFullName,
2779 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
2781 lstrcpynW(pelf->elfStyle,
2782 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2785 HeapFree(GetProcessHeap(), 0, potm);
2787 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
2789 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2790 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2791 pelf->elfStyle[0] = '\0';
2794 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2799 /*************************************************************
2803 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2807 struct list *family_elem_ptr, *face_elem_ptr;
2809 NEWTEXTMETRICEXW ntm;
2810 DWORD type, ret = 1;
2816 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2818 if(plf->lfFaceName[0]) {
2820 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
2823 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2824 debugstr_w(psub->to.name));
2825 memcpy(&lf, plf, sizeof(lf));
2826 strcpyW(lf.lfFaceName, psub->to.name);
2830 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2831 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2832 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2833 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2834 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2835 GetEnumStructs(face, &elf, &ntm, &type);
2836 for(i = 0; i < 32; i++) {
2837 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2838 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2839 strcpyW(elf.elfScript, OEM_DOSW);
2840 i = 32; /* break out of loop */
2841 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2844 fs.fsCsb[0] = 1L << i;
2846 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2848 csi.ciCharset = DEFAULT_CHARSET;
2849 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2850 if(csi.ciCharset != DEFAULT_CHARSET) {
2851 elf.elfLogFont.lfCharSet =
2852 ntm.ntmTm.tmCharSet = csi.ciCharset;
2854 strcpyW(elf.elfScript, ElfScriptsW[i]);
2856 FIXME("Unknown elfscript for bit %d\n", i);
2859 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
2860 debugstr_w(elf.elfLogFont.lfFaceName),
2861 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2862 csi.ciCharset, type, debugstr_w(elf.elfScript),
2863 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2864 ntm.ntmTm.ntmFlags);
2865 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2872 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2873 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2874 face_elem_ptr = list_head(&family->faces);
2875 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2876 GetEnumStructs(face, &elf, &ntm, &type);
2877 for(i = 0; i < 32; i++) {
2878 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2879 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2880 strcpyW(elf.elfScript, OEM_DOSW);
2881 i = 32; /* break out of loop */
2882 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2885 fs.fsCsb[0] = 1L << i;
2887 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2889 csi.ciCharset = DEFAULT_CHARSET;
2890 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2891 if(csi.ciCharset != DEFAULT_CHARSET) {
2892 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2895 strcpyW(elf.elfScript, ElfScriptsW[i]);
2897 FIXME("Unknown elfscript for bit %d\n", i);
2900 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
2901 debugstr_w(elf.elfLogFont.lfFaceName),
2902 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2903 csi.ciCharset, type, debugstr_w(elf.elfScript),
2904 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2905 ntm.ntmTm.ntmFlags);
2906 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2915 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2917 pt->x.value = vec->x >> 6;
2918 pt->x.fract = (vec->x & 0x3f) << 10;
2919 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2920 pt->y.value = vec->y >> 6;
2921 pt->y.fract = (vec->y & 0x3f) << 10;
2922 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2926 /***************************************************
2927 * According to the MSDN documentation on WideCharToMultiByte,
2928 * certain codepages cannot set the default_used parameter.
2929 * This returns TRUE if the codepage can set that parameter, false else
2930 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
2932 static BOOL codepage_sets_default_used(UINT codepage)
2945 static FT_UInt get_glyph_index(GdiFont *font, UINT glyph)
2947 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
2948 WCHAR wc = (WCHAR)glyph;
2950 BOOL *default_used_pointer;
2953 default_used_pointer = NULL;
2954 default_used = FALSE;
2955 if (codepage_sets_default_used(font->codepage))
2956 default_used_pointer = &default_used;
2957 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
2960 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
2961 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
2965 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2966 glyph = glyph + 0xf000;
2967 return pFT_Get_Char_Index(font->ft_face, glyph);
2970 /*************************************************************
2971 * WineEngGetGlyphIndices
2973 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2975 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
2976 LPWORD pgi, DWORD flags)
2979 WCHAR default_char = 0;
2982 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
2984 for(i = 0; i < count; i++)
2986 pgi[i] = get_glyph_index(font, lpstr[i]);
2991 WineEngGetTextMetrics(font, &textm);
2992 default_char = textm.tmDefaultChar;
2994 pgi[i] = default_char;
3000 /*************************************************************
3001 * WineEngGetGlyphOutline
3003 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3004 * except that the first parameter is the HWINEENGFONT of the font in
3005 * question rather than an HDC.
3008 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
3009 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3012 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3013 FT_Face ft_face = font->ft_face;
3014 FT_UInt glyph_index;
3015 DWORD width, height, pitch, needed = 0;
3016 FT_Bitmap ft_bitmap;
3018 INT left, right, top = 0, bottom = 0;
3020 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3021 float widthRatio = 1.0;
3022 FT_Matrix transMat = identityMat;
3023 BOOL needsTransform = FALSE;
3026 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
3027 buflen, buf, lpmat);
3029 if(format & GGO_GLYPH_INDEX) {
3030 glyph_index = glyph;
3031 format &= ~GGO_GLYPH_INDEX;
3033 glyph_index = get_glyph_index(font, glyph);
3035 if(glyph_index >= font->gmsize) {
3036 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
3037 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
3038 font->gmsize * sizeof(*font->gm));
3040 if(format == GGO_METRICS && font->gm[glyph_index].init) {
3041 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
3042 return 1; /* FIXME */
3046 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
3047 load_flags |= FT_LOAD_NO_BITMAP;
3049 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
3052 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
3056 /* Scaling factor */
3057 if (font->aveWidth && font->potm) {
3058 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
3061 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3062 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3064 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3065 font->gm[glyph_index].lsb = left >> 6;
3066 font->gm[glyph_index].bbx = (right - left) >> 6;
3068 /* Scaling transform */
3069 if(font->aveWidth) {
3071 scaleMat.xx = FT_FixedFromFloat(widthRatio);
3074 scaleMat.yy = (1 << 16);
3076 pFT_Matrix_Multiply(&scaleMat, &transMat);
3077 needsTransform = TRUE;
3080 /* Slant transform */
3081 if (font->fake_italic) {
3084 slantMat.xx = (1 << 16);
3085 slantMat.xy = ((1 << 16) >> 2);
3087 slantMat.yy = (1 << 16);
3088 pFT_Matrix_Multiply(&slantMat, &transMat);
3089 needsTransform = TRUE;
3092 /* Rotation transform */
3093 if(font->orientation) {
3094 FT_Matrix rotationMat;
3096 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3097 pFT_Vector_Unit(&vecAngle, angle);
3098 rotationMat.xx = vecAngle.x;
3099 rotationMat.xy = -vecAngle.y;
3100 rotationMat.yx = -rotationMat.xy;
3101 rotationMat.yy = rotationMat.xx;
3103 pFT_Matrix_Multiply(&rotationMat, &transMat);
3104 needsTransform = TRUE;
3107 /* Extra transformation specified by caller */
3110 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3111 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3112 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3113 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3114 pFT_Matrix_Multiply(&extraMat, &transMat);
3115 needsTransform = TRUE;
3118 if(!needsTransform) {
3119 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3120 bottom = (ft_face->glyph->metrics.horiBearingY -
3121 ft_face->glyph->metrics.height) & -64;
3122 lpgm->gmCellIncX = font->gm[glyph_index].adv;
3123 lpgm->gmCellIncY = 0;
3127 for(xc = 0; xc < 2; xc++) {
3128 for(yc = 0; yc < 2; yc++) {
3129 vec.x = (ft_face->glyph->metrics.horiBearingX +
3130 xc * ft_face->glyph->metrics.width);
3131 vec.y = ft_face->glyph->metrics.horiBearingY -
3132 yc * ft_face->glyph->metrics.height;
3133 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3134 pFT_Vector_Transform(&vec, &transMat);
3135 if(xc == 0 && yc == 0) {
3136 left = right = vec.x;
3137 top = bottom = vec.y;
3139 if(vec.x < left) left = vec.x;
3140 else if(vec.x > right) right = vec.x;
3141 if(vec.y < bottom) bottom = vec.y;
3142 else if(vec.y > top) top = vec.y;
3147 right = (right + 63) & -64;
3148 bottom = bottom & -64;
3149 top = (top + 63) & -64;
3151 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3152 vec.x = ft_face->glyph->metrics.horiAdvance;
3154 pFT_Vector_Transform(&vec, &transMat);
3155 lpgm->gmCellIncX = (vec.x+63) >> 6;
3156 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3158 lpgm->gmBlackBoxX = (right - left) >> 6;
3159 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3160 lpgm->gmptGlyphOrigin.x = left >> 6;
3161 lpgm->gmptGlyphOrigin.y = top >> 6;
3163 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
3164 font->gm[glyph_index].init = TRUE;
3166 if(format == GGO_METRICS)
3167 return 1; /* FIXME */
3169 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
3170 TRACE("loaded a bitmap\n");
3176 width = lpgm->gmBlackBoxX;
3177 height = lpgm->gmBlackBoxY;
3178 pitch = ((width + 31) >> 5) << 2;
3179 needed = pitch * height;
3181 if(!buf || !buflen) break;
3183 switch(ft_face->glyph->format) {
3184 case ft_glyph_format_bitmap:
3186 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3187 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3188 INT h = ft_face->glyph->bitmap.rows;
3190 memcpy(dst, src, w);
3191 src += ft_face->glyph->bitmap.pitch;
3197 case ft_glyph_format_outline:
3198 ft_bitmap.width = width;
3199 ft_bitmap.rows = height;
3200 ft_bitmap.pitch = pitch;
3201 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3202 ft_bitmap.buffer = buf;
3204 if(needsTransform) {
3205 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3208 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3210 /* Note: FreeType will only set 'black' bits for us. */
3211 memset(buf, 0, needed);
3212 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3216 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3221 case GGO_GRAY2_BITMAP:
3222 case GGO_GRAY4_BITMAP:
3223 case GGO_GRAY8_BITMAP:
3224 case WINE_GGO_GRAY16_BITMAP:
3226 unsigned int mult, row, col;
3229 width = lpgm->gmBlackBoxX;
3230 height = lpgm->gmBlackBoxY;
3231 pitch = (width + 3) / 4 * 4;
3232 needed = pitch * height;
3234 if(!buf || !buflen) break;
3235 ft_bitmap.width = width;
3236 ft_bitmap.rows = height;
3237 ft_bitmap.pitch = pitch;
3238 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3239 ft_bitmap.buffer = buf;
3241 if(needsTransform) {
3242 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3245 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3247 memset(ft_bitmap.buffer, 0, buflen);
3249 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3251 if(format == GGO_GRAY2_BITMAP)
3253 else if(format == GGO_GRAY4_BITMAP)
3255 else if(format == GGO_GRAY8_BITMAP)
3257 else if(format == WINE_GGO_GRAY16_BITMAP)
3265 for(row = 0; row < height; row++) {
3267 for(col = 0; col < width; col++, ptr++) {
3268 *ptr = (((int)*ptr) * mult + 128) / 256;
3277 int contour, point = 0, first_pt;
3278 FT_Outline *outline = &ft_face->glyph->outline;
3279 TTPOLYGONHEADER *pph;
3281 DWORD pph_start, cpfx, type;
3283 if(buflen == 0) buf = NULL;
3285 if (needsTransform && buf) {
3286 pFT_Outline_Transform(outline, &transMat);
3289 for(contour = 0; contour < outline->n_contours; contour++) {
3291 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3294 pph->dwType = TT_POLYGON_TYPE;
3295 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3297 needed += sizeof(*pph);
3299 while(point <= outline->contours[contour]) {
3300 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3301 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3302 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3306 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3309 } while(point <= outline->contours[contour] &&
3310 (outline->tags[point] & FT_Curve_Tag_On) ==
3311 (outline->tags[point-1] & FT_Curve_Tag_On));
3312 /* At the end of a contour Windows adds the start point, but
3314 if(point > outline->contours[contour] &&
3315 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3317 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3319 } else if(point <= outline->contours[contour] &&
3320 outline->tags[point] & FT_Curve_Tag_On) {
3321 /* add closing pt for bezier */
3323 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3331 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3334 pph->cb = needed - pph_start;
3340 /* Convert the quadratic Beziers to cubic Beziers.
3341 The parametric eqn for a cubic Bezier is, from PLRM:
3342 r(t) = at^3 + bt^2 + ct + r0
3343 with the control points:
3348 A quadratic Beizer has the form:
3349 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3351 So equating powers of t leads to:
3352 r1 = 2/3 p1 + 1/3 p0
3353 r2 = 2/3 p1 + 1/3 p2
3354 and of course r0 = p0, r3 = p2
3357 int contour, point = 0, first_pt;
3358 FT_Outline *outline = &ft_face->glyph->outline;
3359 TTPOLYGONHEADER *pph;
3361 DWORD pph_start, cpfx, type;
3362 FT_Vector cubic_control[4];
3363 if(buflen == 0) buf = NULL;
3365 if (needsTransform && buf) {
3366 pFT_Outline_Transform(outline, &transMat);
3369 for(contour = 0; contour < outline->n_contours; contour++) {
3371 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3374 pph->dwType = TT_POLYGON_TYPE;
3375 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3377 needed += sizeof(*pph);
3379 while(point <= outline->contours[contour]) {
3380 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3381 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3382 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3385 if(type == TT_PRIM_LINE) {
3387 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3391 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3394 /* FIXME: Possible optimization in endpoint calculation
3395 if there are two consecutive curves */
3396 cubic_control[0] = outline->points[point-1];
3397 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3398 cubic_control[0].x += outline->points[point].x + 1;
3399 cubic_control[0].y += outline->points[point].y + 1;
3400 cubic_control[0].x >>= 1;
3401 cubic_control[0].y >>= 1;
3403 if(point+1 > outline->contours[contour])
3404 cubic_control[3] = outline->points[first_pt];
3406 cubic_control[3] = outline->points[point+1];
3407 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3408 cubic_control[3].x += outline->points[point].x + 1;
3409 cubic_control[3].y += outline->points[point].y + 1;
3410 cubic_control[3].x >>= 1;
3411 cubic_control[3].y >>= 1;
3414 /* r1 = 1/3 p0 + 2/3 p1
3415 r2 = 1/3 p2 + 2/3 p1 */
3416 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3417 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3418 cubic_control[2] = cubic_control[1];
3419 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3420 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3421 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3422 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3424 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3425 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3426 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3431 } while(point <= outline->contours[contour] &&
3432 (outline->tags[point] & FT_Curve_Tag_On) ==
3433 (outline->tags[point-1] & FT_Curve_Tag_On));
3434 /* At the end of a contour Windows adds the start point,
3435 but only for Beziers and we've already done that.
3437 if(point <= outline->contours[contour] &&
3438 outline->tags[point] & FT_Curve_Tag_On) {
3439 /* This is the closing pt of a bezier, but we've already
3440 added it, so just inc point and carry on */
3447 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3450 pph->cb = needed - pph_start;
3456 FIXME("Unsupported format %d\n", format);
3462 static BOOL get_bitmap_text_metrics(GdiFont *font)
3464 FT_Face ft_face = font->ft_face;
3465 #ifdef HAVE_FREETYPE_FTWINFNT_H
3466 FT_WinFNT_HeaderRec winfnt_header;
3468 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3469 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3470 font->potm->otmSize = size;
3472 #define TM font->potm->otmTextMetrics
3473 #ifdef HAVE_FREETYPE_FTWINFNT_H
3474 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3476 TM.tmHeight = winfnt_header.pixel_height;
3477 TM.tmAscent = winfnt_header.ascent;
3478 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3479 TM.tmInternalLeading = winfnt_header.internal_leading;
3480 TM.tmExternalLeading = winfnt_header.external_leading;
3481 TM.tmAveCharWidth = winfnt_header.avg_width;
3482 TM.tmMaxCharWidth = winfnt_header.max_width;
3483 TM.tmWeight = winfnt_header.weight;
3485 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3486 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3487 TM.tmFirstChar = winfnt_header.first_char;
3488 TM.tmLastChar = winfnt_header.last_char;
3489 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3490 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3491 TM.tmItalic = winfnt_header.italic;
3492 TM.tmUnderlined = font->underline;
3493 TM.tmStruckOut = font->strikeout;
3494 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3495 TM.tmCharSet = winfnt_header.charset;
3500 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3501 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3502 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3503 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3504 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3505 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3506 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3507 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3509 TM.tmDigitizedAspectX = 96; /* FIXME */
3510 TM.tmDigitizedAspectY = 96; /* FIXME */
3512 TM.tmLastChar = 255;
3513 TM.tmDefaultChar = 32;
3514 TM.tmBreakChar = 32;
3515 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3516 TM.tmUnderlined = font->underline;
3517 TM.tmStruckOut = font->strikeout;
3518 /* NB inverted meaning of TMPF_FIXED_PITCH */
3519 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3520 TM.tmCharSet = font->charset;
3527 /*************************************************************
3528 * WineEngGetTextMetrics
3531 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
3534 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3535 if(!get_bitmap_text_metrics(font))
3538 if(!font->potm) return FALSE;
3539 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3541 if (font->aveWidth) {
3542 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3548 /*************************************************************
3549 * WineEngGetOutlineTextMetrics
3552 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
3553 OUTLINETEXTMETRICW *potm)
3555 FT_Face ft_face = font->ft_face;
3556 UINT needed, lenfam, lensty, ret;
3558 TT_HoriHeader *pHori;
3559 TT_Postscript *pPost;
3560 FT_Fixed x_scale, y_scale;
3561 WCHAR *family_nameW, *style_nameW;
3562 static const WCHAR spaceW[] = {' ', '\0'};
3564 INT ascent, descent;
3566 TRACE("font=%p\n", font);
3568 if(!FT_IS_SCALABLE(ft_face))
3572 if(cbSize >= font->potm->otmSize)
3573 memcpy(potm, font->potm, font->potm->otmSize);
3574 return font->potm->otmSize;
3578 needed = sizeof(*potm);
3580 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3581 family_nameW = strdupW(font->name);
3583 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3585 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3586 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3587 style_nameW, lensty/sizeof(WCHAR));
3589 /* These names should be read from the TT name table */
3591 /* length of otmpFamilyName */
3594 /* length of otmpFaceName */
3595 if(!strcasecmp(ft_face->style_name, "regular")) {
3596 needed += lenfam; /* just the family name */
3598 needed += lenfam + lensty; /* family + " " + style */
3601 /* length of otmpStyleName */
3604 /* length of otmpFullName */
3605 needed += lenfam + lensty;
3608 x_scale = ft_face->size->metrics.x_scale;
3609 y_scale = ft_face->size->metrics.y_scale;
3611 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3613 FIXME("Can't find OS/2 table - not TT font?\n");
3618 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3620 FIXME("Can't find HHEA table - not TT font?\n");
3625 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3627 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",
3628 pOS2->usWinAscent, pOS2->usWinDescent,
3629 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3630 ft_face->ascender, ft_face->descender, ft_face->height,
3631 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3632 ft_face->bbox.yMax, ft_face->bbox.yMin);
3634 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3635 font->potm->otmSize = needed;
3637 #define TM font->potm->otmTextMetrics
3639 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3640 ascent = pHori->Ascender;
3641 descent = -pHori->Descender;
3643 ascent = pOS2->usWinAscent;
3644 descent = pOS2->usWinDescent;
3648 TM.tmAscent = font->yMax;
3649 TM.tmDescent = -font->yMin;
3650 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3652 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
3653 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
3654 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
3655 - ft_face->units_per_EM, y_scale) + 32) >> 6;
3658 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3661 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3663 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
3664 ((ascent + descent) -
3665 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
3667 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
3668 if (TM.tmAveCharWidth == 0) {
3669 TM.tmAveCharWidth = 1;
3671 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
3672 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
3674 TM.tmDigitizedAspectX = 300;
3675 TM.tmDigitizedAspectY = 300;
3676 TM.tmFirstChar = pOS2->usFirstCharIndex;
3677 TM.tmLastChar = pOS2->usLastCharIndex;
3678 TM.tmDefaultChar = pOS2->usDefaultChar;
3679 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
3680 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3681 TM.tmUnderlined = font->underline;
3682 TM.tmStruckOut = font->strikeout;
3684 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3685 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3686 (pOS2->version == 0xFFFFU ||
3687 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3688 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3690 TM.tmPitchAndFamily = 0;
3692 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
3693 case PAN_FAMILY_SCRIPT:
3694 TM.tmPitchAndFamily |= FF_SCRIPT;
3696 case PAN_FAMILY_DECORATIVE:
3697 case PAN_FAMILY_PICTORIAL:
3698 TM.tmPitchAndFamily |= FF_DECORATIVE;
3700 case PAN_FAMILY_TEXT_DISPLAY:
3701 if(TM.tmPitchAndFamily == 0) /* fixed */
3702 TM.tmPitchAndFamily = FF_MODERN;
3704 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
3705 case PAN_SERIF_NORMAL_SANS:
3706 case PAN_SERIF_OBTUSE_SANS:
3707 case PAN_SERIF_PERP_SANS:
3708 TM.tmPitchAndFamily |= FF_SWISS;
3711 TM.tmPitchAndFamily |= FF_ROMAN;
3716 TM.tmPitchAndFamily |= FF_DONTCARE;
3719 if(FT_IS_SCALABLE(ft_face))
3720 TM.tmPitchAndFamily |= TMPF_VECTOR;
3721 if(FT_IS_SFNT(ft_face))
3722 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3724 TM.tmCharSet = font->charset;
3727 font->potm->otmFiller = 0;
3728 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3729 font->potm->otmfsSelection = pOS2->fsSelection;
3730 font->potm->otmfsType = pOS2->fsType;
3731 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
3732 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
3733 font->potm->otmItalicAngle = 0; /* POST table */
3734 font->potm->otmEMSquare = ft_face->units_per_EM;
3735 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
3736 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
3737 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
3738 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
3739 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
3740 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
3741 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
3742 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
3743 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
3744 font->potm->otmMacAscent = 0; /* where do these come from ? */
3745 font->potm->otmMacDescent = 0;
3746 font->potm->otmMacLineGap = 0;
3747 font->potm->otmusMinimumPPEM = 0; /* TT Header */
3748 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
3749 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
3750 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
3751 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
3752 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
3753 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
3754 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
3755 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
3756 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
3757 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
3759 font->potm->otmsUnderscoreSize = 0;
3760 font->potm->otmsUnderscorePosition = 0;
3762 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
3763 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
3766 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
3767 cp = (char*)font->potm + sizeof(*font->potm);
3768 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
3769 strcpyW((WCHAR*)cp, family_nameW);
3771 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
3772 strcpyW((WCHAR*)cp, style_nameW);
3774 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
3775 strcpyW((WCHAR*)cp, family_nameW);
3776 if(strcasecmp(ft_face->style_name, "regular")) {
3777 strcatW((WCHAR*)cp, spaceW);
3778 strcatW((WCHAR*)cp, style_nameW);
3779 cp += lenfam + lensty;
3782 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
3783 strcpyW((WCHAR*)cp, family_nameW);
3784 strcatW((WCHAR*)cp, spaceW);
3785 strcatW((WCHAR*)cp, style_nameW);
3788 if(potm && needed <= cbSize)
3789 memcpy(potm, font->potm, font->potm->otmSize);
3792 HeapFree(GetProcessHeap(), 0, style_nameW);
3793 HeapFree(GetProcessHeap(), 0, family_nameW);
3798 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
3800 HFONTLIST *hfontlist;
3801 child->font = alloc_font();
3802 child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem);
3803 if(!child->font->ft_face)
3805 free_font(child->font);
3810 child->font->orientation = font->orientation;
3811 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
3812 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
3813 list_add_head(&child->font->hfontlist, &hfontlist->entry);
3814 child->font->base_font = font;
3815 list_add_head(&child_font_list, &child->font->entry);
3816 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
3820 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
3823 CHILD_FONT *child_font;
3826 font = font->base_font;
3828 *linked_font = font;
3830 if((*glyph = get_glyph_index(font, c)))
3833 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
3835 if(!child_font->font)
3836 if(!load_child_font(font, child_font))
3839 if(!child_font->font->ft_face)
3841 g = get_glyph_index(child_font->font, c);
3845 *linked_font = child_font->font;
3852 /*************************************************************
3853 * WineEngGetCharWidth
3856 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
3861 FT_UInt glyph_index;
3862 GdiFont *linked_font;
3864 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3866 for(c = firstChar; c <= lastChar; c++) {
3867 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3868 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3869 &gm, 0, NULL, NULL);
3870 buffer[c - firstChar] = linked_font->gm[glyph_index].adv;
3875 /*************************************************************
3876 * WineEngGetCharABCWidths
3879 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
3884 FT_UInt glyph_index;
3885 GdiFont *linked_font;
3887 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3889 if(!FT_IS_SCALABLE(font->ft_face))
3892 for(c = firstChar; c <= lastChar; c++) {
3893 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3894 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3895 &gm, 0, NULL, NULL);
3896 buffer[c - firstChar].abcA = linked_font->gm[glyph_index].lsb;
3897 buffer[c - firstChar].abcB = linked_font->gm[glyph_index].bbx;
3898 buffer[c - firstChar].abcC = linked_font->gm[glyph_index].adv - linked_font->gm[glyph_index].lsb -
3899 linked_font->gm[glyph_index].bbx;
3904 /*************************************************************
3905 * WineEngGetCharABCWidthsI
3908 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
3913 FT_UInt glyph_index;
3914 GdiFont *linked_font;
3916 if(!FT_IS_SCALABLE(font->ft_face))
3919 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
3921 for(c = firstChar; c < firstChar+count; c++) {
3922 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
3923 &gm, 0, NULL, NULL);
3924 buffer[c - firstChar].abcA = linked_font->gm[c].lsb;
3925 buffer[c - firstChar].abcB = linked_font->gm[c].bbx;
3926 buffer[c - firstChar].abcC = linked_font->gm[c].adv - linked_font->gm[c].lsb
3927 - linked_font->gm[c].bbx;
3930 for(c = 0; c < count; c++) {
3931 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
3932 &gm, 0, NULL, NULL);
3933 buffer[c].abcA = linked_font->gm[pgi[c]].lsb;
3934 buffer[c].abcB = linked_font->gm[pgi[c]].bbx;
3935 buffer[c].abcC = linked_font->gm[pgi[c]].adv
3936 - linked_font->gm[pgi[c]].lsb - linked_font->gm[pgi[c]].bbx;
3942 /*************************************************************
3943 * WineEngGetTextExtentExPoint
3946 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
3947 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
3953 FT_UInt glyph_index;
3954 GdiFont *linked_font;
3956 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
3960 WineEngGetTextMetrics(font, &tm);
3961 size->cy = tm.tmHeight;
3963 for(idx = 0; idx < count; idx++) {
3964 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
3965 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3966 &gm, 0, NULL, NULL);
3967 size->cx += linked_font->gm[glyph_index].adv;
3969 if (! pnfit || ext <= max_ext) {
3979 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
3983 /*************************************************************
3984 * WineEngGetTextExtentPointI
3987 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
3994 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3997 WineEngGetTextMetrics(font, &tm);
3998 size->cy = tm.tmHeight;
4000 for(idx = 0; idx < count; idx++) {
4001 WineEngGetGlyphOutline(font, indices[idx],
4002 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
4004 size->cx += font->gm[indices[idx]].adv;
4006 TRACE("return %d,%d\n", size->cx, size->cy);
4010 /*************************************************************
4011 * WineEngGetFontData
4014 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4017 FT_Face ft_face = font->ft_face;
4021 TRACE("font=%p, table=%08x, offset=%08x, buf=%p, cbData=%x\n",
4022 font, table, offset, buf, cbData);
4024 if(!FT_IS_SFNT(ft_face))
4032 if(table) { /* MS tags differ in endidness from FT ones */
4033 table = table >> 24 | table << 24 |
4034 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
4037 /* If the FT_Load_Sfnt_Table function is there we'll use it */
4038 if(pFT_Load_Sfnt_Table) {
4039 /* make sure value of len is the value freetype says it needs */
4041 FT_ULong needed = 0;
4042 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4043 if( !err && needed < len) len = needed;
4045 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4047 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
4048 else { /* Do it the hard way */
4049 TT_Face tt_face = (TT_Face) ft_face;
4050 SFNT_Interface *sfnt;
4051 if (FT_Version.major==2 && FT_Version.minor==0)
4054 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
4058 /* A field was added in the middle of the structure in 2.1.x */
4059 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
4061 /* make sure value of len is the value freetype says it needs */
4063 FT_ULong needed = 0;
4064 err = sfnt->load_any(tt_face, table, offset, NULL, &needed);
4065 if( !err && needed < len) len = needed;
4067 err = sfnt->load_any(tt_face, table, offset, buf, &len);
4073 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
4074 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
4075 "Please upgrade your freetype library.\n");
4078 err = FT_Err_Unimplemented_Feature;
4082 TRACE("Can't find table %08x.\n", table);
4088 /*************************************************************
4089 * WineEngGetTextFace
4092 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4095 lstrcpynW(str, font->name, count);
4096 return strlenW(font->name);
4098 return strlenW(font->name) + 1;
4101 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4103 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4104 return font->charset;
4107 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4109 GdiFont *font = dc->gdiFont, *linked_font;
4110 struct list *first_hfont;
4113 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4114 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4115 if(font == linked_font)
4116 *new_hfont = dc->hFont;
4119 first_hfont = list_head(&linked_font->hfontlist);
4120 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4127 /*************************************************************
4130 BOOL WINAPI FontIsLinked(HDC hdc)
4132 DC *dc = DC_GetDCPtr(hdc);
4135 if(!dc) return FALSE;
4136 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
4138 GDI_ReleaseObj(hdc);
4139 TRACE("returning %d\n", ret);
4143 static BOOL is_hinting_enabled(void)
4145 /* Use the >= 2.2.0 function if available */
4146 if(pFT_Get_TrueType_Engine_Type)
4148 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4149 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4151 #ifdef FT_DRIVER_HAS_HINTER
4156 /* otherwise if we've been compiled with < 2.2.0 headers
4157 use the internal macro */
4158 mod = pFT_Get_Module(library, "truetype");
4159 if(mod && FT_DRIVER_HAS_HINTER(mod))
4167 /*************************************************************************
4168 * GetRasterizerCaps (GDI32.@)
4170 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4172 static int hinting = -1;
4175 hinting = is_hinting_enabled();
4177 lprs->nSize = sizeof(RASTERIZER_STATUS);
4178 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4179 lprs->nLanguageID = 0;
4183 /*************************************************************************
4184 * Kerning support for TrueType fonts
4186 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4188 struct TT_kern_table
4194 struct TT_kern_subtable
4203 USHORT horizontal : 1;
4205 USHORT cross_stream: 1;
4206 USHORT override : 1;
4207 USHORT reserved1 : 4;
4213 struct TT_format0_kern_subtable
4217 USHORT entrySelector;
4228 static DWORD parse_format0_kern_subtable(GdiFont *font,
4229 const struct TT_format0_kern_subtable *tt_f0_ks,
4230 const USHORT *glyph_to_char,
4231 KERNINGPAIR *kern_pair, DWORD cPairs)
4234 const struct TT_kern_pair *tt_kern_pair;
4236 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
4238 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4240 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4241 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4242 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4244 if (!kern_pair || !cPairs)
4247 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4249 nPairs = min(nPairs, cPairs);
4251 for (i = 0; i < nPairs; i++)
4253 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4254 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4255 /* this algorithm appears to better match what Windows does */
4256 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4257 if (kern_pair->iKernAmount < 0)
4259 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
4260 kern_pair->iKernAmount -= font->ppem;
4262 else if (kern_pair->iKernAmount > 0)
4264 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
4265 kern_pair->iKernAmount += font->ppem;
4267 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
4269 TRACE("left %u right %u value %d\n",
4270 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
4274 TRACE("copied %u entries\n", nPairs);
4278 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4282 const struct TT_kern_table *tt_kern_table;
4283 const struct TT_kern_subtable *tt_kern_subtable;
4285 USHORT *glyph_to_char;
4287 if (font->total_kern_pairs != (DWORD)-1)
4289 if (cPairs && kern_pair)
4291 cPairs = min(cPairs, font->total_kern_pairs);
4292 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4295 return font->total_kern_pairs;
4298 font->total_kern_pairs = 0;
4300 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
4302 if (length == GDI_ERROR)
4304 TRACE("no kerning data in the font\n");
4308 buf = HeapAlloc(GetProcessHeap(), 0, length);
4311 WARN("Out of memory\n");
4315 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
4317 /* build a glyph index to char code map */
4318 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
4321 WARN("Out of memory allocating a glyph index to char code map\n");
4322 HeapFree(GetProcessHeap(), 0, buf);
4326 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4332 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
4334 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4335 font->ft_face->num_glyphs, glyph_code, char_code);
4339 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4341 /* FIXME: This doesn't match what Windows does: it does some fancy
4342 * things with duplicate glyph index to char code mappings, while
4343 * we just avoid overriding existing entries.
4345 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
4346 glyph_to_char[glyph_code] = (USHORT)char_code;
4348 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
4355 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
4356 for (n = 0; n <= 65535; n++)
4357 glyph_to_char[n] = (USHORT)n;
4360 tt_kern_table = buf;
4361 nTables = GET_BE_WORD(tt_kern_table->nTables);
4362 TRACE("version %u, nTables %u\n",
4363 GET_BE_WORD(tt_kern_table->version), nTables);
4365 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
4367 for (i = 0; i < nTables; i++)
4369 struct TT_kern_subtable tt_kern_subtable_copy;
4371 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
4372 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
4373 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
4375 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4376 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
4377 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
4379 /* According to the TrueType specification this is the only format
4380 * that will be properly interpreted by Windows and OS/2
4382 if (tt_kern_subtable_copy.coverage.bits.format == 0)
4384 DWORD new_chunk, old_total = font->total_kern_pairs;
4386 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4387 glyph_to_char, NULL, 0);
4388 font->total_kern_pairs += new_chunk;
4390 if (!font->kern_pairs)
4391 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
4392 font->total_kern_pairs * sizeof(*font->kern_pairs));
4394 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
4395 font->total_kern_pairs * sizeof(*font->kern_pairs));
4397 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4398 glyph_to_char, font->kern_pairs + old_total, new_chunk);
4401 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
4403 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
4406 HeapFree(GetProcessHeap(), 0, glyph_to_char);
4407 HeapFree(GetProcessHeap(), 0, buf);
4409 if (cPairs && kern_pair)
4411 cPairs = min(cPairs, font->total_kern_pairs);
4412 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4415 return font->total_kern_pairs;
4418 #else /* HAVE_FREETYPE */
4420 /*************************************************************************/
4422 BOOL WineEngInit(void)
4426 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
4430 BOOL WineEngDestroyFontInstance(HFONT hfont)
4435 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4440 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4441 LPWORD pgi, DWORD flags)
4446 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
4447 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4450 ERR("called but we don't have FreeType\n");
4454 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4456 ERR("called but we don't have FreeType\n");
4460 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4461 OUTLINETEXTMETRICW *potm)
4463 ERR("called but we don't have FreeType\n");
4467 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4470 ERR("called but we don't have FreeType\n");
4474 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4477 ERR("called but we don't have FreeType\n");
4481 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4484 ERR("called but we don't have FreeType\n");
4488 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4489 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
4491 ERR("called but we don't have FreeType\n");
4495 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4498 ERR("called but we don't have FreeType\n");
4502 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4505 ERR("called but we don't have FreeType\n");
4509 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4511 ERR("called but we don't have FreeType\n");
4515 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4521 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4527 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4530 return DEFAULT_CHARSET;
4533 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4538 BOOL WINAPI FontIsLinked(HDC hdc)
4543 /*************************************************************************
4544 * GetRasterizerCaps (GDI32.@)
4546 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4548 lprs->nSize = sizeof(RASTERIZER_STATUS);
4550 lprs->nLanguageID = 0;
4554 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4556 ERR("called but we don't have FreeType\n");
4560 #endif /* HAVE_FREETYPE */