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);
456 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
457 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
459 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
461 if(face_name && strcmpiW(face_name, family->FamilyName))
463 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
465 file = strrchr(face->file, '/');
470 if(!strcmp(file, file_nameA))
475 HeapFree(GetProcessHeap(), 0, file_nameA);
479 static Family *find_family_from_name(const WCHAR *name)
483 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
485 if(!strcmpiW(family->FamilyName, name))
492 static void DumpSubstList(void)
496 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
498 if(psub->from.charset != -1 || psub->to.charset != -1)
499 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
500 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
502 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
503 debugstr_w(psub->to.name));
508 static LPWSTR strdupW(LPCWSTR p)
511 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
512 ret = HeapAlloc(GetProcessHeap(), 0, len);
517 static LPSTR strdupA(LPCSTR p)
520 DWORD len = (strlen(p) + 1);
521 ret = HeapAlloc(GetProcessHeap(), 0, len);
526 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
531 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
533 if(!strcmpiW(element->from.name, from_name) &&
534 (element->from.charset == from_charset ||
535 element->from.charset == -1))
542 #define ADD_FONT_SUBST_FORCE 1
544 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
546 FontSubst *from_exist, *to_exist;
548 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
550 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
552 list_remove(&from_exist->entry);
553 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
554 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
555 HeapFree(GetProcessHeap(), 0, from_exist);
561 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
565 HeapFree(GetProcessHeap(), 0, subst->to.name);
566 subst->to.name = strdupW(to_exist->to.name);
569 list_add_tail(subst_list, &subst->entry);
574 HeapFree(GetProcessHeap(), 0, subst->from.name);
575 HeapFree(GetProcessHeap(), 0, subst->to.name);
576 HeapFree(GetProcessHeap(), 0, subst);
580 static void split_subst_info(NameCs *nc, LPSTR str)
582 CHAR *p = strrchr(str, ',');
587 nc->charset = strtol(p+1, NULL, 10);
590 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
591 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
592 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
595 static void LoadSubstList(void)
599 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
603 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
604 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
605 &hkey) == ERROR_SUCCESS) {
607 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
608 &valuelen, &datalen, NULL, NULL);
610 valuelen++; /* returned value doesn't include room for '\0' */
611 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
612 data = HeapAlloc(GetProcessHeap(), 0, datalen);
616 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
617 &dlen) == ERROR_SUCCESS) {
618 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
620 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
621 split_subst_info(&psub->from, value);
622 split_subst_info(&psub->to, data);
624 /* Win 2000 doesn't allow mapping between different charsets
625 or mapping of DEFAULT_CHARSET */
626 if((psub->to.charset != psub->from.charset) ||
627 psub->to.charset == DEFAULT_CHARSET) {
628 HeapFree(GetProcessHeap(), 0, psub->to.name);
629 HeapFree(GetProcessHeap(), 0, psub->from.name);
630 HeapFree(GetProcessHeap(), 0, psub);
632 add_font_subst(&font_subst_list, psub, 0);
634 /* reset dlen and vlen */
638 HeapFree(GetProcessHeap(), 0, data);
639 HeapFree(GetProcessHeap(), 0, value);
644 static WCHAR *get_familyname(FT_Face ft_face)
646 WCHAR *family = NULL;
648 FT_UInt num_names, name_index, i;
650 if(FT_IS_SFNT(ft_face))
652 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
654 for(name_index = 0; name_index < num_names; name_index++)
656 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
658 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
659 (name.language_id == GetUserDefaultLCID()) &&
660 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
661 (name.encoding_id == TT_MS_ID_UNICODE_CS))
663 /* String is not nul terminated and string_len is a byte length. */
664 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
665 for(i = 0; i < name.string_len / 2; i++)
667 WORD *tmp = (WORD *)&name.string[i * 2];
668 family[i] = GET_BE_WORD(*tmp);
672 TRACE("Got localised name %s\n", debugstr_w(family));
683 #define ADDFONT_EXTERNAL_FONT 0x01
684 #define ADDFONT_FORCE_BITMAP 0x02
685 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
689 TT_Header *pHeader = NULL;
690 WCHAR *english_family, *localised_family, *StyleW;
694 struct list *family_elem_ptr, *face_elem_ptr;
696 FT_Long face_index = 0, num_faces;
697 #ifdef HAVE_FREETYPE_FTWINFNT_H
698 FT_WinFNT_HeaderRec winfnt_header;
700 int i, bitmap_num, internal_leading;
704 char *family_name = fake_family;
706 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
707 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
708 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
712 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*/
713 WARN("Ignoring font %s\n", debugstr_a(file));
714 pFT_Done_Face(ft_face);
718 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
719 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
720 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file));
721 pFT_Done_Face(ft_face);
725 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
726 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
727 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
728 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
729 "Skipping this font.\n", debugstr_a(file));
730 pFT_Done_Face(ft_face);
734 if(!ft_face->family_name || !ft_face->style_name) {
735 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
736 pFT_Done_Face(ft_face);
741 family_name = ft_face->family_name;
745 My_FT_Bitmap_Size *size = NULL;
747 if(!FT_IS_SCALABLE(ft_face))
748 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
750 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
751 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
752 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
754 localised_family = NULL;
756 localised_family = get_familyname(ft_face);
757 if(localised_family && !strcmpW(localised_family, english_family)) {
758 HeapFree(GetProcessHeap(), 0, localised_family);
759 localised_family = NULL;
764 LIST_FOR_EACH(family_elem_ptr, &font_list) {
765 family = LIST_ENTRY(family_elem_ptr, Family, entry);
766 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
771 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
772 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
773 list_init(&family->faces);
774 list_add_tail(&font_list, &family->entry);
776 if(localised_family) {
777 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
778 subst->from.name = strdupW(english_family);
779 subst->from.charset = -1;
780 subst->to.name = strdupW(localised_family);
781 subst->to.charset = -1;
782 add_font_subst(&font_subst_list, subst, 0);
785 HeapFree(GetProcessHeap(), 0, localised_family);
786 HeapFree(GetProcessHeap(), 0, english_family);
788 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
789 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
790 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
792 internal_leading = 0;
793 memset(&fs, 0, sizeof(fs));
795 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
797 fs.fsCsb[0] = pOS2->ulCodePageRange1;
798 fs.fsCsb[1] = pOS2->ulCodePageRange2;
799 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
800 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
801 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
802 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
803 if(pOS2->version == 0) {
806 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
809 fs.fsCsb[0] |= 1L << 31;
812 #ifdef HAVE_FREETYPE_FTWINFNT_H
813 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
815 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
816 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
817 if(TranslateCharsetInfo((DWORD*)(UINT)winfnt_header.charset, &csi, TCI_SRCCHARSET))
818 memcpy(&fs, &csi.fs, sizeof(csi.fs));
819 internal_leading = winfnt_header.internal_leading;
823 face_elem_ptr = list_head(&family->faces);
824 while(face_elem_ptr) {
825 face = LIST_ENTRY(face_elem_ptr, Face, entry);
826 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
827 if(!strcmpW(face->StyleName, StyleW) &&
828 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
829 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
830 debugstr_w(family->FamilyName), debugstr_w(StyleW),
831 face->font_version, pHeader ? pHeader->Font_Revision : 0);
834 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
835 HeapFree(GetProcessHeap(), 0, StyleW);
836 pFT_Done_Face(ft_face);
839 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
840 TRACE("Original font is newer so skipping this one\n");
841 HeapFree(GetProcessHeap(), 0, StyleW);
842 pFT_Done_Face(ft_face);
845 TRACE("Replacing original with this one\n");
846 list_remove(&face->entry);
847 HeapFree(GetProcessHeap(), 0, face->file);
848 HeapFree(GetProcessHeap(), 0, face->StyleName);
849 HeapFree(GetProcessHeap(), 0, face);
854 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
855 list_add_tail(&family->faces, &face->entry);
856 face->StyleName = StyleW;
857 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
858 strcpy(face->file, file);
859 face->face_index = face_index;
860 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
861 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
862 face->font_version = pHeader ? pHeader->Font_Revision : 0;
863 face->family = family;
864 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
865 memcpy(&face->fs, &fs, sizeof(face->fs));
866 memset(&face->fs_links, 0, sizeof(face->fs_links));
868 if(FT_IS_SCALABLE(ft_face)) {
869 memset(&face->size, 0, sizeof(face->size));
870 face->scalable = TRUE;
872 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
873 size->height, size->width, size->size >> 6,
874 size->x_ppem >> 6, size->y_ppem >> 6);
875 face->size.height = size->height;
876 face->size.width = size->width;
877 face->size.size = size->size;
878 face->size.x_ppem = size->x_ppem;
879 face->size.y_ppem = size->y_ppem;
880 face->size.internal_leading = internal_leading;
881 face->scalable = FALSE;
884 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
885 face->fs.fsCsb[0], face->fs.fsCsb[1],
886 face->fs.fsUsb[0], face->fs.fsUsb[1],
887 face->fs.fsUsb[2], face->fs.fsUsb[3]);
890 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
891 for(i = 0; i < ft_face->num_charmaps; i++) {
892 switch(ft_face->charmaps[i]->encoding) {
893 case FT_ENCODING_UNICODE:
894 case FT_ENCODING_APPLE_ROMAN:
895 face->fs.fsCsb[0] |= 1;
897 case FT_ENCODING_MS_SYMBOL:
898 face->fs.fsCsb[0] |= 1L << 31;
906 if(face->fs.fsCsb[0] & ~(1L << 31))
907 have_installed_roman_font = TRUE;
908 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
910 num_faces = ft_face->num_faces;
911 pFT_Done_Face(ft_face);
912 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
914 } while(num_faces > ++face_index);
918 static void DumpFontList(void)
922 struct list *family_elem_ptr, *face_elem_ptr;
924 LIST_FOR_EACH(family_elem_ptr, &font_list) {
925 family = LIST_ENTRY(family_elem_ptr, Family, entry);
926 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
927 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
928 face = LIST_ENTRY(face_elem_ptr, Face, entry);
929 TRACE("\t%s\t%08lx", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
931 TRACE(" %d", face->size.height);
938 /***********************************************************
939 * The replacement list is a way to map an entire font
940 * family onto another family. For example adding
942 * [HKCU\Software\Wine\Fonts\Replacements]
943 * "Wingdings"="Winedings"
945 * would enumerate the Winedings font both as Winedings and
946 * Wingdings. However if a real Wingdings font is present the
947 * replacement does not take place.
950 static void LoadReplaceList(void)
953 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
958 struct list *family_elem_ptr, *face_elem_ptr;
959 WCHAR old_nameW[200];
961 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
962 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
964 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
965 &valuelen, &datalen, NULL, NULL);
967 valuelen++; /* returned value doesn't include room for '\0' */
968 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
969 data = HeapAlloc(GetProcessHeap(), 0, datalen);
973 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
974 &dlen) == ERROR_SUCCESS) {
975 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
976 /* "NewName"="Oldname" */
977 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)/sizeof(WCHAR)))
980 /* Find the old family and hence all of the font files
982 LIST_FOR_EACH(family_elem_ptr, &font_list) {
983 family = LIST_ENTRY(family_elem_ptr, Family, entry);
984 if(!strcmpiW(family->FamilyName, old_nameW)) {
985 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
986 face = LIST_ENTRY(face_elem_ptr, Face, entry);
987 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
988 debugstr_w(face->StyleName), value);
989 /* Now add a new entry with the new family name */
990 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
995 /* reset dlen and vlen */
999 HeapFree(GetProcessHeap(), 0, data);
1000 HeapFree(GetProcessHeap(), 0, value);
1005 /*************************************************************
1008 static BOOL init_system_links(void)
1010 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1011 'W','i','n','d','o','w','s',' ','N','T','\\',
1012 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1013 'S','y','s','t','e','m','L','i','n','k',0};
1016 DWORD type, max_val, max_data, val_len, data_len, index;
1017 WCHAR *value, *data;
1018 WCHAR *entry, *next;
1019 SYSTEM_LINKS *font_link, *system_font_link;
1020 CHILD_FONT *child_font;
1021 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1022 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1023 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1028 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1030 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1031 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1032 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1033 val_len = max_val + 1;
1034 data_len = max_data;
1036 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1038 TRACE("%s:\n", debugstr_w(value));
1040 memset(&fs, 0, sizeof(fs));
1041 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1042 font_link->font_name = strdupW(value);
1043 list_init(&font_link->links);
1044 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1047 CHILD_FONT *child_font;
1049 TRACE("\t%s\n", debugstr_w(entry));
1051 next = entry + strlenW(entry) + 1;
1053 face_name = strchrW(entry, ',');
1057 while(isspaceW(*face_name))
1060 face = find_face_from_filename(entry, face_name);
1063 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1067 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1068 child_font->file_name = strdupA(face->file);
1069 child_font->index = face->face_index;
1070 child_font->font = NULL;
1071 fs.fsCsb[0] |= face->fs.fsCsb[0];
1072 fs.fsCsb[1] |= face->fs.fsCsb[1];
1073 TRACE("Adding file %s index %d\n", child_font->file_name, child_font->index);
1074 list_add_tail(&font_link->links, &child_font->entry);
1076 family = find_family_from_name(font_link->font_name);
1079 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1081 memcpy(&face->fs_links, &fs, sizeof(fs));
1084 list_add_tail(&system_links, &font_link->entry);
1085 val_len = max_val + 1;
1086 data_len = max_data;
1089 HeapFree(GetProcessHeap(), 0, value);
1090 HeapFree(GetProcessHeap(), 0, data);
1094 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1097 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1098 system_font_link->font_name = strdupW(System);
1099 list_init(&system_font_link->links);
1101 face = find_face_from_filename(tahoma_ttf, Tahoma);
1104 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1105 child_font->file_name = strdupA(face->file);
1106 child_font->index = face->face_index;
1107 child_font->font = NULL;
1108 TRACE("Found Tahoma in %s index %d\n", child_font->file_name, child_font->index);
1109 list_add_tail(&system_font_link->links, &child_font->entry);
1111 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1113 if(!strcmpiW(font_link->font_name, Tahoma))
1115 CHILD_FONT *font_link_entry;
1116 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1118 CHILD_FONT *new_child;
1119 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1120 new_child->file_name = strdupA(font_link_entry->file_name);
1121 new_child->index = font_link_entry->index;
1122 new_child->font = NULL;
1123 list_add_tail(&system_font_link->links, &new_child->entry);
1128 list_add_tail(&system_links, &system_font_link->entry);
1132 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1135 struct dirent *dent;
1136 char path[MAX_PATH];
1138 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1140 dir = opendir(dirname);
1142 WARN("Can't open directory %s\n", debugstr_a(dirname));
1145 while((dent = readdir(dir)) != NULL) {
1146 struct stat statbuf;
1148 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1151 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1153 sprintf(path, "%s/%s", dirname, dent->d_name);
1155 if(stat(path, &statbuf) == -1)
1157 WARN("Can't stat %s\n", debugstr_a(path));
1160 if(S_ISDIR(statbuf.st_mode))
1161 ReadFontDir(path, external_fonts);
1163 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1169 static void load_fontconfig_fonts(void)
1171 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1172 void *fc_handle = NULL;
1178 const char *file, *ext;
1180 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1182 TRACE("Wine cannot find the fontconfig library (%s).\n",
1183 SONAME_LIBFONTCONFIG);
1186 #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;}
1187 LOAD_FUNCPTR(FcConfigGetCurrent);
1188 LOAD_FUNCPTR(FcFontList);
1189 LOAD_FUNCPTR(FcFontSetDestroy);
1190 LOAD_FUNCPTR(FcInit);
1191 LOAD_FUNCPTR(FcObjectSetAdd);
1192 LOAD_FUNCPTR(FcObjectSetCreate);
1193 LOAD_FUNCPTR(FcObjectSetDestroy);
1194 LOAD_FUNCPTR(FcPatternCreate);
1195 LOAD_FUNCPTR(FcPatternDestroy);
1196 LOAD_FUNCPTR(FcPatternGetString);
1199 if(!pFcInit()) return;
1201 config = pFcConfigGetCurrent();
1202 pat = pFcPatternCreate();
1203 os = pFcObjectSetCreate();
1204 pFcObjectSetAdd(os, FC_FILE);
1205 fontset = pFcFontList(config, pat, os);
1206 if(!fontset) return;
1207 for(i = 0; i < fontset->nfont; i++) {
1208 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1210 TRACE("fontconfig: %s\n", file);
1212 /* We're just interested in OT/TT fonts for now, so this hack just
1213 picks up the standard extensions to save time loading every other
1215 len = strlen( file );
1216 if(len < 4) continue;
1217 ext = &file[ len - 3 ];
1218 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
1219 AddFontFileToList(file, NULL, ADDFONT_EXTERNAL_FONT);
1221 pFcFontSetDestroy(fontset);
1222 pFcObjectSetDestroy(os);
1223 pFcPatternDestroy(pat);
1229 static BOOL load_font_from_data_dir(LPCWSTR file)
1232 const char *data_dir = wine_get_data_dir();
1234 if (!data_dir) data_dir = wine_get_build_dir();
1241 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1243 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1245 strcpy(unix_name, data_dir);
1246 strcat(unix_name, "/fonts/");
1248 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1250 ret = AddFontFileToList(unix_name, NULL, ADDFONT_FORCE_BITMAP);
1251 HeapFree(GetProcessHeap(), 0, unix_name);
1256 static void load_system_fonts(void)
1259 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1260 const WCHAR * const *value;
1262 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1265 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1266 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1267 strcatW(windowsdir, fontsW);
1268 for(value = SystemFontValues; *value; value++) {
1269 dlen = sizeof(data);
1270 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1274 sprintfW(pathW, fmtW, windowsdir, data);
1275 if((unixname = wine_get_unix_file_name(pathW))) {
1276 added = AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1277 HeapFree(GetProcessHeap(), 0, unixname);
1280 load_font_from_data_dir(data);
1287 /*************************************************************
1289 * This adds registry entries for any externally loaded fonts
1290 * (fonts from fontconfig or FontDirs). It also deletes entries
1291 * of no longer existing fonts.
1294 static void update_reg_entries(void)
1296 HKEY winkey = 0, externalkey = 0;
1299 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1302 struct list *family_elem_ptr, *face_elem_ptr;
1304 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1305 static const WCHAR spaceW[] = {' ', '\0'};
1308 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1309 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1310 ERR("Can't create Windows font reg key\n");
1313 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1314 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1315 ERR("Can't create external font reg key\n");
1319 /* Delete all external fonts added last time */
1321 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1322 &valuelen, &datalen, NULL, NULL);
1323 valuelen++; /* returned value doesn't include room for '\0' */
1324 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1325 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1327 dlen = datalen * sizeof(WCHAR);
1330 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1331 &dlen) == ERROR_SUCCESS) {
1333 RegDeleteValueW(winkey, valueW);
1334 /* reset dlen and vlen */
1338 HeapFree(GetProcessHeap(), 0, data);
1339 HeapFree(GetProcessHeap(), 0, valueW);
1341 /* Delete the old external fonts key */
1342 RegCloseKey(externalkey);
1344 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1346 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1347 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1348 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1349 ERR("Can't create external font reg key\n");
1353 /* enumerate the fonts and add external ones to the two keys */
1355 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1356 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1357 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1358 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1359 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1360 if(!face->external) continue;
1362 if(strcmpiW(face->StyleName, RegularW))
1363 len = len_fam + strlenW(face->StyleName) + 1;
1364 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1365 strcpyW(valueW, family->FamilyName);
1366 if(len != len_fam) {
1367 strcatW(valueW, spaceW);
1368 strcatW(valueW, face->StyleName);
1370 strcatW(valueW, TrueType);
1371 if((path = strrchr(face->file, '/')) == NULL)
1375 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1377 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1378 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1379 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1380 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1382 HeapFree(GetProcessHeap(), 0, file);
1383 HeapFree(GetProcessHeap(), 0, valueW);
1388 RegCloseKey(externalkey);
1390 RegCloseKey(winkey);
1395 /*************************************************************
1396 * WineEngAddFontResourceEx
1399 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1401 if (ft_handle) /* do it only if we have freetype up and running */
1406 FIXME("Ignoring flags %lx\n", flags);
1408 if((unixname = wine_get_unix_file_name(file)))
1410 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1411 HeapFree(GetProcessHeap(), 0, unixname);
1417 /*************************************************************
1418 * WineEngRemoveFontResourceEx
1421 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1427 static const struct nls_update_font_list
1429 UINT ansi_cp, oem_cp;
1430 const char *oem, *fixed, *system;
1431 const char *courier, *serif, *small, *sserif;
1432 } nls_update_font_list[] =
1434 /* Latin 1 (United States) */
1435 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1436 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1438 /* Latin 1 (Multilingual) */
1439 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1440 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1442 /* Eastern Europe */
1443 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1444 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1447 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1448 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1451 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1452 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1455 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1456 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1459 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1460 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1463 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1464 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1467 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1468 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1471 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1472 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1475 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1476 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1479 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1480 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1482 /* Chinese Simplified */
1483 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1484 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1487 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1488 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1490 /* Chinese Traditional */
1491 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1492 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1496 inline static HKEY create_fonts_NT_registry_key(void)
1500 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1501 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1505 inline static HKEY create_fonts_9x_registry_key(void)
1509 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1510 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1514 inline static HKEY create_config_fonts_registry_key(void)
1518 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1519 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1523 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1525 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1526 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1527 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1528 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1531 static void update_font_info(void)
1536 UINT i, ansi_cp = 0, oem_cp = 0;
1537 LCID lcid = GetUserDefaultLCID();
1539 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) != ERROR_SUCCESS)
1543 if (RegQueryValueExA(hkey, "Locale", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1545 if (strtoul(buf, NULL, 16 ) == lcid) /* already set correctly */
1550 TRACE("updating registry, locale changed %s -> %08lx\n", debugstr_a(buf), lcid);
1552 else TRACE("updating registry, locale changed none -> %08lx\n", lcid);
1554 sprintf(buf, "%08lx", lcid);
1555 RegSetValueExA(hkey, "Locale", 0, REG_SZ, (const BYTE *)buf, strlen(buf)+1);
1558 GetLocaleInfoW(lcid, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1559 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1560 GetLocaleInfoW(lcid, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1561 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1563 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1565 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1566 nls_update_font_list[i].oem_cp == oem_cp)
1570 hkey = create_config_fonts_registry_key();
1571 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1572 RegSetValueExA(hkey, "FIXED.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1573 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1576 hkey = create_fonts_NT_registry_key();
1577 add_font_list(hkey, &nls_update_font_list[i]);
1580 hkey = create_fonts_9x_registry_key();
1581 add_font_list(hkey, &nls_update_font_list[i]);
1587 FIXME("there is no font defaults for lcid %04lx/ansi_cp %u", lcid, ansi_cp);
1590 /*************************************************************
1593 * Initialize FreeType library and create a list of available faces
1595 BOOL WineEngInit(void)
1597 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1598 static const WCHAR pathW[] = {'P','a','t','h',0};
1600 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1602 WCHAR windowsdir[MAX_PATH];
1605 const char *data_dir;
1609 /* update locale dependent font info in registry */
1612 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1615 "Wine cannot find the FreeType font library. To enable Wine to\n"
1616 "use TrueType fonts please install a version of FreeType greater than\n"
1617 "or equal to 2.0.5.\n"
1618 "http://www.freetype.org\n");
1622 #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;}
1624 LOAD_FUNCPTR(FT_Vector_Unit)
1625 LOAD_FUNCPTR(FT_Done_Face)
1626 LOAD_FUNCPTR(FT_Get_Char_Index)
1627 LOAD_FUNCPTR(FT_Get_Module)
1628 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1629 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1630 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1631 LOAD_FUNCPTR(FT_Init_FreeType)
1632 LOAD_FUNCPTR(FT_Load_Glyph)
1633 LOAD_FUNCPTR(FT_Matrix_Multiply)
1634 LOAD_FUNCPTR(FT_MulFix)
1635 LOAD_FUNCPTR(FT_New_Face)
1636 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1637 LOAD_FUNCPTR(FT_Outline_Transform)
1638 LOAD_FUNCPTR(FT_Outline_Translate)
1639 LOAD_FUNCPTR(FT_Select_Charmap)
1640 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1641 LOAD_FUNCPTR(FT_Vector_Transform)
1644 /* Don't warn if this one is missing */
1645 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1646 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1647 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1648 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
1649 #ifdef HAVE_FREETYPE_FTWINFNT_H
1650 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1652 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1653 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1654 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1655 <= 2.0.3 has FT_Sqrt64 */
1659 if(pFT_Init_FreeType(&library) != 0) {
1660 ERR("Can't init FreeType library\n");
1661 wine_dlclose(ft_handle, NULL, 0);
1665 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1666 if (pFT_Library_Version)
1668 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1670 if (FT_Version.major<=0)
1676 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1677 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1678 ((FT_Version.minor << 8) & 0x00ff00) |
1679 ((FT_Version.patch ) & 0x0000ff);
1681 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1682 ERR("Failed to create font mutex\n");
1685 WaitForSingleObject(font_mutex, INFINITE);
1687 /* load the system bitmap fonts */
1688 load_system_fonts();
1690 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1691 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1692 strcatW(windowsdir, fontsW);
1693 if((unixname = wine_get_unix_file_name(windowsdir)))
1695 ReadFontDir(unixname, FALSE);
1696 HeapFree(GetProcessHeap(), 0, unixname);
1699 /* load the system truetype fonts */
1700 data_dir = wine_get_data_dir();
1701 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
1702 strcpy(unixname, data_dir);
1703 strcat(unixname, "/fonts/");
1704 ReadFontDir(unixname, FALSE);
1705 HeapFree(GetProcessHeap(), 0, unixname);
1708 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1709 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1710 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1712 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1713 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1714 &hkey) == ERROR_SUCCESS) {
1716 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1717 &valuelen, &datalen, NULL, NULL);
1719 valuelen++; /* returned value doesn't include room for '\0' */
1720 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1721 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1724 dlen = datalen * sizeof(WCHAR);
1726 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1727 &dlen) == ERROR_SUCCESS) {
1728 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1730 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1732 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1733 HeapFree(GetProcessHeap(), 0, unixname);
1736 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1738 WCHAR pathW[MAX_PATH];
1739 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1742 sprintfW(pathW, fmtW, windowsdir, data);
1743 if((unixname = wine_get_unix_file_name(pathW)))
1745 added = AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1746 HeapFree(GetProcessHeap(), 0, unixname);
1749 load_font_from_data_dir(data);
1751 /* reset dlen and vlen */
1756 HeapFree(GetProcessHeap(), 0, data);
1757 HeapFree(GetProcessHeap(), 0, valueW);
1761 load_fontconfig_fonts();
1763 /* then look in any directories that we've specified in the config file */
1764 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
1765 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
1771 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
1773 len += sizeof(WCHAR);
1774 valueW = HeapAlloc( GetProcessHeap(), 0, len );
1775 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
1777 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
1778 valueA = HeapAlloc( GetProcessHeap(), 0, len );
1779 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
1780 TRACE( "got font path %s\n", debugstr_a(valueA) );
1784 LPSTR next = strchr( ptr, ':' );
1785 if (next) *next++ = 0;
1786 ReadFontDir( ptr, TRUE );
1789 HeapFree( GetProcessHeap(), 0, valueA );
1791 HeapFree( GetProcessHeap(), 0, valueW );
1800 update_reg_entries();
1802 init_system_links();
1804 ReleaseMutex(font_mutex);
1808 "Wine cannot find certain functions that it needs inside the FreeType\n"
1809 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1810 "FreeType to at least version 2.0.5.\n"
1811 "http://www.freetype.org\n");
1812 wine_dlclose(ft_handle, NULL, 0);
1818 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1821 TT_HoriHeader *pHori;
1825 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1826 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1828 if(height == 0) height = 16;
1830 /* Calc. height of EM square:
1832 * For +ve lfHeight we have
1833 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1834 * Re-arranging gives:
1835 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1837 * For -ve lfHeight we have
1839 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1840 * with il = winAscent + winDescent - units_per_em]
1845 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1846 ppem = ft_face->units_per_EM * height /
1847 (pHori->Ascender - pHori->Descender);
1849 ppem = ft_face->units_per_EM * height /
1850 (pOS2->usWinAscent + pOS2->usWinDescent);
1858 static LONG load_VDMX(GdiFont, LONG);
1860 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1865 TRACE("%s, %ld, %ld x %ld\n", debugstr_a(file), face_index, width, height);
1866 err = pFT_New_Face(library, file, face_index, &ft_face);
1868 ERR("FT_New_Face rets %d\n", err);
1872 /* set it here, as load_VDMX needs it */
1873 font->ft_face = ft_face;
1875 if(FT_IS_SCALABLE(ft_face)) {
1876 /* load the VDMX table if we have one */
1877 font->ppem = load_VDMX(font, height);
1879 font->ppem = calc_ppem_for_height(ft_face, height);
1881 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
1882 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, font->ppem, err);
1884 font->ppem = height;
1885 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1886 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1892 static int get_nearest_charset(Face *face, int *cp)
1894 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1895 a single face with the requested charset. The idea is to check if
1896 the selected font supports the current ANSI codepage, if it does
1897 return the corresponding charset, else return the first charset */
1900 int acp = GetACP(), i;
1904 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1905 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1906 return csi.ciCharset;
1908 for(i = 0; i < 32; i++) {
1910 if(face->fs.fsCsb[0] & fs0) {
1911 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
1913 return csi.ciCharset;
1916 FIXME("TCI failing on %lx\n", fs0);
1920 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1921 face->fs.fsCsb[0], face->file);
1923 return DEFAULT_CHARSET;
1926 static GdiFont alloc_font(void)
1928 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1929 ret->gmsize = INIT_GM_SIZE;
1930 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1931 ret->gmsize * sizeof(*ret->gm));
1933 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1934 list_init(&ret->hfontlist);
1935 list_init(&ret->child_fonts);
1939 static void free_font(GdiFont font)
1941 struct list *cursor, *cursor2;
1943 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
1945 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
1946 struct list *first_hfont;
1947 HFONTLIST *hfontlist;
1948 list_remove(cursor);
1951 first_hfont = list_head(&child->font->hfontlist);
1952 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
1953 DeleteObject(hfontlist->hfont);
1954 HeapFree(GetProcessHeap(), 0, hfontlist);
1955 free_font(child->font);
1957 HeapFree(GetProcessHeap(), 0, child->file_name);
1958 HeapFree(GetProcessHeap(), 0, child);
1961 if (font->ft_face) pFT_Done_Face(font->ft_face);
1962 HeapFree(GetProcessHeap(), 0, font->potm);
1963 HeapFree(GetProcessHeap(), 0, font->name);
1964 HeapFree(GetProcessHeap(), 0, font->gm);
1965 HeapFree(GetProcessHeap(), 0, font);
1969 /*************************************************************
1972 * load the vdmx entry for the specified height
1975 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1976 ( ( (FT_ULong)_x4 << 24 ) | \
1977 ( (FT_ULong)_x3 << 16 ) | \
1978 ( (FT_ULong)_x2 << 8 ) | \
1981 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1996 static LONG load_VDMX(GdiFont font, LONG height)
2000 BYTE devXRatio, devYRatio;
2001 USHORT numRecs, numRatios;
2002 DWORD result, offset = -1;
2006 /* For documentation on VDMX records, see
2007 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2010 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2012 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2015 /* FIXME: need the real device aspect ratio */
2019 numRecs = GET_BE_WORD(hdr[1]);
2020 numRatios = GET_BE_WORD(hdr[2]);
2022 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2023 for(i = 0; i < numRatios; i++) {
2026 offset = (3 * 2) + (i * sizeof(Ratios));
2027 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2030 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2032 if((ratio.xRatio == 0 &&
2033 ratio.yStartRatio == 0 &&
2034 ratio.yEndRatio == 0) ||
2035 (devXRatio == ratio.xRatio &&
2036 devYRatio >= ratio.yStartRatio &&
2037 devYRatio <= ratio.yEndRatio))
2039 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2040 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2041 offset = GET_BE_WORD(tmp);
2047 FIXME("No suitable ratio found\n");
2051 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2053 BYTE startsz, endsz;
2056 recs = GET_BE_WORD(group.recs);
2057 startsz = group.startsz;
2058 endsz = group.endsz;
2060 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2062 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2063 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2064 if(result == GDI_ERROR) {
2065 FIXME("Failed to retrieve vTable\n");
2070 for(i = 0; i < recs; i++) {
2071 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2072 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2073 ppem = GET_BE_WORD(vTable[i * 3]);
2075 if(yMax + -yMin == height) {
2078 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2081 if(yMax + -yMin > height) {
2084 goto end; /* failed */
2086 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2087 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2088 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2094 TRACE("ppem not found for height %ld\n", height);
2098 if(ppem < startsz || ppem > endsz)
2101 for(i = 0; i < recs; i++) {
2103 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2105 if(yPelHeight > ppem)
2108 if(yPelHeight == ppem) {
2109 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2110 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2111 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2117 HeapFree(GetProcessHeap(), 0, vTable);
2123 static BOOL fontcmp(GdiFont font, FONT_DESC *fd)
2125 if(font->font_desc.hash != fd->hash) return TRUE;
2126 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2127 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2128 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2129 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2132 static void calc_hash(FONT_DESC *pfd)
2134 DWORD hash = 0, *ptr, two_chars;
2138 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2140 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2142 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2144 pwc = (WCHAR *)&two_chars;
2146 *pwc = toupperW(*pwc);
2148 *pwc = toupperW(*pwc);
2152 hash ^= !pfd->can_use_bitmap;
2157 static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2162 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2164 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2165 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2166 fd.can_use_bitmap = can_use_bitmap;
2169 /* try the in-use list */
2170 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2171 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2172 if(!fontcmp(ret, &fd)) {
2173 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2174 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2175 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2176 if(hflist->hfont == hfont)
2179 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2180 hflist->hfont = hfont;
2181 list_add_head(&ret->hfontlist, &hflist->entry);
2186 /* then the unused list */
2187 font_elem_ptr = list_head(&unused_gdi_font_list);
2188 while(font_elem_ptr) {
2189 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2190 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2191 if(!fontcmp(ret, &fd)) {
2192 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2193 assert(list_empty(&ret->hfontlist));
2194 TRACE("Found %p in unused list\n", ret);
2195 list_remove(&ret->entry);
2196 list_add_head(&gdi_font_list, &ret->entry);
2197 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2198 hflist->hfont = hfont;
2199 list_add_head(&ret->hfontlist, &hflist->entry);
2207 /*************************************************************
2208 * create_child_font_list
2210 static BOOL create_child_font_list(GdiFont font)
2213 SYSTEM_LINKS *font_link;
2214 CHILD_FONT *font_link_entry, *new_child;
2216 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2218 if(!strcmpW(font_link->font_name, font->name))
2220 TRACE("found entry in system list\n");
2221 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2223 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2224 new_child->file_name = strdupA(font_link_entry->file_name);
2225 new_child->index = font_link_entry->index;
2226 new_child->font = NULL;
2227 list_add_tail(&font->child_fonts, &new_child->entry);
2228 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
2238 /*************************************************************
2239 * WineEngCreateFontInstance
2242 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2246 Family *family, *last_resort_family;
2247 struct list *family_elem_ptr, *face_elem_ptr;
2248 INT height, width = 0;
2249 signed int diff = 0, newdiff;
2250 BOOL bd, it, can_use_bitmap;
2255 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2257 struct list *first_hfont = list_head(&ret->hfontlist);
2258 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2259 if(hflist->hfont == hfont)
2263 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2264 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2266 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
2267 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2268 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2271 /* check the cache first */
2272 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2273 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2277 TRACE("not in cache\n");
2278 if(list_empty(&font_list)) /* No fonts installed */
2280 TRACE("No fonts installed\n");
2283 if(!have_installed_roman_font)
2285 TRACE("No roman font installed\n");
2291 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2292 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2293 ret->font_desc.can_use_bitmap = can_use_bitmap;
2294 calc_hash(&ret->font_desc);
2295 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2296 hflist->hfont = hfont;
2297 list_add_head(&ret->hfontlist, &hflist->entry);
2300 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2301 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2302 original value lfCharSet. Note this is a special case for
2303 Symbol and doesn't happen at least for "Wingdings*" */
2305 if(!strcmpiW(lf.lfFaceName, SymbolW))
2306 lf.lfCharSet = SYMBOL_CHARSET;
2308 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2309 switch(lf.lfCharSet) {
2310 case DEFAULT_CHARSET:
2311 csi.fs.fsCsb[0] = 0;
2314 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2315 csi.fs.fsCsb[0] = 0;
2321 if(lf.lfFaceName[0] != '\0') {
2323 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2326 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2327 debugstr_w(psub->to.name));
2328 strcpyW(lf.lfFaceName, psub->to.name);
2331 /* We want a match on name and charset or just name if
2332 charset was DEFAULT_CHARSET. If the latter then
2333 we fixup the returned charset later in get_nearest_charset
2334 where we'll either use the charset of the current ansi codepage
2335 or if that's unavailable the first charset that the font supports.
2337 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2338 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2339 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2340 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2341 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2342 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2343 if(face->scalable || can_use_bitmap)
2350 /* If requested charset was DEFAULT_CHARSET then try using charset
2351 corresponding to the current ansi codepage */
2352 if(!csi.fs.fsCsb[0]) {
2354 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
2355 FIXME("TCI failed on codepage %d\n", acp);
2356 csi.fs.fsCsb[0] = 0;
2358 lf.lfCharSet = csi.ciCharset;
2361 /* Face families are in the top 4 bits of lfPitchAndFamily,
2362 so mask with 0xF0 before testing */
2364 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2365 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2366 strcpyW(lf.lfFaceName, defFixed);
2367 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2368 strcpyW(lf.lfFaceName, defSerif);
2369 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2370 strcpyW(lf.lfFaceName, defSans);
2372 strcpyW(lf.lfFaceName, defSans);
2373 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2374 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2375 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2376 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2377 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2378 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2379 if(face->scalable || can_use_bitmap)
2385 last_resort_family = NULL;
2386 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2387 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2388 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2389 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2390 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2393 if(can_use_bitmap && !last_resort_family)
2394 last_resort_family = family;
2399 if(last_resort_family) {
2400 family = last_resort_family;
2401 csi.fs.fsCsb[0] = 0;
2405 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2406 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2407 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2408 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2409 if(face->scalable) {
2410 csi.fs.fsCsb[0] = 0;
2411 FIXME("just using first face for now\n");
2414 if(can_use_bitmap && !last_resort_family)
2415 last_resort_family = family;
2418 if(!last_resort_family) {
2419 FIXME("can't find a single appropriate font - bailing\n");
2424 WARN("could only find a bitmap font - this will probably look awful!\n");
2425 family = last_resort_family;
2426 csi.fs.fsCsb[0] = 0;
2429 it = lf.lfItalic ? 1 : 0;
2430 bd = lf.lfWeight > 550 ? 1 : 0;
2432 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2433 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2436 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2437 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2438 if(!(face->Italic ^ it) && !(face->Bold ^ bd) &&
2439 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])) {
2443 newdiff = height - (signed int)(face->size.height);
2445 newdiff = -height - ((signed int)(face->size.height) - face->size.internal_leading);
2446 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
2447 (diff < 0 && newdiff > diff)) {
2448 TRACE("%d is better for %d diff was %d\n", face->size.height, height, diff);
2461 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2462 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2463 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]) {
2467 newdiff = height - (signed int)(face->size.height);
2469 newdiff = -height - ((signed int)(face->size.height) - face->size.internal_leading);
2470 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
2471 (diff < 0 && newdiff > diff)) {
2472 TRACE("%d is better for %d diff was %d\n", face->size.height, height, diff);
2483 if(it && !face->Italic) ret->fake_italic = TRUE;
2484 if(bd && !face->Bold) ret->fake_bold = TRUE;
2487 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2489 if(csi.fs.fsCsb[0]) {
2490 ret->charset = lf.lfCharSet;
2491 ret->codepage = csi.ciACP;
2494 ret->charset = get_nearest_charset(face, &ret->codepage);
2496 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2497 debugstr_w(face->StyleName), face->file, face->face_index);
2499 if(!face->scalable) {
2500 width = face->size.x_ppem >> 6;
2501 height = face->size.y_ppem >> 6;
2503 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2511 if (ret->charset == SYMBOL_CHARSET &&
2512 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2515 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2519 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2522 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2523 ret->name = strdupW(family->FamilyName);
2524 ret->underline = lf.lfUnderline ? 0xff : 0;
2525 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2526 create_child_font_list(ret);
2528 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2530 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
2531 list_add_head(&gdi_font_list, &ret->entry);
2535 static void dump_gdi_font_list(void)
2538 struct list *elem_ptr;
2540 TRACE("---------- gdiFont Cache ----------\n");
2541 LIST_FOR_EACH(elem_ptr, &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);
2547 TRACE("---------- Unused gdiFont Cache ----------\n");
2548 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2549 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2550 TRACE("gdiFont=%p %s %ld\n",
2551 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2555 /*************************************************************
2556 * WineEngDestroyFontInstance
2558 * free the gdiFont associated with this handle
2561 BOOL WineEngDestroyFontInstance(HFONT handle)
2566 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2569 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
2571 struct list *first_hfont = list_head(&gdiFont->hfontlist);
2572 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2573 if(hflist->hfont == handle)
2575 TRACE("removing child font %p from child list\n", gdiFont);
2576 list_remove(&gdiFont->entry);
2581 TRACE("destroying hfont=%p\n", handle);
2583 dump_gdi_font_list();
2585 font_elem_ptr = list_head(&gdi_font_list);
2586 while(font_elem_ptr) {
2587 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2588 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
2590 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
2591 while(hfontlist_elem_ptr) {
2592 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2593 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
2594 if(hflist->hfont == handle) {
2595 list_remove(&hflist->entry);
2596 HeapFree(GetProcessHeap(), 0, hflist);
2600 if(list_empty(&gdiFont->hfontlist)) {
2601 TRACE("Moving to Unused list\n");
2602 list_remove(&gdiFont->entry);
2603 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
2608 font_elem_ptr = list_head(&unused_gdi_font_list);
2609 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
2610 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2611 while(font_elem_ptr) {
2612 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2613 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2614 TRACE("freeing %p\n", gdiFont);
2615 list_remove(&gdiFont->entry);
2621 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2622 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
2624 OUTLINETEXTMETRICW *potm = NULL;
2626 TEXTMETRICW tm, *ptm;
2627 GdiFont font = alloc_font();
2630 if(face->scalable) {
2634 height = face->size.y_ppem >> 6;
2635 width = face->size.x_ppem >> 6;
2638 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
2644 font->name = strdupW(face->family->FamilyName);
2646 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
2648 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
2650 potm = HeapAlloc(GetProcessHeap(), 0, size);
2651 WineEngGetOutlineTextMetrics(font, size, potm);
2652 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
2654 WineEngGetTextMetrics(font, &tm);
2658 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
2659 pntm->ntmTm.tmAscent = ptm->tmAscent;
2660 pntm->ntmTm.tmDescent = ptm->tmDescent;
2661 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
2662 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
2663 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
2664 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
2665 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
2666 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
2667 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
2668 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
2669 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
2670 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
2671 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
2672 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
2673 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
2674 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
2675 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
2676 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
2677 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
2678 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
2679 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2680 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2681 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
2683 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
2684 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
2685 *ptype |= RASTER_FONTTYPE;
2687 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2688 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2689 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2691 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
2692 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
2693 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2696 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
2698 lstrcpynW(pelf->elfLogFont.lfFaceName,
2699 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
2701 lstrcpynW(pelf->elfFullName,
2702 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
2704 lstrcpynW(pelf->elfStyle,
2705 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2708 HeapFree(GetProcessHeap(), 0, potm);
2710 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
2712 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2713 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2714 pelf->elfStyle[0] = '\0';
2717 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2722 /*************************************************************
2726 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2730 struct list *family_elem_ptr, *face_elem_ptr;
2732 NEWTEXTMETRICEXW ntm;
2733 DWORD type, ret = 1;
2739 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2741 if(plf->lfFaceName[0]) {
2743 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
2746 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2747 debugstr_w(psub->to.name));
2748 memcpy(&lf, plf, sizeof(lf));
2749 strcpyW(lf.lfFaceName, psub->to.name);
2753 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2754 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2755 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2756 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2757 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2758 GetEnumStructs(face, &elf, &ntm, &type);
2759 for(i = 0; i < 32; i++) {
2760 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2761 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2762 strcpyW(elf.elfScript, OEM_DOSW);
2763 i = 32; /* break out of loop */
2764 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2767 fs.fsCsb[0] = 1L << i;
2769 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2771 csi.ciCharset = DEFAULT_CHARSET;
2772 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2773 if(csi.ciCharset != DEFAULT_CHARSET) {
2774 elf.elfLogFont.lfCharSet =
2775 ntm.ntmTm.tmCharSet = csi.ciCharset;
2777 strcpyW(elf.elfScript, ElfScriptsW[i]);
2779 FIXME("Unknown elfscript for bit %d\n", i);
2782 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2783 debugstr_w(elf.elfLogFont.lfFaceName),
2784 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2785 csi.ciCharset, type, debugstr_w(elf.elfScript),
2786 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2787 ntm.ntmTm.ntmFlags);
2788 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2795 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2796 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2797 face_elem_ptr = list_head(&family->faces);
2798 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2799 GetEnumStructs(face, &elf, &ntm, &type);
2800 for(i = 0; i < 32; i++) {
2801 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2802 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2803 strcpyW(elf.elfScript, OEM_DOSW);
2804 i = 32; /* break out of loop */
2805 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2808 fs.fsCsb[0] = 1L << i;
2810 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2812 csi.ciCharset = DEFAULT_CHARSET;
2813 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2814 if(csi.ciCharset != DEFAULT_CHARSET) {
2815 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2818 strcpyW(elf.elfScript, ElfScriptsW[i]);
2820 FIXME("Unknown elfscript for bit %d\n", i);
2823 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2824 debugstr_w(elf.elfLogFont.lfFaceName),
2825 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2826 csi.ciCharset, type, debugstr_w(elf.elfScript),
2827 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2828 ntm.ntmTm.ntmFlags);
2829 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2838 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2840 pt->x.value = vec->x >> 6;
2841 pt->x.fract = (vec->x & 0x3f) << 10;
2842 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2843 pt->y.value = vec->y >> 6;
2844 pt->y.fract = (vec->y & 0x3f) << 10;
2845 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2849 /***************************************************
2850 * According to the MSDN documentation on WideCharToMultiByte,
2851 * certain codepages cannot set the default_used parameter.
2852 * This returns TRUE if the codepage can set that parameter, false else
2853 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
2855 static BOOL codepage_sets_default_used(UINT codepage)
2868 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2870 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
2871 WCHAR wc = (WCHAR)glyph;
2873 BOOL *default_used_pointer;
2876 default_used_pointer = NULL;
2877 default_used = FALSE;
2878 if (codepage_sets_default_used(font->codepage))
2879 default_used_pointer = &default_used;
2880 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
2883 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
2884 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
2888 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2889 glyph = glyph + 0xf000;
2890 return pFT_Get_Char_Index(font->ft_face, glyph);
2893 /*************************************************************
2894 * WineEngGetGlyphIndices
2896 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2898 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2899 LPWORD pgi, DWORD flags)
2903 for(i = 0; i < count; i++)
2904 pgi[i] = get_glyph_index(font, lpstr[i]);
2909 /*************************************************************
2910 * WineEngGetGlyphOutline
2912 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2913 * except that the first parameter is the HWINEENGFONT of the font in
2914 * question rather than an HDC.
2917 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2918 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2921 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2922 FT_Face ft_face = font->ft_face;
2923 FT_UInt glyph_index;
2924 DWORD width, height, pitch, needed = 0;
2925 FT_Bitmap ft_bitmap;
2927 INT left, right, top = 0, bottom = 0;
2929 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2930 float widthRatio = 1.0;
2931 FT_Matrix transMat = identityMat;
2932 BOOL needsTransform = FALSE;
2935 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2936 buflen, buf, lpmat);
2938 if(format & GGO_GLYPH_INDEX) {
2939 glyph_index = glyph;
2940 format &= ~GGO_GLYPH_INDEX;
2942 glyph_index = get_glyph_index(font, glyph);
2944 if(glyph_index >= font->gmsize) {
2945 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2946 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2947 font->gmsize * sizeof(*font->gm));
2949 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2950 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2951 return 1; /* FIXME */
2955 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2956 load_flags |= FT_LOAD_NO_BITMAP;
2958 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2961 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2965 /* Scaling factor */
2966 if (font->aveWidth && font->potm) {
2967 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2970 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2971 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2973 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2974 font->gm[glyph_index].lsb = left >> 6;
2975 font->gm[glyph_index].bbx = (right - left) >> 6;
2977 /* Scaling transform */
2978 if(font->aveWidth) {
2980 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2983 scaleMat.yy = (1 << 16);
2985 pFT_Matrix_Multiply(&scaleMat, &transMat);
2986 needsTransform = TRUE;
2989 /* Slant transform */
2990 if (font->fake_italic) {
2993 slantMat.xx = (1 << 16);
2994 slantMat.xy = ((1 << 16) >> 2);
2996 slantMat.yy = (1 << 16);
2997 pFT_Matrix_Multiply(&slantMat, &transMat);
2998 needsTransform = TRUE;
3001 /* Rotation transform */
3002 if(font->orientation) {
3003 FT_Matrix rotationMat;
3005 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3006 pFT_Vector_Unit(&vecAngle, angle);
3007 rotationMat.xx = vecAngle.x;
3008 rotationMat.xy = -vecAngle.y;
3009 rotationMat.yx = -rotationMat.xy;
3010 rotationMat.yy = rotationMat.xx;
3012 pFT_Matrix_Multiply(&rotationMat, &transMat);
3013 needsTransform = TRUE;
3016 /* Extra transformation specified by caller */
3019 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3020 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3021 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3022 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3023 pFT_Matrix_Multiply(&extraMat, &transMat);
3024 needsTransform = TRUE;
3027 if(!needsTransform) {
3028 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3029 bottom = (ft_face->glyph->metrics.horiBearingY -
3030 ft_face->glyph->metrics.height) & -64;
3031 lpgm->gmCellIncX = font->gm[glyph_index].adv;
3032 lpgm->gmCellIncY = 0;
3036 for(xc = 0; xc < 2; xc++) {
3037 for(yc = 0; yc < 2; yc++) {
3038 vec.x = (ft_face->glyph->metrics.horiBearingX +
3039 xc * ft_face->glyph->metrics.width);
3040 vec.y = ft_face->glyph->metrics.horiBearingY -
3041 yc * ft_face->glyph->metrics.height;
3042 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3043 pFT_Vector_Transform(&vec, &transMat);
3044 if(xc == 0 && yc == 0) {
3045 left = right = vec.x;
3046 top = bottom = vec.y;
3048 if(vec.x < left) left = vec.x;
3049 else if(vec.x > right) right = vec.x;
3050 if(vec.y < bottom) bottom = vec.y;
3051 else if(vec.y > top) top = vec.y;
3056 right = (right + 63) & -64;
3057 bottom = bottom & -64;
3058 top = (top + 63) & -64;
3060 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3061 vec.x = ft_face->glyph->metrics.horiAdvance;
3063 pFT_Vector_Transform(&vec, &transMat);
3064 lpgm->gmCellIncX = (vec.x+63) >> 6;
3065 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3067 lpgm->gmBlackBoxX = (right - left) >> 6;
3068 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3069 lpgm->gmptGlyphOrigin.x = left >> 6;
3070 lpgm->gmptGlyphOrigin.y = top >> 6;
3072 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
3073 font->gm[glyph_index].init = TRUE;
3075 if(format == GGO_METRICS)
3076 return 1; /* FIXME */
3078 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
3079 TRACE("loaded a bitmap\n");
3085 width = lpgm->gmBlackBoxX;
3086 height = lpgm->gmBlackBoxY;
3087 pitch = ((width + 31) >> 5) << 2;
3088 needed = pitch * height;
3090 if(!buf || !buflen) break;
3092 switch(ft_face->glyph->format) {
3093 case ft_glyph_format_bitmap:
3095 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3096 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3097 INT h = ft_face->glyph->bitmap.rows;
3099 memcpy(dst, src, w);
3100 src += ft_face->glyph->bitmap.pitch;
3106 case ft_glyph_format_outline:
3107 ft_bitmap.width = width;
3108 ft_bitmap.rows = height;
3109 ft_bitmap.pitch = pitch;
3110 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3111 ft_bitmap.buffer = buf;
3113 if(needsTransform) {
3114 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3117 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3119 /* Note: FreeType will only set 'black' bits for us. */
3120 memset(buf, 0, needed);
3121 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3125 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3130 case GGO_GRAY2_BITMAP:
3131 case GGO_GRAY4_BITMAP:
3132 case GGO_GRAY8_BITMAP:
3133 case WINE_GGO_GRAY16_BITMAP:
3135 unsigned int mult, row, col;
3138 width = lpgm->gmBlackBoxX;
3139 height = lpgm->gmBlackBoxY;
3140 pitch = (width + 3) / 4 * 4;
3141 needed = pitch * height;
3143 if(!buf || !buflen) break;
3144 ft_bitmap.width = width;
3145 ft_bitmap.rows = height;
3146 ft_bitmap.pitch = pitch;
3147 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3148 ft_bitmap.buffer = buf;
3150 if(needsTransform) {
3151 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3154 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3156 memset(ft_bitmap.buffer, 0, buflen);
3158 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3160 if(format == GGO_GRAY2_BITMAP)
3162 else if(format == GGO_GRAY4_BITMAP)
3164 else if(format == GGO_GRAY8_BITMAP)
3166 else if(format == WINE_GGO_GRAY16_BITMAP)
3174 for(row = 0; row < height; row++) {
3176 for(col = 0; col < width; col++, ptr++) {
3177 *ptr = (((int)*ptr) * mult + 128) / 256;
3186 int contour, point = 0, first_pt;
3187 FT_Outline *outline = &ft_face->glyph->outline;
3188 TTPOLYGONHEADER *pph;
3190 DWORD pph_start, cpfx, type;
3192 if(buflen == 0) buf = NULL;
3194 if (needsTransform && buf) {
3195 pFT_Outline_Transform(outline, &transMat);
3198 for(contour = 0; contour < outline->n_contours; contour++) {
3200 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3203 pph->dwType = TT_POLYGON_TYPE;
3204 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3206 needed += sizeof(*pph);
3208 while(point <= outline->contours[contour]) {
3209 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3210 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3211 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3215 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3218 } while(point <= outline->contours[contour] &&
3219 (outline->tags[point] & FT_Curve_Tag_On) ==
3220 (outline->tags[point-1] & FT_Curve_Tag_On));
3221 /* At the end of a contour Windows adds the start point, but
3223 if(point > outline->contours[contour] &&
3224 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3226 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3228 } else if(point <= outline->contours[contour] &&
3229 outline->tags[point] & FT_Curve_Tag_On) {
3230 /* add closing pt for bezier */
3232 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3240 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3243 pph->cb = needed - pph_start;
3249 /* Convert the quadratic Beziers to cubic Beziers.
3250 The parametric eqn for a cubic Bezier is, from PLRM:
3251 r(t) = at^3 + bt^2 + ct + r0
3252 with the control points:
3257 A quadratic Beizer has the form:
3258 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3260 So equating powers of t leads to:
3261 r1 = 2/3 p1 + 1/3 p0
3262 r2 = 2/3 p1 + 1/3 p2
3263 and of course r0 = p0, r3 = p2
3266 int contour, point = 0, first_pt;
3267 FT_Outline *outline = &ft_face->glyph->outline;
3268 TTPOLYGONHEADER *pph;
3270 DWORD pph_start, cpfx, type;
3271 FT_Vector cubic_control[4];
3272 if(buflen == 0) buf = NULL;
3274 if (needsTransform && buf) {
3275 pFT_Outline_Transform(outline, &transMat);
3278 for(contour = 0; contour < outline->n_contours; contour++) {
3280 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3283 pph->dwType = TT_POLYGON_TYPE;
3284 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3286 needed += sizeof(*pph);
3288 while(point <= outline->contours[contour]) {
3289 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3290 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3291 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3294 if(type == TT_PRIM_LINE) {
3296 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3300 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3303 /* FIXME: Possible optimization in endpoint calculation
3304 if there are two consecutive curves */
3305 cubic_control[0] = outline->points[point-1];
3306 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3307 cubic_control[0].x += outline->points[point].x + 1;
3308 cubic_control[0].y += outline->points[point].y + 1;
3309 cubic_control[0].x >>= 1;
3310 cubic_control[0].y >>= 1;
3312 if(point+1 > outline->contours[contour])
3313 cubic_control[3] = outline->points[first_pt];
3315 cubic_control[3] = outline->points[point+1];
3316 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3317 cubic_control[3].x += outline->points[point].x + 1;
3318 cubic_control[3].y += outline->points[point].y + 1;
3319 cubic_control[3].x >>= 1;
3320 cubic_control[3].y >>= 1;
3323 /* r1 = 1/3 p0 + 2/3 p1
3324 r2 = 1/3 p2 + 2/3 p1 */
3325 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3326 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3327 cubic_control[2] = cubic_control[1];
3328 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3329 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3330 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3331 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3333 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3334 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3335 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3340 } while(point <= outline->contours[contour] &&
3341 (outline->tags[point] & FT_Curve_Tag_On) ==
3342 (outline->tags[point-1] & FT_Curve_Tag_On));
3343 /* At the end of a contour Windows adds the start point,
3344 but only for Beziers and we've already done that.
3346 if(point <= outline->contours[contour] &&
3347 outline->tags[point] & FT_Curve_Tag_On) {
3348 /* This is the closing pt of a bezier, but we've already
3349 added it, so just inc point and carry on */
3356 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3359 pph->cb = needed - pph_start;
3365 FIXME("Unsupported format %d\n", format);
3371 static BOOL get_bitmap_text_metrics(GdiFont font)
3373 FT_Face ft_face = font->ft_face;
3374 #ifdef HAVE_FREETYPE_FTWINFNT_H
3375 FT_WinFNT_HeaderRec winfnt_header;
3377 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3378 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3379 font->potm->otmSize = size;
3381 #define TM font->potm->otmTextMetrics
3382 #ifdef HAVE_FREETYPE_FTWINFNT_H
3383 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3385 TM.tmHeight = winfnt_header.pixel_height;
3386 TM.tmAscent = winfnt_header.ascent;
3387 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3388 TM.tmInternalLeading = winfnt_header.internal_leading;
3389 TM.tmExternalLeading = winfnt_header.external_leading;
3390 TM.tmAveCharWidth = winfnt_header.avg_width;
3391 TM.tmMaxCharWidth = winfnt_header.max_width;
3392 TM.tmWeight = winfnt_header.weight;
3394 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3395 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3396 TM.tmFirstChar = winfnt_header.first_char;
3397 TM.tmLastChar = winfnt_header.last_char;
3398 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3399 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3400 TM.tmItalic = winfnt_header.italic;
3401 TM.tmUnderlined = font->underline;
3402 TM.tmStruckOut = font->strikeout;
3403 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3404 TM.tmCharSet = winfnt_header.charset;
3409 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3410 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3411 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3412 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3413 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3414 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3415 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3416 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3418 TM.tmDigitizedAspectX = 96; /* FIXME */
3419 TM.tmDigitizedAspectY = 96; /* FIXME */
3421 TM.tmLastChar = 255;
3422 TM.tmDefaultChar = 32;
3423 TM.tmBreakChar = 32;
3424 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3425 TM.tmUnderlined = font->underline;
3426 TM.tmStruckOut = font->strikeout;
3427 /* NB inverted meaning of TMPF_FIXED_PITCH */
3428 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3429 TM.tmCharSet = font->charset;
3436 /*************************************************************
3437 * WineEngGetTextMetrics
3440 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3443 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3444 if(!get_bitmap_text_metrics(font))
3447 if(!font->potm) return FALSE;
3448 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3450 if (font->aveWidth) {
3451 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3457 /*************************************************************
3458 * WineEngGetOutlineTextMetrics
3461 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3462 OUTLINETEXTMETRICW *potm)
3464 FT_Face ft_face = font->ft_face;
3465 UINT needed, lenfam, lensty, ret;
3467 TT_HoriHeader *pHori;
3468 TT_Postscript *pPost;
3469 FT_Fixed x_scale, y_scale;
3470 WCHAR *family_nameW, *style_nameW;
3471 static const WCHAR spaceW[] = {' ', '\0'};
3473 INT ascent, descent;
3475 TRACE("font=%p\n", font);
3477 if(!FT_IS_SCALABLE(ft_face))
3481 if(cbSize >= font->potm->otmSize)
3482 memcpy(potm, font->potm, font->potm->otmSize);
3483 return font->potm->otmSize;
3487 needed = sizeof(*potm);
3489 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3490 family_nameW = strdupW(font->name);
3492 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3494 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3495 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3496 style_nameW, lensty/sizeof(WCHAR));
3498 /* These names should be read from the TT name table */
3500 /* length of otmpFamilyName */
3503 /* length of otmpFaceName */
3504 if(!strcasecmp(ft_face->style_name, "regular")) {
3505 needed += lenfam; /* just the family name */
3507 needed += lenfam + lensty; /* family + " " + style */
3510 /* length of otmpStyleName */
3513 /* length of otmpFullName */
3514 needed += lenfam + lensty;
3517 x_scale = ft_face->size->metrics.x_scale;
3518 y_scale = ft_face->size->metrics.y_scale;
3520 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3522 FIXME("Can't find OS/2 table - not TT font?\n");
3527 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3529 FIXME("Can't find HHEA table - not TT font?\n");
3534 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3536 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",
3537 pOS2->usWinAscent, pOS2->usWinDescent,
3538 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3539 ft_face->ascender, ft_face->descender, ft_face->height,
3540 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3541 ft_face->bbox.yMax, ft_face->bbox.yMin);
3543 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3544 font->potm->otmSize = needed;
3546 #define TM font->potm->otmTextMetrics
3548 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3549 ascent = pHori->Ascender;
3550 descent = -pHori->Descender;
3552 ascent = pOS2->usWinAscent;
3553 descent = pOS2->usWinDescent;
3557 TM.tmAscent = font->yMax;
3558 TM.tmDescent = -font->yMin;
3559 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3561 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
3562 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
3563 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
3564 - ft_face->units_per_EM, y_scale) + 32) >> 6;
3567 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3570 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3572 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
3573 ((ascent + descent) -
3574 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
3576 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
3577 if (TM.tmAveCharWidth == 0) {
3578 TM.tmAveCharWidth = 1;
3580 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
3581 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
3583 TM.tmDigitizedAspectX = 300;
3584 TM.tmDigitizedAspectY = 300;
3585 TM.tmFirstChar = pOS2->usFirstCharIndex;
3586 TM.tmLastChar = pOS2->usLastCharIndex;
3587 TM.tmDefaultChar = pOS2->usDefaultChar;
3588 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
3589 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3590 TM.tmUnderlined = font->underline;
3591 TM.tmStruckOut = font->strikeout;
3593 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3594 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3595 (pOS2->version == 0xFFFFU ||
3596 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3597 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3599 TM.tmPitchAndFamily = 0;
3601 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
3602 case PAN_FAMILY_SCRIPT:
3603 TM.tmPitchAndFamily |= FF_SCRIPT;
3605 case PAN_FAMILY_DECORATIVE:
3606 case PAN_FAMILY_PICTORIAL:
3607 TM.tmPitchAndFamily |= FF_DECORATIVE;
3609 case PAN_FAMILY_TEXT_DISPLAY:
3610 if(TM.tmPitchAndFamily == 0) /* fixed */
3611 TM.tmPitchAndFamily = FF_MODERN;
3613 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
3614 case PAN_SERIF_NORMAL_SANS:
3615 case PAN_SERIF_OBTUSE_SANS:
3616 case PAN_SERIF_PERP_SANS:
3617 TM.tmPitchAndFamily |= FF_SWISS;
3620 TM.tmPitchAndFamily |= FF_ROMAN;
3625 TM.tmPitchAndFamily |= FF_DONTCARE;
3628 if(FT_IS_SCALABLE(ft_face))
3629 TM.tmPitchAndFamily |= TMPF_VECTOR;
3630 if(FT_IS_SFNT(ft_face))
3631 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3633 TM.tmCharSet = font->charset;
3636 font->potm->otmFiller = 0;
3637 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3638 font->potm->otmfsSelection = pOS2->fsSelection;
3639 font->potm->otmfsType = pOS2->fsType;
3640 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
3641 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
3642 font->potm->otmItalicAngle = 0; /* POST table */
3643 font->potm->otmEMSquare = ft_face->units_per_EM;
3644 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
3645 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
3646 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
3647 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
3648 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
3649 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
3650 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
3651 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
3652 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
3653 font->potm->otmMacAscent = 0; /* where do these come from ? */
3654 font->potm->otmMacDescent = 0;
3655 font->potm->otmMacLineGap = 0;
3656 font->potm->otmusMinimumPPEM = 0; /* TT Header */
3657 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
3658 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
3659 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
3660 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
3661 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
3662 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
3663 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
3664 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
3665 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
3666 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
3668 font->potm->otmsUnderscoreSize = 0;
3669 font->potm->otmsUnderscorePosition = 0;
3671 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
3672 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
3675 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
3676 cp = (char*)font->potm + sizeof(*font->potm);
3677 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
3678 strcpyW((WCHAR*)cp, family_nameW);
3680 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
3681 strcpyW((WCHAR*)cp, style_nameW);
3683 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
3684 strcpyW((WCHAR*)cp, family_nameW);
3685 if(strcasecmp(ft_face->style_name, "regular")) {
3686 strcatW((WCHAR*)cp, spaceW);
3687 strcatW((WCHAR*)cp, style_nameW);
3688 cp += lenfam + lensty;
3691 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
3692 strcpyW((WCHAR*)cp, family_nameW);
3693 strcatW((WCHAR*)cp, spaceW);
3694 strcatW((WCHAR*)cp, style_nameW);
3697 if(potm && needed <= cbSize)
3698 memcpy(potm, font->potm, font->potm->otmSize);
3701 HeapFree(GetProcessHeap(), 0, style_nameW);
3702 HeapFree(GetProcessHeap(), 0, family_nameW);
3707 static BOOL load_child_font(GdiFont font, CHILD_FONT *child)
3709 HFONTLIST *hfontlist;
3710 child->font = alloc_font();
3711 child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem);
3712 if(!child->font->ft_face)
3714 free_font(child->font);
3719 child->font->orientation = font->orientation;
3720 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
3721 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
3722 list_add_head(&child->font->hfontlist, &hfontlist->entry);
3723 child->font->base_font = font;
3724 list_add_head(&child_font_list, &child->font->entry);
3725 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
3729 static BOOL get_glyph_index_linked(GdiFont font, UINT c, GdiFont *linked_font, FT_UInt *glyph)
3732 CHILD_FONT *child_font;
3735 font = font->base_font;
3737 *linked_font = font;
3739 if((*glyph = get_glyph_index(font, c)))
3742 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
3744 if(!child_font->font)
3745 if(!load_child_font(font, child_font))
3748 if(!child_font->font->ft_face)
3750 g = get_glyph_index(child_font->font, c);
3754 *linked_font = child_font->font;
3761 /*************************************************************
3762 * WineEngGetCharWidth
3765 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3770 FT_UInt glyph_index;
3771 GdiFont linked_font;
3773 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3775 for(c = firstChar; c <= lastChar; c++) {
3776 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3777 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3778 &gm, 0, NULL, NULL);
3779 buffer[c - firstChar] = linked_font->gm[glyph_index].adv;
3784 /*************************************************************
3785 * WineEngGetCharABCWidths
3788 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3793 FT_UInt glyph_index;
3794 GdiFont linked_font;
3796 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3798 if(!FT_IS_SCALABLE(font->ft_face))
3801 for(c = firstChar; c <= lastChar; c++) {
3802 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3803 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3804 &gm, 0, NULL, NULL);
3805 buffer[c - firstChar].abcA = linked_font->gm[glyph_index].lsb;
3806 buffer[c - firstChar].abcB = linked_font->gm[glyph_index].bbx;
3807 buffer[c - firstChar].abcC = linked_font->gm[glyph_index].adv - linked_font->gm[glyph_index].lsb -
3808 linked_font->gm[glyph_index].bbx;
3813 /*************************************************************
3814 * WineEngGetCharABCWidthsI
3817 BOOL WineEngGetCharABCWidthsI(GdiFont font, UINT firstChar, UINT count, LPWORD pgi,
3822 FT_UInt glyph_index;
3823 GdiFont linked_font;
3825 if(!FT_IS_SCALABLE(font->ft_face))
3828 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
3830 for(c = firstChar; c < firstChar+count; c++) {
3831 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
3832 &gm, 0, NULL, NULL);
3833 buffer[c - firstChar].abcA = linked_font->gm[c].lsb;
3834 buffer[c - firstChar].abcB = linked_font->gm[c].bbx;
3835 buffer[c - firstChar].abcC = linked_font->gm[c].adv - linked_font->gm[c].lsb
3836 - linked_font->gm[c].bbx;
3839 for(c = 0; c < count; c++) {
3840 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
3841 &gm, 0, NULL, NULL);
3842 buffer[c].abcA = linked_font->gm[pgi[c]].lsb;
3843 buffer[c].abcB = linked_font->gm[pgi[c]].bbx;
3844 buffer[c].abcC = linked_font->gm[pgi[c]].adv
3845 - linked_font->gm[pgi[c]].lsb - linked_font->gm[pgi[c]].bbx;
3851 /*************************************************************
3852 * WineEngGetTextExtentExPoint
3855 BOOL WineEngGetTextExtentExPoint(GdiFont font, LPCWSTR wstr, INT count,
3856 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
3862 FT_UInt glyph_index;
3863 GdiFont linked_font;
3865 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
3869 WineEngGetTextMetrics(font, &tm);
3870 size->cy = tm.tmHeight;
3872 for(idx = 0; idx < count; idx++) {
3873 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
3874 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3875 &gm, 0, NULL, NULL);
3876 size->cx += linked_font->gm[glyph_index].adv;
3878 if (! pnfit || ext <= max_ext) {
3888 TRACE("return %ld, %ld, %d\n", size->cx, size->cy, nfit);
3892 /*************************************************************
3893 * WineEngGetTextExtentPointI
3896 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3903 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3906 WineEngGetTextMetrics(font, &tm);
3907 size->cy = tm.tmHeight;
3909 for(idx = 0; idx < count; idx++) {
3910 WineEngGetGlyphOutline(font, indices[idx],
3911 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3913 size->cx += font->gm[indices[idx]].adv;
3915 TRACE("return %ld,%ld\n", size->cx, size->cy);
3919 /*************************************************************
3920 * WineEngGetFontData
3923 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3926 FT_Face ft_face = font->ft_face;
3930 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3931 font, table, offset, buf, cbData);
3933 if(!FT_IS_SFNT(ft_face))
3941 if(table) { /* MS tags differ in endidness from FT ones */
3942 table = table >> 24 | table << 24 |
3943 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3946 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3947 if(pFT_Load_Sfnt_Table) {
3948 /* make sure value of len is the value freetype says it needs */
3951 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3952 if( !err && needed < len) len = needed;
3954 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3956 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
3957 else { /* Do it the hard way */
3958 TT_Face tt_face = (TT_Face) ft_face;
3959 SFNT_Interface *sfnt;
3960 if (FT_Version.major==2 && FT_Version.minor==0)
3963 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3967 /* A field was added in the middle of the structure in 2.1.x */
3968 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3970 /* make sure value of len is the value freetype says it needs */
3973 err = sfnt->load_any(tt_face, table, offset, NULL, &needed);
3974 if( !err && needed < len) len = needed;
3976 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3982 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
3983 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
3984 "Please upgrade your freetype library.\n");
3987 err = FT_Err_Unimplemented_Feature;
3991 TRACE("Can't find table %08lx.\n", table);
3997 /*************************************************************
3998 * WineEngGetTextFace
4001 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
4004 lstrcpynW(str, font->name, count);
4005 return strlenW(font->name);
4007 return strlenW(font->name) + 1;
4010 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
4012 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4013 return font->charset;
4016 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4018 GdiFont font = dc->gdiFont, linked_font;
4019 struct list *first_hfont;
4022 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4023 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4024 if(font == linked_font)
4025 *new_hfont = dc->hFont;
4028 first_hfont = list_head(&linked_font->hfontlist);
4029 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4036 /*************************************************************
4039 BOOL WINAPI FontIsLinked(HDC hdc)
4041 DC *dc = DC_GetDCPtr(hdc);
4044 if(!dc) return FALSE;
4045 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
4047 GDI_ReleaseObj(hdc);
4048 TRACE("returning %d\n", ret);
4052 static BOOL is_hinting_enabled(void)
4054 /* Use the >= 2.2.0 function if available */
4055 if(pFT_Get_TrueType_Engine_Type)
4057 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4058 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4060 #ifdef FT_DRIVER_HAS_HINTER
4065 /* otherwise if we've been compiled with < 2.2.0 headers
4066 use the internal macro */
4067 mod = pFT_Get_Module(library, "truetype");
4068 if(mod && FT_DRIVER_HAS_HINTER(mod))
4076 /*************************************************************************
4077 * GetRasterizerCaps (GDI32.@)
4079 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4081 static int hinting = -1;
4084 hinting = is_hinting_enabled();
4086 lprs->nSize = sizeof(RASTERIZER_STATUS);
4087 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4088 lprs->nLanguageID = 0;
4093 #else /* HAVE_FREETYPE */
4095 /*************************************************************************/
4097 BOOL WineEngInit(void)
4101 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
4105 BOOL WineEngDestroyFontInstance(HFONT hfont)
4110 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4115 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
4116 LPWORD pgi, DWORD flags)
4121 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
4122 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4125 ERR("called but we don't have FreeType\n");
4129 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
4131 ERR("called but we don't have FreeType\n");
4135 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
4136 OUTLINETEXTMETRICW *potm)
4138 ERR("called but we don't have FreeType\n");
4142 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
4145 ERR("called but we don't have FreeType\n");
4149 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
4152 ERR("called but we don't have FreeType\n");
4156 BOOL WineEngGetCharABCWidthsI(GdiFont font, UINT firstChar, UINT count, LPWORD pgi,
4159 ERR("called but we don't have FreeType\n");
4163 BOOL WineEngGetTextExtentExPoint(GdiFont font, LPCWSTR wstr, INT count,
4164 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
4166 ERR("called but we don't have FreeType\n");
4170 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
4173 ERR("called but we don't have FreeType\n");
4177 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
4180 ERR("called but we don't have FreeType\n");
4184 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
4186 ERR("called but we don't have FreeType\n");
4190 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4196 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4202 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
4205 return DEFAULT_CHARSET;
4208 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4213 BOOL WINAPI FontIsLinked(HDC hdc)
4218 /*************************************************************************
4219 * GetRasterizerCaps (GDI32.@)
4221 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4223 lprs->nSize = sizeof(RASTERIZER_STATUS);
4225 lprs->nLanguageID = 0;
4229 #endif /* HAVE_FREETYPE */