2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
6 * This file contains the WineEng* functions.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "wine/port.h"
28 #ifdef HAVE_SYS_STAT_H
29 # include <sys/stat.h>
43 #include "gdi_private.h"
44 #include "wine/unicode.h"
45 #include "wine/debug.h"
46 #include "wine/list.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(font);
52 #ifdef HAVE_FT2BUILD_H
55 #ifdef HAVE_FREETYPE_FREETYPE_H
56 #include <freetype/freetype.h>
58 #ifdef HAVE_FREETYPE_FTGLYPH_H
59 #include <freetype/ftglyph.h>
61 #ifdef HAVE_FREETYPE_TTTABLES_H
62 #include <freetype/tttables.h>
64 #ifdef HAVE_FREETYPE_FTSNAMES_H
65 #include <freetype/ftsnames.h>
67 # ifdef HAVE_FREETYPE_FTNAMES_H
68 # include <freetype/ftnames.h>
71 #ifdef HAVE_FREETYPE_TTNAMEID_H
72 #include <freetype/ttnameid.h>
74 #ifdef HAVE_FREETYPE_FTOUTLN_H
75 #include <freetype/ftoutln.h>
77 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
78 #include <freetype/internal/sfnt.h>
80 #ifdef HAVE_FREETYPE_FTTRIGON_H
81 #include <freetype/fttrigon.h>
83 #ifdef HAVE_FREETYPE_FTWINFNT_H
84 #include <freetype/ftwinfnt.h>
86 #ifdef HAVE_FREETYPE_FTMODAPI_H
87 #include <freetype/ftmodapi.h>
90 #ifndef SONAME_LIBFREETYPE
91 #define SONAME_LIBFREETYPE "libfreetype.so"
94 #ifndef HAVE_FT_TRUETYPEENGINETYPE
97 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
98 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
99 FT_TRUETYPE_ENGINE_TYPE_PATENTED
100 } FT_TrueTypeEngineType;
103 static FT_Library library = 0;
110 static FT_Version_t FT_Version;
111 static DWORD FT_SimpleVersion;
113 static void *ft_handle = NULL;
115 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
116 MAKE_FUNCPTR(FT_Vector_Unit);
117 MAKE_FUNCPTR(FT_Done_Face);
118 MAKE_FUNCPTR(FT_Get_Char_Index);
119 MAKE_FUNCPTR(FT_Get_Module);
120 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
121 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
122 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
123 MAKE_FUNCPTR(FT_Init_FreeType);
124 MAKE_FUNCPTR(FT_Load_Glyph);
125 MAKE_FUNCPTR(FT_Matrix_Multiply);
126 MAKE_FUNCPTR(FT_MulFix);
127 MAKE_FUNCPTR(FT_New_Face);
128 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
129 MAKE_FUNCPTR(FT_Outline_Transform);
130 MAKE_FUNCPTR(FT_Outline_Translate);
131 MAKE_FUNCPTR(FT_Select_Charmap);
132 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
133 MAKE_FUNCPTR(FT_Vector_Transform);
134 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
135 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
136 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
137 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
138 #ifdef HAVE_FREETYPE_FTWINFNT_H
139 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
142 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
143 #include <fontconfig/fontconfig.h>
144 MAKE_FUNCPTR(FcConfigGetCurrent);
145 MAKE_FUNCPTR(FcFontList);
146 MAKE_FUNCPTR(FcFontSetDestroy);
147 MAKE_FUNCPTR(FcInit);
148 MAKE_FUNCPTR(FcObjectSetAdd);
149 MAKE_FUNCPTR(FcObjectSetCreate);
150 MAKE_FUNCPTR(FcObjectSetDestroy);
151 MAKE_FUNCPTR(FcPatternCreate);
152 MAKE_FUNCPTR(FcPatternDestroy);
153 MAKE_FUNCPTR(FcPatternGetString);
154 #ifndef SONAME_LIBFONTCONFIG
155 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
161 #ifndef ft_encoding_none
162 #define FT_ENCODING_NONE ft_encoding_none
164 #ifndef ft_encoding_ms_symbol
165 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
167 #ifndef ft_encoding_unicode
168 #define FT_ENCODING_UNICODE ft_encoding_unicode
170 #ifndef ft_encoding_apple_roman
171 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
174 #ifdef WORDS_BIGENDIAN
175 #define GET_BE_WORD(x) (x)
177 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
180 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
187 FT_Short internal_leading;
190 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
191 So to let this compile on older versions of FreeType we'll define the
192 new structure here. */
194 FT_Short height, width;
195 FT_Pos size, x_ppem, y_ppem;
198 typedef struct tagFace {
206 FONTSIGNATURE fs_links;
207 FT_Fixed font_version;
209 Bitmap_Size size; /* set if face is a bitmap */
210 BOOL external; /* TRUE if we should manually add this font to the registry */
211 struct tagFamily *family;
214 typedef struct tagFamily {
216 const WCHAR *FamilyName;
222 INT adv; /* These three hold to widths of the unrotated chars */
240 typedef struct tagHFONTLIST {
265 struct list hfontlist;
270 OUTLINETEXTMETRICW *potm;
273 struct list child_fonts;
279 const WCHAR *font_name;
283 #define INIT_GM_SIZE 128
285 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
286 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
287 #define UNUSED_CACHE_SIZE 10
288 static struct list child_font_list = LIST_INIT(child_font_list);
289 static struct list system_links = LIST_INIT(system_links);
291 static struct list font_subst_list = LIST_INIT(font_subst_list);
293 static struct list font_list = LIST_INIT(font_list);
295 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
296 'R','o','m','a','n','\0'};
297 static const WCHAR defSans[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
298 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
300 static const WCHAR defSystem[] = {'S','y','s','t','e','m','\0'};
301 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
302 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
303 'S','e','r','i','f','\0'};
304 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
305 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
307 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
308 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
309 'W','i','n','d','o','w','s','\\',
310 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
311 'F','o','n','t','s','\0'};
313 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
314 'W','i','n','d','o','w','s',' ','N','T','\\',
315 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
316 'F','o','n','t','s','\0'};
318 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
319 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
320 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
321 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
323 static const WCHAR * const SystemFontValues[4] = {
330 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
331 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
333 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
334 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
335 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
336 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
337 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
338 'E','u','r','o','p','e','a','n','\0'};
339 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
340 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
341 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
342 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
343 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
344 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
345 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
346 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
347 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
348 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
349 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
350 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
352 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
362 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
370 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
379 typedef struct tagFontSubst {
385 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
387 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
390 /****************************************
391 * Notes on .fon files
393 * The fonts System, FixedSys and Terminal are special. There are typically multiple
394 * versions installed for different resolutions and codepages. Windows stores which one to use
395 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
397 * FIXEDFON.FON FixedSys
399 * OEMFONT.FON Terminal
400 * LogPixels Current dpi set by the display control panel applet
401 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
402 * also has a LogPixels value that appears to mirror this)
404 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
405 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
406 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
407 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
408 * so that makes sense.
410 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
411 * to be mapped into the registry on Windows 2000 at least).
414 * ega80woa.fon=ega80850.fon
415 * ega40woa.fon=ega40850.fon
416 * cga80woa.fon=cga80850.fon
417 * cga40woa.fon=cga40850.fon
421 static inline BOOL is_win9x(void)
423 return GetVersion() & 0x80000000;
426 This function builds an FT_Fixed from a float. It puts the integer part
427 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
428 It fails if the integer part of the float number is greater than SHORT_MAX.
430 static inline FT_Fixed FT_FixedFromFloat(float f)
433 unsigned short fract = (f - value) * 0xFFFF;
434 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
438 This function builds an FT_Fixed from a FIXED. It simply put f.value
439 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
441 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
443 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
447 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
452 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
453 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
455 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
456 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
458 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
460 if(face_name && strcmpiW(face_name, family->FamilyName))
462 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
464 file = strrchr(face->file, '/');
469 if(!strcasecmp(file, file_nameA))
471 HeapFree(GetProcessHeap(), 0, file_nameA);
476 HeapFree(GetProcessHeap(), 0, file_nameA);
480 static Family *find_family_from_name(const WCHAR *name)
484 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
486 if(!strcmpiW(family->FamilyName, name))
493 static void DumpSubstList(void)
497 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
499 if(psub->from.charset != -1 || psub->to.charset != -1)
500 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
501 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
503 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
504 debugstr_w(psub->to.name));
509 static LPWSTR strdupW(LPCWSTR p)
512 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
513 ret = HeapAlloc(GetProcessHeap(), 0, len);
518 static LPSTR strdupA(LPCSTR p)
521 DWORD len = (strlen(p) + 1);
522 ret = HeapAlloc(GetProcessHeap(), 0, len);
527 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
532 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
534 if(!strcmpiW(element->from.name, from_name) &&
535 (element->from.charset == from_charset ||
536 element->from.charset == -1))
543 #define ADD_FONT_SUBST_FORCE 1
545 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
547 FontSubst *from_exist, *to_exist;
549 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
551 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
553 list_remove(&from_exist->entry);
554 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
555 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
556 HeapFree(GetProcessHeap(), 0, from_exist);
562 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
566 HeapFree(GetProcessHeap(), 0, subst->to.name);
567 subst->to.name = strdupW(to_exist->to.name);
570 list_add_tail(subst_list, &subst->entry);
575 HeapFree(GetProcessHeap(), 0, subst->from.name);
576 HeapFree(GetProcessHeap(), 0, subst->to.name);
577 HeapFree(GetProcessHeap(), 0, subst);
581 static void split_subst_info(NameCs *nc, LPSTR str)
583 CHAR *p = strrchr(str, ',');
588 nc->charset = strtol(p+1, NULL, 10);
591 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
592 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
593 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
596 static void LoadSubstList(void)
600 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
604 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
605 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
606 &hkey) == ERROR_SUCCESS) {
608 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
609 &valuelen, &datalen, NULL, NULL);
611 valuelen++; /* returned value doesn't include room for '\0' */
612 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
613 data = HeapAlloc(GetProcessHeap(), 0, datalen);
617 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
618 &dlen) == ERROR_SUCCESS) {
619 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
621 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
622 split_subst_info(&psub->from, value);
623 split_subst_info(&psub->to, data);
625 /* Win 2000 doesn't allow mapping between different charsets
626 or mapping of DEFAULT_CHARSET */
627 if((psub->to.charset != psub->from.charset) ||
628 psub->to.charset == DEFAULT_CHARSET) {
629 HeapFree(GetProcessHeap(), 0, psub->to.name);
630 HeapFree(GetProcessHeap(), 0, psub->from.name);
631 HeapFree(GetProcessHeap(), 0, psub);
633 add_font_subst(&font_subst_list, psub, 0);
635 /* reset dlen and vlen */
639 HeapFree(GetProcessHeap(), 0, data);
640 HeapFree(GetProcessHeap(), 0, value);
645 static WCHAR *get_familyname(FT_Face ft_face)
647 WCHAR *family = NULL;
649 FT_UInt num_names, name_index, i;
651 if(FT_IS_SFNT(ft_face))
653 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
655 for(name_index = 0; name_index < num_names; name_index++)
657 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
659 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
660 (name.language_id == GetUserDefaultLCID()) &&
661 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
662 (name.encoding_id == TT_MS_ID_UNICODE_CS))
664 /* String is not nul terminated and string_len is a byte length. */
665 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
666 for(i = 0; i < name.string_len / 2; i++)
668 WORD *tmp = (WORD *)&name.string[i * 2];
669 family[i] = GET_BE_WORD(*tmp);
673 TRACE("Got localised name %s\n", debugstr_w(family));
684 #define ADDFONT_EXTERNAL_FONT 0x01
685 #define ADDFONT_FORCE_BITMAP 0x02
686 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
690 TT_Header *pHeader = NULL;
691 WCHAR *english_family, *localised_family, *StyleW;
695 struct list *family_elem_ptr, *face_elem_ptr;
697 FT_Long face_index = 0, num_faces;
698 #ifdef HAVE_FREETYPE_FTWINFNT_H
699 FT_WinFNT_HeaderRec winfnt_header;
701 int i, bitmap_num, internal_leading;
705 char *family_name = fake_family;
707 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
708 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
709 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
713 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*/
714 WARN("Ignoring font %s\n", debugstr_a(file));
715 pFT_Done_Face(ft_face);
719 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
720 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
721 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file));
722 pFT_Done_Face(ft_face);
726 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
727 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
728 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
729 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
730 "Skipping this font.\n", debugstr_a(file));
731 pFT_Done_Face(ft_face);
735 if(!ft_face->family_name || !ft_face->style_name) {
736 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
737 pFT_Done_Face(ft_face);
742 family_name = ft_face->family_name;
746 My_FT_Bitmap_Size *size = NULL;
748 if(!FT_IS_SCALABLE(ft_face))
749 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
751 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
752 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
753 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
755 localised_family = NULL;
757 localised_family = get_familyname(ft_face);
758 if(localised_family && !strcmpW(localised_family, english_family)) {
759 HeapFree(GetProcessHeap(), 0, localised_family);
760 localised_family = NULL;
765 LIST_FOR_EACH(family_elem_ptr, &font_list) {
766 family = LIST_ENTRY(family_elem_ptr, Family, entry);
767 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
772 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
773 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
774 list_init(&family->faces);
775 list_add_tail(&font_list, &family->entry);
777 if(localised_family) {
778 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
779 subst->from.name = strdupW(english_family);
780 subst->from.charset = -1;
781 subst->to.name = strdupW(localised_family);
782 subst->to.charset = -1;
783 add_font_subst(&font_subst_list, subst, 0);
786 HeapFree(GetProcessHeap(), 0, localised_family);
787 HeapFree(GetProcessHeap(), 0, english_family);
789 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
790 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
791 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
793 internal_leading = 0;
794 memset(&fs, 0, sizeof(fs));
796 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
798 fs.fsCsb[0] = pOS2->ulCodePageRange1;
799 fs.fsCsb[1] = pOS2->ulCodePageRange2;
800 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
801 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
802 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
803 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
804 if(pOS2->version == 0) {
807 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
810 fs.fsCsb[0] |= 1L << 31;
813 #ifdef HAVE_FREETYPE_FTWINFNT_H
814 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
816 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
817 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
818 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
819 memcpy(&fs, &csi.fs, sizeof(csi.fs));
820 internal_leading = winfnt_header.internal_leading;
824 face_elem_ptr = list_head(&family->faces);
825 while(face_elem_ptr) {
826 face = LIST_ENTRY(face_elem_ptr, Face, entry);
827 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
828 if(!strcmpW(face->StyleName, StyleW) &&
829 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
830 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
831 debugstr_w(family->FamilyName), debugstr_w(StyleW),
832 face->font_version, pHeader ? pHeader->Font_Revision : 0);
835 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
836 HeapFree(GetProcessHeap(), 0, StyleW);
837 pFT_Done_Face(ft_face);
840 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
841 TRACE("Original font is newer so skipping this one\n");
842 HeapFree(GetProcessHeap(), 0, StyleW);
843 pFT_Done_Face(ft_face);
846 TRACE("Replacing original with this one\n");
847 list_remove(&face->entry);
848 HeapFree(GetProcessHeap(), 0, face->file);
849 HeapFree(GetProcessHeap(), 0, face->StyleName);
850 HeapFree(GetProcessHeap(), 0, face);
855 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
856 list_add_tail(&family->faces, &face->entry);
857 face->StyleName = StyleW;
858 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
859 strcpy(face->file, file);
860 face->face_index = face_index;
861 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
862 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
863 face->font_version = pHeader ? pHeader->Font_Revision : 0;
864 face->family = family;
865 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
866 memcpy(&face->fs, &fs, sizeof(face->fs));
867 memset(&face->fs_links, 0, sizeof(face->fs_links));
869 if(FT_IS_SCALABLE(ft_face)) {
870 memset(&face->size, 0, sizeof(face->size));
871 face->scalable = TRUE;
873 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
874 size->height, size->width, size->size >> 6,
875 size->x_ppem >> 6, size->y_ppem >> 6);
876 face->size.height = size->height;
877 face->size.width = size->width;
878 face->size.size = size->size;
879 face->size.x_ppem = size->x_ppem;
880 face->size.y_ppem = size->y_ppem;
881 face->size.internal_leading = internal_leading;
882 face->scalable = FALSE;
885 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
886 face->fs.fsCsb[0], face->fs.fsCsb[1],
887 face->fs.fsUsb[0], face->fs.fsUsb[1],
888 face->fs.fsUsb[2], face->fs.fsUsb[3]);
891 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
892 for(i = 0; i < ft_face->num_charmaps; i++) {
893 switch(ft_face->charmaps[i]->encoding) {
894 case FT_ENCODING_UNICODE:
895 case FT_ENCODING_APPLE_ROMAN:
896 face->fs.fsCsb[0] |= 1;
898 case FT_ENCODING_MS_SYMBOL:
899 face->fs.fsCsb[0] |= 1L << 31;
907 if(face->fs.fsCsb[0] & ~(1L << 31))
908 have_installed_roman_font = TRUE;
909 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
911 num_faces = ft_face->num_faces;
912 pFT_Done_Face(ft_face);
913 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
915 } while(num_faces > ++face_index);
919 static void DumpFontList(void)
923 struct list *family_elem_ptr, *face_elem_ptr;
925 LIST_FOR_EACH(family_elem_ptr, &font_list) {
926 family = LIST_ENTRY(family_elem_ptr, Family, entry);
927 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
928 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
929 face = LIST_ENTRY(face_elem_ptr, Face, entry);
930 TRACE("\t%s\t%08lx", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
932 TRACE(" %d", face->size.height);
939 /***********************************************************
940 * The replacement list is a way to map an entire font
941 * family onto another family. For example adding
943 * [HKCU\Software\Wine\Fonts\Replacements]
944 * "Wingdings"="Winedings"
946 * would enumerate the Winedings font both as Winedings and
947 * Wingdings. However if a real Wingdings font is present the
948 * replacement does not take place.
951 static void LoadReplaceList(void)
954 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
959 struct list *family_elem_ptr, *face_elem_ptr;
960 WCHAR old_nameW[200];
962 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
963 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
965 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
966 &valuelen, &datalen, NULL, NULL);
968 valuelen++; /* returned value doesn't include room for '\0' */
969 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
970 data = HeapAlloc(GetProcessHeap(), 0, datalen);
974 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
975 &dlen) == ERROR_SUCCESS) {
976 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
977 /* "NewName"="Oldname" */
978 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)/sizeof(WCHAR)))
981 /* Find the old family and hence all of the font files
983 LIST_FOR_EACH(family_elem_ptr, &font_list) {
984 family = LIST_ENTRY(family_elem_ptr, Family, entry);
985 if(!strcmpiW(family->FamilyName, old_nameW)) {
986 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
987 face = LIST_ENTRY(face_elem_ptr, Face, entry);
988 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
989 debugstr_w(face->StyleName), value);
990 /* Now add a new entry with the new family name */
991 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
996 /* reset dlen and vlen */
1000 HeapFree(GetProcessHeap(), 0, data);
1001 HeapFree(GetProcessHeap(), 0, value);
1006 /*************************************************************
1009 static BOOL init_system_links(void)
1011 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1012 'W','i','n','d','o','w','s',' ','N','T','\\',
1013 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1014 'S','y','s','t','e','m','L','i','n','k',0};
1017 DWORD type, max_val, max_data, val_len, data_len, index;
1018 WCHAR *value, *data;
1019 WCHAR *entry, *next;
1020 SYSTEM_LINKS *font_link, *system_font_link;
1021 CHILD_FONT *child_font;
1022 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1023 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1024 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1030 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1032 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1033 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1034 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1035 val_len = max_val + 1;
1036 data_len = max_data;
1038 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1040 TRACE("%s:\n", debugstr_w(value));
1042 memset(&fs, 0, sizeof(fs));
1043 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1044 psub = get_font_subst(&font_subst_list, value, -1);
1045 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1046 list_init(&font_link->links);
1047 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1050 CHILD_FONT *child_font;
1052 TRACE("\t%s\n", debugstr_w(entry));
1054 next = entry + strlenW(entry) + 1;
1056 face_name = strchrW(entry, ',');
1060 while(isspaceW(*face_name))
1063 psub = get_font_subst(&font_subst_list, face_name, -1);
1065 face_name = psub->to.name;
1067 face = find_face_from_filename(entry, face_name);
1070 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1074 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1075 child_font->file_name = strdupA(face->file);
1076 child_font->index = face->face_index;
1077 child_font->font = NULL;
1078 fs.fsCsb[0] |= face->fs.fsCsb[0];
1079 fs.fsCsb[1] |= face->fs.fsCsb[1];
1080 TRACE("Adding file %s index %d\n", child_font->file_name, child_font->index);
1081 list_add_tail(&font_link->links, &child_font->entry);
1083 family = find_family_from_name(font_link->font_name);
1086 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1088 memcpy(&face->fs_links, &fs, sizeof(fs));
1091 list_add_tail(&system_links, &font_link->entry);
1092 val_len = max_val + 1;
1093 data_len = max_data;
1096 HeapFree(GetProcessHeap(), 0, value);
1097 HeapFree(GetProcessHeap(), 0, data);
1101 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1104 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1105 system_font_link->font_name = strdupW(System);
1106 list_init(&system_font_link->links);
1108 face = find_face_from_filename(tahoma_ttf, Tahoma);
1111 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1112 child_font->file_name = strdupA(face->file);
1113 child_font->index = face->face_index;
1114 child_font->font = NULL;
1115 TRACE("Found Tahoma in %s index %d\n", child_font->file_name, child_font->index);
1116 list_add_tail(&system_font_link->links, &child_font->entry);
1118 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1120 if(!strcmpiW(font_link->font_name, Tahoma))
1122 CHILD_FONT *font_link_entry;
1123 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1125 CHILD_FONT *new_child;
1126 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1127 new_child->file_name = strdupA(font_link_entry->file_name);
1128 new_child->index = font_link_entry->index;
1129 new_child->font = NULL;
1130 list_add_tail(&system_font_link->links, &new_child->entry);
1135 list_add_tail(&system_links, &system_font_link->entry);
1139 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1142 struct dirent *dent;
1143 char path[MAX_PATH];
1145 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1147 dir = opendir(dirname);
1149 WARN("Can't open directory %s\n", debugstr_a(dirname));
1152 while((dent = readdir(dir)) != NULL) {
1153 struct stat statbuf;
1155 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1158 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1160 sprintf(path, "%s/%s", dirname, dent->d_name);
1162 if(stat(path, &statbuf) == -1)
1164 WARN("Can't stat %s\n", debugstr_a(path));
1167 if(S_ISDIR(statbuf.st_mode))
1168 ReadFontDir(path, external_fonts);
1170 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1176 static void load_fontconfig_fonts(void)
1178 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1179 void *fc_handle = NULL;
1185 const char *file, *ext;
1187 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1189 TRACE("Wine cannot find the fontconfig library (%s).\n",
1190 SONAME_LIBFONTCONFIG);
1193 #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;}
1194 LOAD_FUNCPTR(FcConfigGetCurrent);
1195 LOAD_FUNCPTR(FcFontList);
1196 LOAD_FUNCPTR(FcFontSetDestroy);
1197 LOAD_FUNCPTR(FcInit);
1198 LOAD_FUNCPTR(FcObjectSetAdd);
1199 LOAD_FUNCPTR(FcObjectSetCreate);
1200 LOAD_FUNCPTR(FcObjectSetDestroy);
1201 LOAD_FUNCPTR(FcPatternCreate);
1202 LOAD_FUNCPTR(FcPatternDestroy);
1203 LOAD_FUNCPTR(FcPatternGetString);
1206 if(!pFcInit()) return;
1208 config = pFcConfigGetCurrent();
1209 pat = pFcPatternCreate();
1210 os = pFcObjectSetCreate();
1211 pFcObjectSetAdd(os, FC_FILE);
1212 fontset = pFcFontList(config, pat, os);
1213 if(!fontset) return;
1214 for(i = 0; i < fontset->nfont; i++) {
1215 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1217 TRACE("fontconfig: %s\n", file);
1219 /* We're just interested in OT/TT fonts for now, so this hack just
1220 picks up the standard extensions to save time loading every other
1222 len = strlen( file );
1223 if(len < 4) continue;
1224 ext = &file[ len - 3 ];
1225 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
1226 AddFontFileToList(file, NULL, ADDFONT_EXTERNAL_FONT);
1228 pFcFontSetDestroy(fontset);
1229 pFcObjectSetDestroy(os);
1230 pFcPatternDestroy(pat);
1236 static BOOL load_font_from_data_dir(LPCWSTR file)
1239 const char *data_dir = wine_get_data_dir();
1241 if (!data_dir) data_dir = wine_get_build_dir();
1248 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1250 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1252 strcpy(unix_name, data_dir);
1253 strcat(unix_name, "/fonts/");
1255 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1257 ret = AddFontFileToList(unix_name, NULL, ADDFONT_FORCE_BITMAP);
1258 HeapFree(GetProcessHeap(), 0, unix_name);
1263 static void load_system_fonts(void)
1266 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1267 const WCHAR * const *value;
1269 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1272 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1273 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1274 strcatW(windowsdir, fontsW);
1275 for(value = SystemFontValues; *value; value++) {
1276 dlen = sizeof(data);
1277 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1281 sprintfW(pathW, fmtW, windowsdir, data);
1282 if((unixname = wine_get_unix_file_name(pathW))) {
1283 added = AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1284 HeapFree(GetProcessHeap(), 0, unixname);
1287 load_font_from_data_dir(data);
1294 /*************************************************************
1296 * This adds registry entries for any externally loaded fonts
1297 * (fonts from fontconfig or FontDirs). It also deletes entries
1298 * of no longer existing fonts.
1301 static void update_reg_entries(void)
1303 HKEY winkey = 0, externalkey = 0;
1306 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1309 struct list *family_elem_ptr, *face_elem_ptr;
1311 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1312 static const WCHAR spaceW[] = {' ', '\0'};
1315 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1316 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1317 ERR("Can't create Windows font reg key\n");
1320 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1321 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1322 ERR("Can't create external font reg key\n");
1326 /* Delete all external fonts added last time */
1328 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1329 &valuelen, &datalen, NULL, NULL);
1330 valuelen++; /* returned value doesn't include room for '\0' */
1331 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1332 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1334 dlen = datalen * sizeof(WCHAR);
1337 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1338 &dlen) == ERROR_SUCCESS) {
1340 RegDeleteValueW(winkey, valueW);
1341 /* reset dlen and vlen */
1345 HeapFree(GetProcessHeap(), 0, data);
1346 HeapFree(GetProcessHeap(), 0, valueW);
1348 /* Delete the old external fonts key */
1349 RegCloseKey(externalkey);
1351 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1353 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1354 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1355 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1356 ERR("Can't create external font reg key\n");
1360 /* enumerate the fonts and add external ones to the two keys */
1362 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1363 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1364 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1365 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1366 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1367 if(!face->external) continue;
1369 if(strcmpiW(face->StyleName, RegularW))
1370 len = len_fam + strlenW(face->StyleName) + 1;
1371 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1372 strcpyW(valueW, family->FamilyName);
1373 if(len != len_fam) {
1374 strcatW(valueW, spaceW);
1375 strcatW(valueW, face->StyleName);
1377 strcatW(valueW, TrueType);
1378 if((path = strrchr(face->file, '/')) == NULL)
1382 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1384 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1385 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1386 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1387 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1389 HeapFree(GetProcessHeap(), 0, file);
1390 HeapFree(GetProcessHeap(), 0, valueW);
1395 RegCloseKey(externalkey);
1397 RegCloseKey(winkey);
1402 /*************************************************************
1403 * WineEngAddFontResourceEx
1406 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1408 if (ft_handle) /* do it only if we have freetype up and running */
1413 FIXME("Ignoring flags %lx\n", flags);
1415 if((unixname = wine_get_unix_file_name(file)))
1417 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1418 HeapFree(GetProcessHeap(), 0, unixname);
1424 /*************************************************************
1425 * WineEngRemoveFontResourceEx
1428 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1434 static const struct nls_update_font_list
1436 UINT ansi_cp, oem_cp;
1437 const char *oem, *fixed, *system;
1438 const char *courier, *serif, *small, *sserif;
1439 } nls_update_font_list[] =
1441 /* Latin 1 (United States) */
1442 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1443 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1445 /* Latin 1 (Multilingual) */
1446 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1447 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1449 /* Eastern Europe */
1450 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1451 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1454 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1455 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1458 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1459 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1462 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1463 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1466 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1467 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1470 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1471 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1474 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1475 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1478 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1479 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1482 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1483 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1486 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1487 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1489 /* Chinese Simplified */
1490 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1491 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1494 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1495 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1497 /* Chinese Traditional */
1498 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1499 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1503 inline static HKEY create_fonts_NT_registry_key(void)
1507 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1508 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1512 inline static HKEY create_fonts_9x_registry_key(void)
1516 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1517 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1521 inline static HKEY create_config_fonts_registry_key(void)
1525 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1526 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1530 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1532 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1533 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1534 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1535 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1538 static void update_font_info(void)
1543 UINT i, ansi_cp = 0, oem_cp = 0;
1544 LCID lcid = GetUserDefaultLCID();
1546 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) != ERROR_SUCCESS)
1550 if (RegQueryValueExA(hkey, "Locale", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1552 if (strtoul(buf, NULL, 16 ) == lcid) /* already set correctly */
1557 TRACE("updating registry, locale changed %s -> %08lx\n", debugstr_a(buf), lcid);
1559 else TRACE("updating registry, locale changed none -> %08lx\n", lcid);
1561 sprintf(buf, "%08lx", lcid);
1562 RegSetValueExA(hkey, "Locale", 0, REG_SZ, (const BYTE *)buf, strlen(buf)+1);
1565 GetLocaleInfoW(lcid, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1566 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1567 GetLocaleInfoW(lcid, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1568 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1570 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1572 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1573 nls_update_font_list[i].oem_cp == oem_cp)
1577 hkey = create_config_fonts_registry_key();
1578 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1579 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1580 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1583 hkey = create_fonts_NT_registry_key();
1584 add_font_list(hkey, &nls_update_font_list[i]);
1587 hkey = create_fonts_9x_registry_key();
1588 add_font_list(hkey, &nls_update_font_list[i]);
1594 FIXME("there is no font defaults for lcid %04lx/ansi_cp %u", lcid, ansi_cp);
1597 /*************************************************************
1600 * Initialize FreeType library and create a list of available faces
1602 BOOL WineEngInit(void)
1604 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1605 static const WCHAR pathW[] = {'P','a','t','h',0};
1607 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1609 WCHAR windowsdir[MAX_PATH];
1612 const char *data_dir;
1616 /* update locale dependent font info in registry */
1619 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1622 "Wine cannot find the FreeType font library. To enable Wine to\n"
1623 "use TrueType fonts please install a version of FreeType greater than\n"
1624 "or equal to 2.0.5.\n"
1625 "http://www.freetype.org\n");
1629 #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;}
1631 LOAD_FUNCPTR(FT_Vector_Unit)
1632 LOAD_FUNCPTR(FT_Done_Face)
1633 LOAD_FUNCPTR(FT_Get_Char_Index)
1634 LOAD_FUNCPTR(FT_Get_Module)
1635 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1636 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1637 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1638 LOAD_FUNCPTR(FT_Init_FreeType)
1639 LOAD_FUNCPTR(FT_Load_Glyph)
1640 LOAD_FUNCPTR(FT_Matrix_Multiply)
1641 LOAD_FUNCPTR(FT_MulFix)
1642 LOAD_FUNCPTR(FT_New_Face)
1643 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1644 LOAD_FUNCPTR(FT_Outline_Transform)
1645 LOAD_FUNCPTR(FT_Outline_Translate)
1646 LOAD_FUNCPTR(FT_Select_Charmap)
1647 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1648 LOAD_FUNCPTR(FT_Vector_Transform)
1651 /* Don't warn if this one is missing */
1652 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1653 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1654 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1655 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
1656 #ifdef HAVE_FREETYPE_FTWINFNT_H
1657 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1659 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1660 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1661 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1662 <= 2.0.3 has FT_Sqrt64 */
1666 if(pFT_Init_FreeType(&library) != 0) {
1667 ERR("Can't init FreeType library\n");
1668 wine_dlclose(ft_handle, NULL, 0);
1672 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1673 if (pFT_Library_Version)
1675 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1677 if (FT_Version.major<=0)
1683 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1684 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1685 ((FT_Version.minor << 8) & 0x00ff00) |
1686 ((FT_Version.patch ) & 0x0000ff);
1688 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1689 ERR("Failed to create font mutex\n");
1692 WaitForSingleObject(font_mutex, INFINITE);
1694 /* load the system bitmap fonts */
1695 load_system_fonts();
1697 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1698 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1699 strcatW(windowsdir, fontsW);
1700 if((unixname = wine_get_unix_file_name(windowsdir)))
1702 ReadFontDir(unixname, FALSE);
1703 HeapFree(GetProcessHeap(), 0, unixname);
1706 /* load the system truetype fonts */
1707 data_dir = wine_get_data_dir();
1708 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
1709 strcpy(unixname, data_dir);
1710 strcat(unixname, "/fonts/");
1711 ReadFontDir(unixname, FALSE);
1712 HeapFree(GetProcessHeap(), 0, unixname);
1715 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1716 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1717 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1719 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1720 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1721 &hkey) == ERROR_SUCCESS) {
1723 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1724 &valuelen, &datalen, NULL, NULL);
1726 valuelen++; /* returned value doesn't include room for '\0' */
1727 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1728 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1731 dlen = datalen * sizeof(WCHAR);
1733 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1734 &dlen) == ERROR_SUCCESS) {
1735 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1737 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1739 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1740 HeapFree(GetProcessHeap(), 0, unixname);
1743 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1745 WCHAR pathW[MAX_PATH];
1746 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1749 sprintfW(pathW, fmtW, windowsdir, data);
1750 if((unixname = wine_get_unix_file_name(pathW)))
1752 added = AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1753 HeapFree(GetProcessHeap(), 0, unixname);
1756 load_font_from_data_dir(data);
1758 /* reset dlen and vlen */
1763 HeapFree(GetProcessHeap(), 0, data);
1764 HeapFree(GetProcessHeap(), 0, valueW);
1768 load_fontconfig_fonts();
1770 /* then look in any directories that we've specified in the config file */
1771 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
1772 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
1778 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
1780 len += sizeof(WCHAR);
1781 valueW = HeapAlloc( GetProcessHeap(), 0, len );
1782 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
1784 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
1785 valueA = HeapAlloc( GetProcessHeap(), 0, len );
1786 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
1787 TRACE( "got font path %s\n", debugstr_a(valueA) );
1791 LPSTR next = strchr( ptr, ':' );
1792 if (next) *next++ = 0;
1793 ReadFontDir( ptr, TRUE );
1796 HeapFree( GetProcessHeap(), 0, valueA );
1798 HeapFree( GetProcessHeap(), 0, valueW );
1807 update_reg_entries();
1809 init_system_links();
1811 ReleaseMutex(font_mutex);
1815 "Wine cannot find certain functions that it needs inside the FreeType\n"
1816 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1817 "FreeType to at least version 2.0.5.\n"
1818 "http://www.freetype.org\n");
1819 wine_dlclose(ft_handle, NULL, 0);
1825 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1828 TT_HoriHeader *pHori;
1832 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1833 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1835 if(height == 0) height = 16;
1837 /* Calc. height of EM square:
1839 * For +ve lfHeight we have
1840 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1841 * Re-arranging gives:
1842 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1844 * For -ve lfHeight we have
1846 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1847 * with il = winAscent + winDescent - units_per_em]
1852 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1853 ppem = ft_face->units_per_EM * height /
1854 (pHori->Ascender - pHori->Descender);
1856 ppem = ft_face->units_per_EM * height /
1857 (pOS2->usWinAscent + pOS2->usWinDescent);
1865 static LONG load_VDMX(GdiFont, LONG);
1867 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1872 TRACE("%s, %ld, %ld x %ld\n", debugstr_a(file), face_index, width, height);
1873 err = pFT_New_Face(library, file, face_index, &ft_face);
1875 ERR("FT_New_Face rets %d\n", err);
1879 /* set it here, as load_VDMX needs it */
1880 font->ft_face = ft_face;
1882 if(FT_IS_SCALABLE(ft_face)) {
1883 /* load the VDMX table if we have one */
1884 font->ppem = load_VDMX(font, height);
1886 font->ppem = calc_ppem_for_height(ft_face, height);
1888 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
1889 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, font->ppem, err);
1891 font->ppem = height;
1892 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1893 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1899 static int get_nearest_charset(Face *face, int *cp)
1901 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1902 a single face with the requested charset. The idea is to check if
1903 the selected font supports the current ANSI codepage, if it does
1904 return the corresponding charset, else return the first charset */
1907 int acp = GetACP(), i;
1911 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
1912 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1913 return csi.ciCharset;
1915 for(i = 0; i < 32; i++) {
1917 if(face->fs.fsCsb[0] & fs0) {
1918 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
1920 return csi.ciCharset;
1923 FIXME("TCI failing on %lx\n", fs0);
1927 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1928 face->fs.fsCsb[0], face->file);
1930 return DEFAULT_CHARSET;
1933 static GdiFont alloc_font(void)
1935 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1936 ret->gmsize = INIT_GM_SIZE;
1937 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1938 ret->gmsize * sizeof(*ret->gm));
1940 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1941 list_init(&ret->hfontlist);
1942 list_init(&ret->child_fonts);
1946 static void free_font(GdiFont font)
1948 struct list *cursor, *cursor2;
1950 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
1952 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
1953 struct list *first_hfont;
1954 HFONTLIST *hfontlist;
1955 list_remove(cursor);
1958 first_hfont = list_head(&child->font->hfontlist);
1959 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
1960 DeleteObject(hfontlist->hfont);
1961 HeapFree(GetProcessHeap(), 0, hfontlist);
1962 free_font(child->font);
1964 HeapFree(GetProcessHeap(), 0, child->file_name);
1965 HeapFree(GetProcessHeap(), 0, child);
1968 if (font->ft_face) pFT_Done_Face(font->ft_face);
1969 HeapFree(GetProcessHeap(), 0, font->potm);
1970 HeapFree(GetProcessHeap(), 0, font->name);
1971 HeapFree(GetProcessHeap(), 0, font->gm);
1972 HeapFree(GetProcessHeap(), 0, font);
1976 /*************************************************************
1979 * load the vdmx entry for the specified height
1982 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1983 ( ( (FT_ULong)_x4 << 24 ) | \
1984 ( (FT_ULong)_x3 << 16 ) | \
1985 ( (FT_ULong)_x2 << 8 ) | \
1988 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2003 static LONG load_VDMX(GdiFont font, LONG height)
2007 BYTE devXRatio, devYRatio;
2008 USHORT numRecs, numRatios;
2009 DWORD result, offset = -1;
2013 /* For documentation on VDMX records, see
2014 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2017 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2019 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2022 /* FIXME: need the real device aspect ratio */
2026 numRecs = GET_BE_WORD(hdr[1]);
2027 numRatios = GET_BE_WORD(hdr[2]);
2029 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2030 for(i = 0; i < numRatios; i++) {
2033 offset = (3 * 2) + (i * sizeof(Ratios));
2034 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2037 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2039 if((ratio.xRatio == 0 &&
2040 ratio.yStartRatio == 0 &&
2041 ratio.yEndRatio == 0) ||
2042 (devXRatio == ratio.xRatio &&
2043 devYRatio >= ratio.yStartRatio &&
2044 devYRatio <= ratio.yEndRatio))
2046 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2047 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2048 offset = GET_BE_WORD(tmp);
2054 FIXME("No suitable ratio found\n");
2058 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2060 BYTE startsz, endsz;
2063 recs = GET_BE_WORD(group.recs);
2064 startsz = group.startsz;
2065 endsz = group.endsz;
2067 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2069 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2070 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2071 if(result == GDI_ERROR) {
2072 FIXME("Failed to retrieve vTable\n");
2077 for(i = 0; i < recs; i++) {
2078 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2079 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2080 ppem = GET_BE_WORD(vTable[i * 3]);
2082 if(yMax + -yMin == height) {
2085 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2088 if(yMax + -yMin > height) {
2091 goto end; /* failed */
2093 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2094 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2095 ppem = GET_BE_WORD(vTable[i * 3]);
2096 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2102 TRACE("ppem not found for height %ld\n", height);
2106 if(ppem < startsz || ppem > endsz)
2109 for(i = 0; i < recs; i++) {
2111 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2113 if(yPelHeight > ppem)
2116 if(yPelHeight == ppem) {
2117 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2118 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2119 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2125 HeapFree(GetProcessHeap(), 0, vTable);
2131 static BOOL fontcmp(GdiFont font, FONT_DESC *fd)
2133 if(font->font_desc.hash != fd->hash) return TRUE;
2134 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2135 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2136 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2137 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2140 static void calc_hash(FONT_DESC *pfd)
2142 DWORD hash = 0, *ptr, two_chars;
2146 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2148 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2150 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2152 pwc = (WCHAR *)&two_chars;
2154 *pwc = toupperW(*pwc);
2156 *pwc = toupperW(*pwc);
2160 hash ^= !pfd->can_use_bitmap;
2165 static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2170 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2172 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2173 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2174 fd.can_use_bitmap = can_use_bitmap;
2177 /* try the in-use list */
2178 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2179 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2180 if(!fontcmp(ret, &fd)) {
2181 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2182 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2183 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2184 if(hflist->hfont == hfont)
2187 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2188 hflist->hfont = hfont;
2189 list_add_head(&ret->hfontlist, &hflist->entry);
2194 /* then the unused list */
2195 font_elem_ptr = list_head(&unused_gdi_font_list);
2196 while(font_elem_ptr) {
2197 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2198 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2199 if(!fontcmp(ret, &fd)) {
2200 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2201 assert(list_empty(&ret->hfontlist));
2202 TRACE("Found %p in unused list\n", ret);
2203 list_remove(&ret->entry);
2204 list_add_head(&gdi_font_list, &ret->entry);
2205 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2206 hflist->hfont = hfont;
2207 list_add_head(&ret->hfontlist, &hflist->entry);
2215 /*************************************************************
2216 * create_child_font_list
2218 static BOOL create_child_font_list(GdiFont font)
2221 SYSTEM_LINKS *font_link;
2222 CHILD_FONT *font_link_entry, *new_child;
2224 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2226 if(!strcmpW(font_link->font_name, font->name))
2228 TRACE("found entry in system list\n");
2229 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2231 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2232 new_child->file_name = strdupA(font_link_entry->file_name);
2233 new_child->index = font_link_entry->index;
2234 new_child->font = NULL;
2235 list_add_tail(&font->child_fonts, &new_child->entry);
2236 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
2246 /*************************************************************
2247 * WineEngCreateFontInstance
2250 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2253 Face *face, *best, *best_bitmap;
2254 Family *family, *last_resort_family;
2255 struct list *family_elem_ptr, *face_elem_ptr;
2256 INT height, width = 0;
2257 unsigned int score = 0, new_score;
2258 signed int diff = 0, newdiff;
2259 BOOL bd, it, can_use_bitmap;
2264 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2266 struct list *first_hfont = list_head(&ret->hfontlist);
2267 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2268 if(hflist->hfont == hfont)
2272 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2273 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2275 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
2276 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2277 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2280 /* check the cache first */
2281 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2282 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2286 TRACE("not in cache\n");
2287 if(list_empty(&font_list)) /* No fonts installed */
2289 TRACE("No fonts installed\n");
2292 if(!have_installed_roman_font)
2294 TRACE("No roman font installed\n");
2300 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2301 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2302 ret->font_desc.can_use_bitmap = can_use_bitmap;
2303 calc_hash(&ret->font_desc);
2304 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2305 hflist->hfont = hfont;
2306 list_add_head(&ret->hfontlist, &hflist->entry);
2309 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2310 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2311 original value lfCharSet. Note this is a special case for
2312 Symbol and doesn't happen at least for "Wingdings*" */
2314 if(!strcmpiW(lf.lfFaceName, SymbolW))
2315 lf.lfCharSet = SYMBOL_CHARSET;
2317 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2318 switch(lf.lfCharSet) {
2319 case DEFAULT_CHARSET:
2320 csi.fs.fsCsb[0] = 0;
2323 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2324 csi.fs.fsCsb[0] = 0;
2330 if(lf.lfFaceName[0] != '\0') {
2332 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2335 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2336 debugstr_w(psub->to.name));
2337 strcpyW(lf.lfFaceName, psub->to.name);
2340 /* We want a match on name and charset or just name if
2341 charset was DEFAULT_CHARSET. If the latter then
2342 we fixup the returned charset later in get_nearest_charset
2343 where we'll either use the charset of the current ansi codepage
2344 or if that's unavailable the first charset that the font supports.
2346 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2347 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2348 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2349 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2350 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2351 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2352 if(face->scalable || can_use_bitmap)
2359 /* If requested charset was DEFAULT_CHARSET then try using charset
2360 corresponding to the current ansi codepage */
2361 if(!csi.fs.fsCsb[0]) {
2363 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
2364 FIXME("TCI failed on codepage %d\n", acp);
2365 csi.fs.fsCsb[0] = 0;
2367 lf.lfCharSet = csi.ciCharset;
2370 /* Face families are in the top 4 bits of lfPitchAndFamily,
2371 so mask with 0xF0 before testing */
2373 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2374 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2375 strcpyW(lf.lfFaceName, defFixed);
2376 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2377 strcpyW(lf.lfFaceName, defSerif);
2378 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2379 strcpyW(lf.lfFaceName, defSans);
2381 strcpyW(lf.lfFaceName, defSans);
2382 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2383 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2384 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2385 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2386 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2387 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2388 if(face->scalable || can_use_bitmap)
2394 last_resort_family = NULL;
2395 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2396 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2397 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2398 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2399 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2402 if(can_use_bitmap && !last_resort_family)
2403 last_resort_family = family;
2408 if(last_resort_family) {
2409 family = last_resort_family;
2410 csi.fs.fsCsb[0] = 0;
2414 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2415 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2416 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2417 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2418 if(face->scalable) {
2419 csi.fs.fsCsb[0] = 0;
2420 FIXME("just using first face for now\n");
2423 if(can_use_bitmap && !last_resort_family)
2424 last_resort_family = family;
2427 if(!last_resort_family) {
2428 FIXME("can't find a single appropriate font - bailing\n");
2433 WARN("could only find a bitmap font - this will probably look awful!\n");
2434 family = last_resort_family;
2435 csi.fs.fsCsb[0] = 0;
2438 it = lf.lfItalic ? 1 : 0;
2439 bd = lf.lfWeight > 550 ? 1 : 0;
2441 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2442 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2444 face = best = best_bitmap = NULL;
2445 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2447 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2449 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
2450 if(!best || new_score <= score)
2452 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
2453 face->Italic, face->Bold, it, bd);
2456 if(best->scalable && score == 0) break;
2460 newdiff = height - (signed int)(best->size.height);
2462 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
2463 if(!best_bitmap || new_score < score ||
2464 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
2466 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
2469 if(score == 0 && diff == 0) break;
2476 face = best->scalable ? best : best_bitmap;
2477 ret->fake_italic = (it && !face->Italic);
2478 ret->fake_bold = (bd && !face->Bold);
2480 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2482 if(csi.fs.fsCsb[0]) {
2483 ret->charset = lf.lfCharSet;
2484 ret->codepage = csi.ciACP;
2487 ret->charset = get_nearest_charset(face, &ret->codepage);
2489 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2490 debugstr_w(face->StyleName), face->file, face->face_index);
2492 if(!face->scalable) {
2493 width = face->size.x_ppem >> 6;
2494 height = face->size.y_ppem >> 6;
2496 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2504 if (ret->charset == SYMBOL_CHARSET &&
2505 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2508 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2512 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2515 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2516 ret->name = strdupW(family->FamilyName);
2517 ret->underline = lf.lfUnderline ? 0xff : 0;
2518 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2519 create_child_font_list(ret);
2521 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2523 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
2524 list_add_head(&gdi_font_list, &ret->entry);
2528 static void dump_gdi_font_list(void)
2531 struct list *elem_ptr;
2533 TRACE("---------- gdiFont Cache ----------\n");
2534 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2535 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2536 TRACE("gdiFont=%p %s %ld\n",
2537 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2540 TRACE("---------- Unused gdiFont Cache ----------\n");
2541 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2542 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2543 TRACE("gdiFont=%p %s %ld\n",
2544 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2548 /*************************************************************
2549 * WineEngDestroyFontInstance
2551 * free the gdiFont associated with this handle
2554 BOOL WineEngDestroyFontInstance(HFONT handle)
2559 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2562 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
2564 struct list *first_hfont = list_head(&gdiFont->hfontlist);
2565 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2566 if(hflist->hfont == handle)
2568 TRACE("removing child font %p from child list\n", gdiFont);
2569 list_remove(&gdiFont->entry);
2574 TRACE("destroying hfont=%p\n", handle);
2576 dump_gdi_font_list();
2578 font_elem_ptr = list_head(&gdi_font_list);
2579 while(font_elem_ptr) {
2580 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2581 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
2583 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
2584 while(hfontlist_elem_ptr) {
2585 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2586 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
2587 if(hflist->hfont == handle) {
2588 list_remove(&hflist->entry);
2589 HeapFree(GetProcessHeap(), 0, hflist);
2593 if(list_empty(&gdiFont->hfontlist)) {
2594 TRACE("Moving to Unused list\n");
2595 list_remove(&gdiFont->entry);
2596 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
2601 font_elem_ptr = list_head(&unused_gdi_font_list);
2602 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
2603 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2604 while(font_elem_ptr) {
2605 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2606 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2607 TRACE("freeing %p\n", gdiFont);
2608 list_remove(&gdiFont->entry);
2614 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2615 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
2617 OUTLINETEXTMETRICW *potm = NULL;
2619 TEXTMETRICW tm, *ptm;
2620 GdiFont font = alloc_font();
2623 if(face->scalable) {
2627 height = face->size.y_ppem >> 6;
2628 width = face->size.x_ppem >> 6;
2631 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
2637 font->name = strdupW(face->family->FamilyName);
2639 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
2641 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
2643 potm = HeapAlloc(GetProcessHeap(), 0, size);
2644 WineEngGetOutlineTextMetrics(font, size, potm);
2645 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
2647 WineEngGetTextMetrics(font, &tm);
2651 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
2652 pntm->ntmTm.tmAscent = ptm->tmAscent;
2653 pntm->ntmTm.tmDescent = ptm->tmDescent;
2654 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
2655 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
2656 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
2657 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
2658 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
2659 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
2660 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
2661 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
2662 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
2663 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
2664 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
2665 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
2666 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
2667 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
2668 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
2669 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
2670 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
2671 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
2672 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2673 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2674 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
2676 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
2677 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
2678 *ptype |= RASTER_FONTTYPE;
2680 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2681 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2682 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2684 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
2685 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
2686 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2689 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
2691 lstrcpynW(pelf->elfLogFont.lfFaceName,
2692 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
2694 lstrcpynW(pelf->elfFullName,
2695 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
2697 lstrcpynW(pelf->elfStyle,
2698 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2701 HeapFree(GetProcessHeap(), 0, potm);
2703 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
2705 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2706 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2707 pelf->elfStyle[0] = '\0';
2710 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2715 /*************************************************************
2719 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2723 struct list *family_elem_ptr, *face_elem_ptr;
2725 NEWTEXTMETRICEXW ntm;
2726 DWORD type, ret = 1;
2732 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2734 if(plf->lfFaceName[0]) {
2736 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
2739 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2740 debugstr_w(psub->to.name));
2741 memcpy(&lf, plf, sizeof(lf));
2742 strcpyW(lf.lfFaceName, psub->to.name);
2746 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2747 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2748 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2749 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2750 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2751 GetEnumStructs(face, &elf, &ntm, &type);
2752 for(i = 0; i < 32; i++) {
2753 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2754 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2755 strcpyW(elf.elfScript, OEM_DOSW);
2756 i = 32; /* break out of loop */
2757 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2760 fs.fsCsb[0] = 1L << i;
2762 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2764 csi.ciCharset = DEFAULT_CHARSET;
2765 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2766 if(csi.ciCharset != DEFAULT_CHARSET) {
2767 elf.elfLogFont.lfCharSet =
2768 ntm.ntmTm.tmCharSet = csi.ciCharset;
2770 strcpyW(elf.elfScript, ElfScriptsW[i]);
2772 FIXME("Unknown elfscript for bit %d\n", i);
2775 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2776 debugstr_w(elf.elfLogFont.lfFaceName),
2777 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2778 csi.ciCharset, type, debugstr_w(elf.elfScript),
2779 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2780 ntm.ntmTm.ntmFlags);
2781 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2788 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2789 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2790 face_elem_ptr = list_head(&family->faces);
2791 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2792 GetEnumStructs(face, &elf, &ntm, &type);
2793 for(i = 0; i < 32; i++) {
2794 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2795 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2796 strcpyW(elf.elfScript, OEM_DOSW);
2797 i = 32; /* break out of loop */
2798 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2801 fs.fsCsb[0] = 1L << i;
2803 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2805 csi.ciCharset = DEFAULT_CHARSET;
2806 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2807 if(csi.ciCharset != DEFAULT_CHARSET) {
2808 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2811 strcpyW(elf.elfScript, ElfScriptsW[i]);
2813 FIXME("Unknown elfscript for bit %d\n", i);
2816 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2817 debugstr_w(elf.elfLogFont.lfFaceName),
2818 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2819 csi.ciCharset, type, debugstr_w(elf.elfScript),
2820 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2821 ntm.ntmTm.ntmFlags);
2822 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2831 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2833 pt->x.value = vec->x >> 6;
2834 pt->x.fract = (vec->x & 0x3f) << 10;
2835 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2836 pt->y.value = vec->y >> 6;
2837 pt->y.fract = (vec->y & 0x3f) << 10;
2838 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2842 /***************************************************
2843 * According to the MSDN documentation on WideCharToMultiByte,
2844 * certain codepages cannot set the default_used parameter.
2845 * This returns TRUE if the codepage can set that parameter, false else
2846 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
2848 static BOOL codepage_sets_default_used(UINT codepage)
2861 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2863 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
2864 WCHAR wc = (WCHAR)glyph;
2866 BOOL *default_used_pointer;
2869 default_used_pointer = NULL;
2870 default_used = FALSE;
2871 if (codepage_sets_default_used(font->codepage))
2872 default_used_pointer = &default_used;
2873 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
2876 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
2877 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
2881 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2882 glyph = glyph + 0xf000;
2883 return pFT_Get_Char_Index(font->ft_face, glyph);
2886 /*************************************************************
2887 * WineEngGetGlyphIndices
2889 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2891 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2892 LPWORD pgi, DWORD flags)
2895 WCHAR default_char = 0;
2898 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
2900 for(i = 0; i < count; i++)
2902 pgi[i] = get_glyph_index(font, lpstr[i]);
2907 WineEngGetTextMetrics(font, &textm);
2908 default_char = textm.tmDefaultChar;
2910 pgi[i] = default_char;
2916 /*************************************************************
2917 * WineEngGetGlyphOutline
2919 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2920 * except that the first parameter is the HWINEENGFONT of the font in
2921 * question rather than an HDC.
2924 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2925 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2928 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2929 FT_Face ft_face = font->ft_face;
2930 FT_UInt glyph_index;
2931 DWORD width, height, pitch, needed = 0;
2932 FT_Bitmap ft_bitmap;
2934 INT left, right, top = 0, bottom = 0;
2936 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2937 float widthRatio = 1.0;
2938 FT_Matrix transMat = identityMat;
2939 BOOL needsTransform = FALSE;
2942 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2943 buflen, buf, lpmat);
2945 if(format & GGO_GLYPH_INDEX) {
2946 glyph_index = glyph;
2947 format &= ~GGO_GLYPH_INDEX;
2949 glyph_index = get_glyph_index(font, glyph);
2951 if(glyph_index >= font->gmsize) {
2952 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2953 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2954 font->gmsize * sizeof(*font->gm));
2956 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2957 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2958 return 1; /* FIXME */
2962 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2963 load_flags |= FT_LOAD_NO_BITMAP;
2965 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2968 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2972 /* Scaling factor */
2973 if (font->aveWidth && font->potm) {
2974 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2977 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2978 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2980 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2981 font->gm[glyph_index].lsb = left >> 6;
2982 font->gm[glyph_index].bbx = (right - left) >> 6;
2984 /* Scaling transform */
2985 if(font->aveWidth) {
2987 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2990 scaleMat.yy = (1 << 16);
2992 pFT_Matrix_Multiply(&scaleMat, &transMat);
2993 needsTransform = TRUE;
2996 /* Slant transform */
2997 if (font->fake_italic) {
3000 slantMat.xx = (1 << 16);
3001 slantMat.xy = ((1 << 16) >> 2);
3003 slantMat.yy = (1 << 16);
3004 pFT_Matrix_Multiply(&slantMat, &transMat);
3005 needsTransform = TRUE;
3008 /* Rotation transform */
3009 if(font->orientation) {
3010 FT_Matrix rotationMat;
3012 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3013 pFT_Vector_Unit(&vecAngle, angle);
3014 rotationMat.xx = vecAngle.x;
3015 rotationMat.xy = -vecAngle.y;
3016 rotationMat.yx = -rotationMat.xy;
3017 rotationMat.yy = rotationMat.xx;
3019 pFT_Matrix_Multiply(&rotationMat, &transMat);
3020 needsTransform = TRUE;
3023 /* Extra transformation specified by caller */
3026 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3027 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3028 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3029 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3030 pFT_Matrix_Multiply(&extraMat, &transMat);
3031 needsTransform = TRUE;
3034 if(!needsTransform) {
3035 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3036 bottom = (ft_face->glyph->metrics.horiBearingY -
3037 ft_face->glyph->metrics.height) & -64;
3038 lpgm->gmCellIncX = font->gm[glyph_index].adv;
3039 lpgm->gmCellIncY = 0;
3043 for(xc = 0; xc < 2; xc++) {
3044 for(yc = 0; yc < 2; yc++) {
3045 vec.x = (ft_face->glyph->metrics.horiBearingX +
3046 xc * ft_face->glyph->metrics.width);
3047 vec.y = ft_face->glyph->metrics.horiBearingY -
3048 yc * ft_face->glyph->metrics.height;
3049 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3050 pFT_Vector_Transform(&vec, &transMat);
3051 if(xc == 0 && yc == 0) {
3052 left = right = vec.x;
3053 top = bottom = vec.y;
3055 if(vec.x < left) left = vec.x;
3056 else if(vec.x > right) right = vec.x;
3057 if(vec.y < bottom) bottom = vec.y;
3058 else if(vec.y > top) top = vec.y;
3063 right = (right + 63) & -64;
3064 bottom = bottom & -64;
3065 top = (top + 63) & -64;
3067 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3068 vec.x = ft_face->glyph->metrics.horiAdvance;
3070 pFT_Vector_Transform(&vec, &transMat);
3071 lpgm->gmCellIncX = (vec.x+63) >> 6;
3072 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3074 lpgm->gmBlackBoxX = (right - left) >> 6;
3075 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3076 lpgm->gmptGlyphOrigin.x = left >> 6;
3077 lpgm->gmptGlyphOrigin.y = top >> 6;
3079 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
3080 font->gm[glyph_index].init = TRUE;
3082 if(format == GGO_METRICS)
3083 return 1; /* FIXME */
3085 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
3086 TRACE("loaded a bitmap\n");
3092 width = lpgm->gmBlackBoxX;
3093 height = lpgm->gmBlackBoxY;
3094 pitch = ((width + 31) >> 5) << 2;
3095 needed = pitch * height;
3097 if(!buf || !buflen) break;
3099 switch(ft_face->glyph->format) {
3100 case ft_glyph_format_bitmap:
3102 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3103 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3104 INT h = ft_face->glyph->bitmap.rows;
3106 memcpy(dst, src, w);
3107 src += ft_face->glyph->bitmap.pitch;
3113 case ft_glyph_format_outline:
3114 ft_bitmap.width = width;
3115 ft_bitmap.rows = height;
3116 ft_bitmap.pitch = pitch;
3117 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3118 ft_bitmap.buffer = buf;
3120 if(needsTransform) {
3121 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3124 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3126 /* Note: FreeType will only set 'black' bits for us. */
3127 memset(buf, 0, needed);
3128 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3132 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3137 case GGO_GRAY2_BITMAP:
3138 case GGO_GRAY4_BITMAP:
3139 case GGO_GRAY8_BITMAP:
3140 case WINE_GGO_GRAY16_BITMAP:
3142 unsigned int mult, row, col;
3145 width = lpgm->gmBlackBoxX;
3146 height = lpgm->gmBlackBoxY;
3147 pitch = (width + 3) / 4 * 4;
3148 needed = pitch * height;
3150 if(!buf || !buflen) break;
3151 ft_bitmap.width = width;
3152 ft_bitmap.rows = height;
3153 ft_bitmap.pitch = pitch;
3154 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3155 ft_bitmap.buffer = buf;
3157 if(needsTransform) {
3158 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3161 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3163 memset(ft_bitmap.buffer, 0, buflen);
3165 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3167 if(format == GGO_GRAY2_BITMAP)
3169 else if(format == GGO_GRAY4_BITMAP)
3171 else if(format == GGO_GRAY8_BITMAP)
3173 else if(format == WINE_GGO_GRAY16_BITMAP)
3181 for(row = 0; row < height; row++) {
3183 for(col = 0; col < width; col++, ptr++) {
3184 *ptr = (((int)*ptr) * mult + 128) / 256;
3193 int contour, point = 0, first_pt;
3194 FT_Outline *outline = &ft_face->glyph->outline;
3195 TTPOLYGONHEADER *pph;
3197 DWORD pph_start, cpfx, type;
3199 if(buflen == 0) buf = NULL;
3201 if (needsTransform && buf) {
3202 pFT_Outline_Transform(outline, &transMat);
3205 for(contour = 0; contour < outline->n_contours; contour++) {
3207 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3210 pph->dwType = TT_POLYGON_TYPE;
3211 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3213 needed += sizeof(*pph);
3215 while(point <= outline->contours[contour]) {
3216 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3217 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3218 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3222 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3225 } while(point <= outline->contours[contour] &&
3226 (outline->tags[point] & FT_Curve_Tag_On) ==
3227 (outline->tags[point-1] & FT_Curve_Tag_On));
3228 /* At the end of a contour Windows adds the start point, but
3230 if(point > outline->contours[contour] &&
3231 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3233 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3235 } else if(point <= outline->contours[contour] &&
3236 outline->tags[point] & FT_Curve_Tag_On) {
3237 /* add closing pt for bezier */
3239 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3247 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3250 pph->cb = needed - pph_start;
3256 /* Convert the quadratic Beziers to cubic Beziers.
3257 The parametric eqn for a cubic Bezier is, from PLRM:
3258 r(t) = at^3 + bt^2 + ct + r0
3259 with the control points:
3264 A quadratic Beizer has the form:
3265 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3267 So equating powers of t leads to:
3268 r1 = 2/3 p1 + 1/3 p0
3269 r2 = 2/3 p1 + 1/3 p2
3270 and of course r0 = p0, r3 = p2
3273 int contour, point = 0, first_pt;
3274 FT_Outline *outline = &ft_face->glyph->outline;
3275 TTPOLYGONHEADER *pph;
3277 DWORD pph_start, cpfx, type;
3278 FT_Vector cubic_control[4];
3279 if(buflen == 0) buf = NULL;
3281 if (needsTransform && buf) {
3282 pFT_Outline_Transform(outline, &transMat);
3285 for(contour = 0; contour < outline->n_contours; contour++) {
3287 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3290 pph->dwType = TT_POLYGON_TYPE;
3291 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3293 needed += sizeof(*pph);
3295 while(point <= outline->contours[contour]) {
3296 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3297 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3298 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3301 if(type == TT_PRIM_LINE) {
3303 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3307 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3310 /* FIXME: Possible optimization in endpoint calculation
3311 if there are two consecutive curves */
3312 cubic_control[0] = outline->points[point-1];
3313 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3314 cubic_control[0].x += outline->points[point].x + 1;
3315 cubic_control[0].y += outline->points[point].y + 1;
3316 cubic_control[0].x >>= 1;
3317 cubic_control[0].y >>= 1;
3319 if(point+1 > outline->contours[contour])
3320 cubic_control[3] = outline->points[first_pt];
3322 cubic_control[3] = outline->points[point+1];
3323 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3324 cubic_control[3].x += outline->points[point].x + 1;
3325 cubic_control[3].y += outline->points[point].y + 1;
3326 cubic_control[3].x >>= 1;
3327 cubic_control[3].y >>= 1;
3330 /* r1 = 1/3 p0 + 2/3 p1
3331 r2 = 1/3 p2 + 2/3 p1 */
3332 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3333 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3334 cubic_control[2] = cubic_control[1];
3335 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3336 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3337 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3338 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3340 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3341 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3342 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3347 } while(point <= outline->contours[contour] &&
3348 (outline->tags[point] & FT_Curve_Tag_On) ==
3349 (outline->tags[point-1] & FT_Curve_Tag_On));
3350 /* At the end of a contour Windows adds the start point,
3351 but only for Beziers and we've already done that.
3353 if(point <= outline->contours[contour] &&
3354 outline->tags[point] & FT_Curve_Tag_On) {
3355 /* This is the closing pt of a bezier, but we've already
3356 added it, so just inc point and carry on */
3363 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3366 pph->cb = needed - pph_start;
3372 FIXME("Unsupported format %d\n", format);
3378 static BOOL get_bitmap_text_metrics(GdiFont font)
3380 FT_Face ft_face = font->ft_face;
3381 #ifdef HAVE_FREETYPE_FTWINFNT_H
3382 FT_WinFNT_HeaderRec winfnt_header;
3384 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3385 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3386 font->potm->otmSize = size;
3388 #define TM font->potm->otmTextMetrics
3389 #ifdef HAVE_FREETYPE_FTWINFNT_H
3390 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3392 TM.tmHeight = winfnt_header.pixel_height;
3393 TM.tmAscent = winfnt_header.ascent;
3394 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3395 TM.tmInternalLeading = winfnt_header.internal_leading;
3396 TM.tmExternalLeading = winfnt_header.external_leading;
3397 TM.tmAveCharWidth = winfnt_header.avg_width;
3398 TM.tmMaxCharWidth = winfnt_header.max_width;
3399 TM.tmWeight = winfnt_header.weight;
3401 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3402 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3403 TM.tmFirstChar = winfnt_header.first_char;
3404 TM.tmLastChar = winfnt_header.last_char;
3405 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3406 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3407 TM.tmItalic = winfnt_header.italic;
3408 TM.tmUnderlined = font->underline;
3409 TM.tmStruckOut = font->strikeout;
3410 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3411 TM.tmCharSet = winfnt_header.charset;
3416 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3417 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3418 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3419 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3420 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3421 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3422 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3423 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3425 TM.tmDigitizedAspectX = 96; /* FIXME */
3426 TM.tmDigitizedAspectY = 96; /* FIXME */
3428 TM.tmLastChar = 255;
3429 TM.tmDefaultChar = 32;
3430 TM.tmBreakChar = 32;
3431 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3432 TM.tmUnderlined = font->underline;
3433 TM.tmStruckOut = font->strikeout;
3434 /* NB inverted meaning of TMPF_FIXED_PITCH */
3435 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3436 TM.tmCharSet = font->charset;
3443 /*************************************************************
3444 * WineEngGetTextMetrics
3447 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3450 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3451 if(!get_bitmap_text_metrics(font))
3454 if(!font->potm) return FALSE;
3455 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3457 if (font->aveWidth) {
3458 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3464 /*************************************************************
3465 * WineEngGetOutlineTextMetrics
3468 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3469 OUTLINETEXTMETRICW *potm)
3471 FT_Face ft_face = font->ft_face;
3472 UINT needed, lenfam, lensty, ret;
3474 TT_HoriHeader *pHori;
3475 TT_Postscript *pPost;
3476 FT_Fixed x_scale, y_scale;
3477 WCHAR *family_nameW, *style_nameW;
3478 static const WCHAR spaceW[] = {' ', '\0'};
3480 INT ascent, descent;
3482 TRACE("font=%p\n", font);
3484 if(!FT_IS_SCALABLE(ft_face))
3488 if(cbSize >= font->potm->otmSize)
3489 memcpy(potm, font->potm, font->potm->otmSize);
3490 return font->potm->otmSize;
3494 needed = sizeof(*potm);
3496 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3497 family_nameW = strdupW(font->name);
3499 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3501 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3502 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3503 style_nameW, lensty/sizeof(WCHAR));
3505 /* These names should be read from the TT name table */
3507 /* length of otmpFamilyName */
3510 /* length of otmpFaceName */
3511 if(!strcasecmp(ft_face->style_name, "regular")) {
3512 needed += lenfam; /* just the family name */
3514 needed += lenfam + lensty; /* family + " " + style */
3517 /* length of otmpStyleName */
3520 /* length of otmpFullName */
3521 needed += lenfam + lensty;
3524 x_scale = ft_face->size->metrics.x_scale;
3525 y_scale = ft_face->size->metrics.y_scale;
3527 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3529 FIXME("Can't find OS/2 table - not TT font?\n");
3534 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3536 FIXME("Can't find HHEA table - not TT font?\n");
3541 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3543 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",
3544 pOS2->usWinAscent, pOS2->usWinDescent,
3545 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3546 ft_face->ascender, ft_face->descender, ft_face->height,
3547 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3548 ft_face->bbox.yMax, ft_face->bbox.yMin);
3550 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3551 font->potm->otmSize = needed;
3553 #define TM font->potm->otmTextMetrics
3555 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3556 ascent = pHori->Ascender;
3557 descent = -pHori->Descender;
3559 ascent = pOS2->usWinAscent;
3560 descent = pOS2->usWinDescent;
3564 TM.tmAscent = font->yMax;
3565 TM.tmDescent = -font->yMin;
3566 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3568 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
3569 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
3570 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
3571 - ft_face->units_per_EM, y_scale) + 32) >> 6;
3574 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3577 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3579 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
3580 ((ascent + descent) -
3581 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
3583 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
3584 if (TM.tmAveCharWidth == 0) {
3585 TM.tmAveCharWidth = 1;
3587 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
3588 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
3590 TM.tmDigitizedAspectX = 300;
3591 TM.tmDigitizedAspectY = 300;
3592 TM.tmFirstChar = pOS2->usFirstCharIndex;
3593 TM.tmLastChar = pOS2->usLastCharIndex;
3594 TM.tmDefaultChar = pOS2->usDefaultChar;
3595 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
3596 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3597 TM.tmUnderlined = font->underline;
3598 TM.tmStruckOut = font->strikeout;
3600 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3601 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3602 (pOS2->version == 0xFFFFU ||
3603 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3604 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3606 TM.tmPitchAndFamily = 0;
3608 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
3609 case PAN_FAMILY_SCRIPT:
3610 TM.tmPitchAndFamily |= FF_SCRIPT;
3612 case PAN_FAMILY_DECORATIVE:
3613 case PAN_FAMILY_PICTORIAL:
3614 TM.tmPitchAndFamily |= FF_DECORATIVE;
3616 case PAN_FAMILY_TEXT_DISPLAY:
3617 if(TM.tmPitchAndFamily == 0) /* fixed */
3618 TM.tmPitchAndFamily = FF_MODERN;
3620 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
3621 case PAN_SERIF_NORMAL_SANS:
3622 case PAN_SERIF_OBTUSE_SANS:
3623 case PAN_SERIF_PERP_SANS:
3624 TM.tmPitchAndFamily |= FF_SWISS;
3627 TM.tmPitchAndFamily |= FF_ROMAN;
3632 TM.tmPitchAndFamily |= FF_DONTCARE;
3635 if(FT_IS_SCALABLE(ft_face))
3636 TM.tmPitchAndFamily |= TMPF_VECTOR;
3637 if(FT_IS_SFNT(ft_face))
3638 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3640 TM.tmCharSet = font->charset;
3643 font->potm->otmFiller = 0;
3644 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3645 font->potm->otmfsSelection = pOS2->fsSelection;
3646 font->potm->otmfsType = pOS2->fsType;
3647 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
3648 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
3649 font->potm->otmItalicAngle = 0; /* POST table */
3650 font->potm->otmEMSquare = ft_face->units_per_EM;
3651 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
3652 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
3653 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
3654 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
3655 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
3656 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
3657 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
3658 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
3659 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
3660 font->potm->otmMacAscent = 0; /* where do these come from ? */
3661 font->potm->otmMacDescent = 0;
3662 font->potm->otmMacLineGap = 0;
3663 font->potm->otmusMinimumPPEM = 0; /* TT Header */
3664 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
3665 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
3666 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
3667 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
3668 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
3669 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
3670 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
3671 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
3672 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
3673 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
3675 font->potm->otmsUnderscoreSize = 0;
3676 font->potm->otmsUnderscorePosition = 0;
3678 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
3679 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
3682 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
3683 cp = (char*)font->potm + sizeof(*font->potm);
3684 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
3685 strcpyW((WCHAR*)cp, family_nameW);
3687 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
3688 strcpyW((WCHAR*)cp, style_nameW);
3690 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
3691 strcpyW((WCHAR*)cp, family_nameW);
3692 if(strcasecmp(ft_face->style_name, "regular")) {
3693 strcatW((WCHAR*)cp, spaceW);
3694 strcatW((WCHAR*)cp, style_nameW);
3695 cp += lenfam + lensty;
3698 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
3699 strcpyW((WCHAR*)cp, family_nameW);
3700 strcatW((WCHAR*)cp, spaceW);
3701 strcatW((WCHAR*)cp, style_nameW);
3704 if(potm && needed <= cbSize)
3705 memcpy(potm, font->potm, font->potm->otmSize);
3708 HeapFree(GetProcessHeap(), 0, style_nameW);
3709 HeapFree(GetProcessHeap(), 0, family_nameW);
3714 static BOOL load_child_font(GdiFont font, CHILD_FONT *child)
3716 HFONTLIST *hfontlist;
3717 child->font = alloc_font();
3718 child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem);
3719 if(!child->font->ft_face)
3721 free_font(child->font);
3726 child->font->orientation = font->orientation;
3727 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
3728 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
3729 list_add_head(&child->font->hfontlist, &hfontlist->entry);
3730 child->font->base_font = font;
3731 list_add_head(&child_font_list, &child->font->entry);
3732 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
3736 static BOOL get_glyph_index_linked(GdiFont font, UINT c, GdiFont *linked_font, FT_UInt *glyph)
3739 CHILD_FONT *child_font;
3742 font = font->base_font;
3744 *linked_font = font;
3746 if((*glyph = get_glyph_index(font, c)))
3749 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
3751 if(!child_font->font)
3752 if(!load_child_font(font, child_font))
3755 if(!child_font->font->ft_face)
3757 g = get_glyph_index(child_font->font, c);
3761 *linked_font = child_font->font;
3768 /*************************************************************
3769 * WineEngGetCharWidth
3772 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3777 FT_UInt glyph_index;
3778 GdiFont linked_font;
3780 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3782 for(c = firstChar; c <= lastChar; c++) {
3783 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3784 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3785 &gm, 0, NULL, NULL);
3786 buffer[c - firstChar] = linked_font->gm[glyph_index].adv;
3791 /*************************************************************
3792 * WineEngGetCharABCWidths
3795 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3800 FT_UInt glyph_index;
3801 GdiFont linked_font;
3803 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3805 if(!FT_IS_SCALABLE(font->ft_face))
3808 for(c = firstChar; c <= lastChar; c++) {
3809 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3810 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3811 &gm, 0, NULL, NULL);
3812 buffer[c - firstChar].abcA = linked_font->gm[glyph_index].lsb;
3813 buffer[c - firstChar].abcB = linked_font->gm[glyph_index].bbx;
3814 buffer[c - firstChar].abcC = linked_font->gm[glyph_index].adv - linked_font->gm[glyph_index].lsb -
3815 linked_font->gm[glyph_index].bbx;
3820 /*************************************************************
3821 * WineEngGetCharABCWidthsI
3824 BOOL WineEngGetCharABCWidthsI(GdiFont font, UINT firstChar, UINT count, LPWORD pgi,
3829 FT_UInt glyph_index;
3830 GdiFont linked_font;
3832 if(!FT_IS_SCALABLE(font->ft_face))
3835 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
3837 for(c = firstChar; c < firstChar+count; c++) {
3838 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
3839 &gm, 0, NULL, NULL);
3840 buffer[c - firstChar].abcA = linked_font->gm[c].lsb;
3841 buffer[c - firstChar].abcB = linked_font->gm[c].bbx;
3842 buffer[c - firstChar].abcC = linked_font->gm[c].adv - linked_font->gm[c].lsb
3843 - linked_font->gm[c].bbx;
3846 for(c = 0; c < count; c++) {
3847 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
3848 &gm, 0, NULL, NULL);
3849 buffer[c].abcA = linked_font->gm[pgi[c]].lsb;
3850 buffer[c].abcB = linked_font->gm[pgi[c]].bbx;
3851 buffer[c].abcC = linked_font->gm[pgi[c]].adv
3852 - linked_font->gm[pgi[c]].lsb - linked_font->gm[pgi[c]].bbx;
3858 /*************************************************************
3859 * WineEngGetTextExtentExPoint
3862 BOOL WineEngGetTextExtentExPoint(GdiFont font, LPCWSTR wstr, INT count,
3863 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
3869 FT_UInt glyph_index;
3870 GdiFont linked_font;
3872 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
3876 WineEngGetTextMetrics(font, &tm);
3877 size->cy = tm.tmHeight;
3879 for(idx = 0; idx < count; idx++) {
3880 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
3881 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3882 &gm, 0, NULL, NULL);
3883 size->cx += linked_font->gm[glyph_index].adv;
3885 if (! pnfit || ext <= max_ext) {
3895 TRACE("return %ld, %ld, %d\n", size->cx, size->cy, nfit);
3899 /*************************************************************
3900 * WineEngGetTextExtentPointI
3903 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3910 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3913 WineEngGetTextMetrics(font, &tm);
3914 size->cy = tm.tmHeight;
3916 for(idx = 0; idx < count; idx++) {
3917 WineEngGetGlyphOutline(font, indices[idx],
3918 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3920 size->cx += font->gm[indices[idx]].adv;
3922 TRACE("return %ld,%ld\n", size->cx, size->cy);
3926 /*************************************************************
3927 * WineEngGetFontData
3930 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3933 FT_Face ft_face = font->ft_face;
3937 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3938 font, table, offset, buf, cbData);
3940 if(!FT_IS_SFNT(ft_face))
3948 if(table) { /* MS tags differ in endidness from FT ones */
3949 table = table >> 24 | table << 24 |
3950 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3953 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3954 if(pFT_Load_Sfnt_Table) {
3955 /* make sure value of len is the value freetype says it needs */
3957 FT_ULong needed = 0;
3958 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3959 if( !err && needed < len) len = needed;
3961 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3963 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
3964 else { /* Do it the hard way */
3965 TT_Face tt_face = (TT_Face) ft_face;
3966 SFNT_Interface *sfnt;
3967 if (FT_Version.major==2 && FT_Version.minor==0)
3970 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3974 /* A field was added in the middle of the structure in 2.1.x */
3975 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3977 /* make sure value of len is the value freetype says it needs */
3979 FT_ULong needed = 0;
3980 err = sfnt->load_any(tt_face, table, offset, NULL, &needed);
3981 if( !err && needed < len) len = needed;
3983 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3989 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
3990 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
3991 "Please upgrade your freetype library.\n");
3994 err = FT_Err_Unimplemented_Feature;
3998 TRACE("Can't find table %08lx.\n", table);
4004 /*************************************************************
4005 * WineEngGetTextFace
4008 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
4011 lstrcpynW(str, font->name, count);
4012 return strlenW(font->name);
4014 return strlenW(font->name) + 1;
4017 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
4019 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4020 return font->charset;
4023 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4025 GdiFont font = dc->gdiFont, linked_font;
4026 struct list *first_hfont;
4029 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4030 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4031 if(font == linked_font)
4032 *new_hfont = dc->hFont;
4035 first_hfont = list_head(&linked_font->hfontlist);
4036 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4043 /*************************************************************
4046 BOOL WINAPI FontIsLinked(HDC hdc)
4048 DC *dc = DC_GetDCPtr(hdc);
4051 if(!dc) return FALSE;
4052 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
4054 GDI_ReleaseObj(hdc);
4055 TRACE("returning %d\n", ret);
4059 static BOOL is_hinting_enabled(void)
4061 /* Use the >= 2.2.0 function if available */
4062 if(pFT_Get_TrueType_Engine_Type)
4064 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4065 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4067 #ifdef FT_DRIVER_HAS_HINTER
4072 /* otherwise if we've been compiled with < 2.2.0 headers
4073 use the internal macro */
4074 mod = pFT_Get_Module(library, "truetype");
4075 if(mod && FT_DRIVER_HAS_HINTER(mod))
4083 /*************************************************************************
4084 * GetRasterizerCaps (GDI32.@)
4086 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4088 static int hinting = -1;
4091 hinting = is_hinting_enabled();
4093 lprs->nSize = sizeof(RASTERIZER_STATUS);
4094 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4095 lprs->nLanguageID = 0;
4100 #else /* HAVE_FREETYPE */
4102 /*************************************************************************/
4104 BOOL WineEngInit(void)
4108 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
4112 BOOL WineEngDestroyFontInstance(HFONT hfont)
4117 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4122 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
4123 LPWORD pgi, DWORD flags)
4128 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
4129 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4132 ERR("called but we don't have FreeType\n");
4136 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
4138 ERR("called but we don't have FreeType\n");
4142 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
4143 OUTLINETEXTMETRICW *potm)
4145 ERR("called but we don't have FreeType\n");
4149 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
4152 ERR("called but we don't have FreeType\n");
4156 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
4159 ERR("called but we don't have FreeType\n");
4163 BOOL WineEngGetCharABCWidthsI(GdiFont font, UINT firstChar, UINT count, LPWORD pgi,
4166 ERR("called but we don't have FreeType\n");
4170 BOOL WineEngGetTextExtentExPoint(GdiFont font, LPCWSTR wstr, INT count,
4171 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
4173 ERR("called but we don't have FreeType\n");
4177 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
4180 ERR("called but we don't have FreeType\n");
4184 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
4187 ERR("called but we don't have FreeType\n");
4191 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
4193 ERR("called but we don't have FreeType\n");
4197 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4203 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4209 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
4212 return DEFAULT_CHARSET;
4215 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4220 BOOL WINAPI FontIsLinked(HDC hdc)
4225 /*************************************************************************
4226 * GetRasterizerCaps (GDI32.@)
4228 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4230 lprs->nSize = sizeof(RASTERIZER_STATUS);
4232 lprs->nLanguageID = 0;
4236 #endif /* HAVE_FREETYPE */