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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 {
222 INT adv; /* These three hold to widths of the unrotated chars */
239 typedef struct tagHFONTLIST {
264 struct list hfontlist;
269 OUTLINETEXTMETRICW *potm;
272 struct list child_fonts;
282 #define INIT_GM_SIZE 128
284 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
285 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
286 #define UNUSED_CACHE_SIZE 10
287 static struct list child_font_list = LIST_INIT(child_font_list);
288 static struct list system_links = LIST_INIT(system_links);
290 static struct list font_subst_list = LIST_INIT(font_subst_list);
292 static struct list font_list = LIST_INIT(font_list);
294 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
295 'R','o','m','a','n','\0'};
296 static const WCHAR defSans[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
297 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
299 static const WCHAR defSystem[] = {'S','y','s','t','e','m','\0'};
300 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
301 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
302 'S','e','r','i','f','\0'};
303 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
304 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
306 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
307 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
308 'W','i','n','d','o','w','s','\\',
309 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
310 'F','o','n','t','s','\0'};
312 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
313 'W','i','n','d','o','w','s',' ','N','T','\\',
314 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
315 'F','o','n','t','s','\0'};
317 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
318 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
319 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
320 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
322 static const WCHAR *SystemFontValues[4] = {
329 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
330 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
332 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
333 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
334 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
335 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
336 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
337 'E','u','r','o','p','e','a','n','\0'};
338 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
339 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
340 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
341 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
342 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
343 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
344 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
345 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
346 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
347 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
348 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
349 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
351 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
361 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
369 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
378 typedef struct tagFontSubst {
384 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
386 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
389 /****************************************
390 * Notes on .fon files
392 * The fonts System, FixedSys and Terminal are special. There are typically multiple
393 * versions installed for different resolutions and codepages. Windows stores which one to use
394 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
396 * FIXEDFON.FON FixedSys
398 * OEMFONT.FON Terminal
399 * LogPixels Current dpi set by the display control panel applet
400 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
401 * also has a LogPixels value that appears to mirror this)
403 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
404 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
405 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
406 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
407 * so that makes sense.
409 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
410 * to be mapped into the registry on Windows 2000 at least).
413 * ega80woa.fon=ega80850.fon
414 * ega40woa.fon=ega40850.fon
415 * cga80woa.fon=cga80850.fon
416 * cga40woa.fon=cga40850.fon
420 static inline BOOL is_win9x(void)
422 return GetVersion() & 0x80000000;
425 This function builds an FT_Fixed from a float. It puts the integer part
426 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
427 It fails if the integer part of the float number is greater than SHORT_MAX.
429 static inline FT_Fixed FT_FixedFromFloat(float f)
432 unsigned short fract = (f - value) * 0xFFFF;
433 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
437 This function builds an FT_Fixed from a FIXED. It simply put f.value
438 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
440 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
442 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
446 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
451 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
452 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
455 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
456 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
458 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
460 if(face_name && strcmpiW(face_name, family->FamilyName))
462 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
464 file = strrchr(face->file, '/');
469 if(!strcmp(file, file_nameA))
474 HeapFree(GetProcessHeap(), 0, file_nameA);
478 static Family *find_family_from_name(const WCHAR *name)
482 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
484 if(!strcmpiW(family->FamilyName, name))
491 static void DumpSubstList(void)
495 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
497 if(psub->from.charset != -1 || psub->to.charset != -1)
498 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
499 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
501 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
502 debugstr_w(psub->to.name));
507 static LPWSTR strdupW(LPCWSTR p)
510 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
511 ret = HeapAlloc(GetProcessHeap(), 0, len);
516 static LPSTR strdupA(LPCSTR p)
519 DWORD len = (strlen(p) + 1);
520 ret = HeapAlloc(GetProcessHeap(), 0, len);
525 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
530 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
532 if(!strcmpiW(element->from.name, from_name) &&
533 (element->from.charset == from_charset ||
534 element->from.charset == -1))
541 #define ADD_FONT_SUBST_FORCE 1
543 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
545 FontSubst *from_exist, *to_exist;
547 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
549 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
551 list_remove(&from_exist->entry);
552 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
553 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
554 HeapFree(GetProcessHeap(), 0, from_exist);
560 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
564 HeapFree(GetProcessHeap(), 0, subst->to.name);
565 subst->to.name = strdupW(to_exist->to.name);
568 list_add_tail(subst_list, &subst->entry);
573 HeapFree(GetProcessHeap(), 0, subst->from.name);
574 HeapFree(GetProcessHeap(), 0, subst->to.name);
575 HeapFree(GetProcessHeap(), 0, subst);
579 static void split_subst_info(NameCs *nc, LPSTR str)
581 CHAR *p = strrchr(str, ',');
586 nc->charset = strtol(p+1, NULL, 10);
589 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
590 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
591 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
594 static void LoadSubstList(void)
598 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
602 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
603 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
604 &hkey) == ERROR_SUCCESS) {
606 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
607 &valuelen, &datalen, NULL, NULL);
609 valuelen++; /* returned value doesn't include room for '\0' */
610 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
611 data = HeapAlloc(GetProcessHeap(), 0, datalen);
615 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
616 &dlen) == ERROR_SUCCESS) {
617 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
619 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
620 split_subst_info(&psub->from, value);
621 split_subst_info(&psub->to, data);
623 /* Win 2000 doesn't allow mapping between different charsets
624 or mapping of DEFAULT_CHARSET */
625 if((psub->to.charset != psub->from.charset) ||
626 psub->to.charset == DEFAULT_CHARSET) {
627 HeapFree(GetProcessHeap(), 0, psub->to.name);
628 HeapFree(GetProcessHeap(), 0, psub->from.name);
629 HeapFree(GetProcessHeap(), 0, psub);
631 add_font_subst(&font_subst_list, psub, 0);
633 /* reset dlen and vlen */
637 HeapFree(GetProcessHeap(), 0, data);
638 HeapFree(GetProcessHeap(), 0, value);
643 static WCHAR *get_familyname(FT_Face ft_face)
645 WCHAR *family = NULL;
647 FT_UInt num_names, name_index, i;
649 if(FT_IS_SFNT(ft_face))
651 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
653 for(name_index = 0; name_index < num_names; name_index++)
655 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
657 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
658 (name.language_id == GetUserDefaultLCID()) &&
659 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
660 (name.encoding_id == TT_MS_ID_UNICODE_CS))
662 /* String is not nul terminated and string_len is a byte length. */
663 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
664 for(i = 0; i < name.string_len / 2; i++)
666 WORD *tmp = (WORD *)&name.string[i * 2];
667 family[i] = GET_BE_WORD(*tmp);
671 TRACE("Got localised name %s\n", debugstr_w(family));
682 #define ADDFONT_EXTERNAL_FONT 0x01
683 #define ADDFONT_FORCE_BITMAP 0x02
684 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
688 TT_Header *pHeader = NULL;
689 WCHAR *english_family, *localised_family, *StyleW;
693 struct list *family_elem_ptr, *face_elem_ptr;
695 FT_Long face_index = 0, num_faces;
696 #ifdef HAVE_FREETYPE_FTWINFNT_H
697 FT_WinFNT_HeaderRec winfnt_header;
699 int i, bitmap_num, internal_leading;
703 char *family_name = fake_family;
705 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
706 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
707 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
711 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*/
712 WARN("Ignoring font %s\n", debugstr_a(file));
713 pFT_Done_Face(ft_face);
717 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
718 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
719 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file));
720 pFT_Done_Face(ft_face);
724 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
725 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
726 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
727 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
728 "Skipping this font.\n", debugstr_a(file));
729 pFT_Done_Face(ft_face);
733 if(!ft_face->family_name || !ft_face->style_name) {
734 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
735 pFT_Done_Face(ft_face);
740 family_name = ft_face->family_name;
744 My_FT_Bitmap_Size *size = NULL;
746 if(!FT_IS_SCALABLE(ft_face))
747 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
749 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
750 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
751 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
753 localised_family = NULL;
755 localised_family = get_familyname(ft_face);
756 if(localised_family && !strcmpW(localised_family, english_family)) {
757 HeapFree(GetProcessHeap(), 0, localised_family);
758 localised_family = NULL;
763 LIST_FOR_EACH(family_elem_ptr, &font_list) {
764 family = LIST_ENTRY(family_elem_ptr, Family, entry);
765 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
770 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
771 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
772 list_init(&family->faces);
773 list_add_tail(&font_list, &family->entry);
775 if(localised_family) {
776 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
777 subst->from.name = strdupW(english_family);
778 subst->from.charset = -1;
779 subst->to.name = strdupW(localised_family);
780 subst->to.charset = -1;
781 add_font_subst(&font_subst_list, subst, 0);
784 HeapFree(GetProcessHeap(), 0, localised_family);
785 HeapFree(GetProcessHeap(), 0, english_family);
787 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
788 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
789 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
791 internal_leading = 0;
792 memset(&fs, 0, sizeof(fs));
794 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
796 fs.fsCsb[0] = pOS2->ulCodePageRange1;
797 fs.fsCsb[1] = pOS2->ulCodePageRange2;
798 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
799 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
800 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
801 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
802 if(pOS2->version == 0) {
805 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
808 fs.fsCsb[0] |= 1L << 31;
811 #ifdef HAVE_FREETYPE_FTWINFNT_H
812 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
814 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
815 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
816 if(TranslateCharsetInfo((DWORD*)(UINT)winfnt_header.charset, &csi, TCI_SRCCHARSET))
817 memcpy(&fs, &csi.fs, sizeof(csi.fs));
818 internal_leading = winfnt_header.internal_leading;
822 face_elem_ptr = list_head(&family->faces);
823 while(face_elem_ptr) {
824 face = LIST_ENTRY(face_elem_ptr, Face, entry);
825 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
826 if(!strcmpW(face->StyleName, StyleW) &&
827 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
828 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
829 debugstr_w(family->FamilyName), debugstr_w(StyleW),
830 face->font_version, pHeader ? pHeader->Font_Revision : 0);
833 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
834 HeapFree(GetProcessHeap(), 0, StyleW);
835 pFT_Done_Face(ft_face);
838 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
839 TRACE("Original font is newer so skipping this one\n");
840 HeapFree(GetProcessHeap(), 0, StyleW);
841 pFT_Done_Face(ft_face);
844 TRACE("Replacing original with this one\n");
845 list_remove(&face->entry);
846 HeapFree(GetProcessHeap(), 0, face->file);
847 HeapFree(GetProcessHeap(), 0, face->StyleName);
848 HeapFree(GetProcessHeap(), 0, face);
853 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
854 list_add_tail(&family->faces, &face->entry);
855 face->StyleName = StyleW;
856 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
857 strcpy(face->file, file);
858 face->face_index = face_index;
859 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
860 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
861 face->font_version = pHeader ? pHeader->Font_Revision : 0;
862 face->family = family;
863 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
864 memcpy(&face->fs, &fs, sizeof(face->fs));
865 memset(&face->fs_links, 0, sizeof(face->fs_links));
867 if(FT_IS_SCALABLE(ft_face)) {
868 memset(&face->size, 0, sizeof(face->size));
869 face->scalable = TRUE;
871 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
872 size->height, size->width, size->size >> 6,
873 size->x_ppem >> 6, size->y_ppem >> 6);
874 face->size.height = size->height;
875 face->size.width = size->width;
876 face->size.size = size->size;
877 face->size.x_ppem = size->x_ppem;
878 face->size.y_ppem = size->y_ppem;
879 face->size.internal_leading = internal_leading;
880 face->scalable = FALSE;
883 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
884 face->fs.fsCsb[0], face->fs.fsCsb[1],
885 face->fs.fsUsb[0], face->fs.fsUsb[1],
886 face->fs.fsUsb[2], face->fs.fsUsb[3]);
889 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
890 for(i = 0; i < ft_face->num_charmaps; i++) {
891 switch(ft_face->charmaps[i]->encoding) {
892 case FT_ENCODING_UNICODE:
893 case FT_ENCODING_APPLE_ROMAN:
894 face->fs.fsCsb[0] |= 1;
896 case FT_ENCODING_MS_SYMBOL:
897 face->fs.fsCsb[0] |= 1L << 31;
905 if(face->fs.fsCsb[0] & ~(1L << 31))
906 have_installed_roman_font = TRUE;
907 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
909 num_faces = ft_face->num_faces;
910 pFT_Done_Face(ft_face);
911 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
913 } while(num_faces > ++face_index);
917 static void DumpFontList(void)
921 struct list *family_elem_ptr, *face_elem_ptr;
923 LIST_FOR_EACH(family_elem_ptr, &font_list) {
924 family = LIST_ENTRY(family_elem_ptr, Family, entry);
925 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
926 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
927 face = LIST_ENTRY(face_elem_ptr, Face, entry);
928 TRACE("\t%s\t%08lx", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
930 TRACE(" %ld", face->size.y_ppem >> 6);
937 /***********************************************************
938 * The replacement list is a way to map an entire font
939 * family onto another family. For example adding
941 * [HKCU\Software\Wine\Fonts\Replacements]
942 * "Wingdings"="Winedings"
944 * would enumerate the Winedings font both as Winedings and
945 * Wingdings. However if a real Wingdings font is present the
946 * replacement does not take place.
949 static void LoadReplaceList(void)
952 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
957 struct list *family_elem_ptr, *face_elem_ptr;
958 WCHAR old_nameW[200];
960 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
961 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
963 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
964 &valuelen, &datalen, NULL, NULL);
966 valuelen++; /* returned value doesn't include room for '\0' */
967 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
968 data = HeapAlloc(GetProcessHeap(), 0, datalen);
972 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
973 &dlen) == ERROR_SUCCESS) {
974 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
975 /* "NewName"="Oldname" */
976 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)/sizeof(WCHAR)))
979 /* Find the old family and hence all of the font files
981 LIST_FOR_EACH(family_elem_ptr, &font_list) {
982 family = LIST_ENTRY(family_elem_ptr, Family, entry);
983 if(!strcmpiW(family->FamilyName, old_nameW)) {
984 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
985 face = LIST_ENTRY(face_elem_ptr, Face, entry);
986 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
987 debugstr_w(face->StyleName), value);
988 /* Now add a new entry with the new family name */
989 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
994 /* reset dlen and vlen */
998 HeapFree(GetProcessHeap(), 0, data);
999 HeapFree(GetProcessHeap(), 0, value);
1004 /*************************************************************
1007 static BOOL init_system_links(void)
1009 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1010 'W','i','n','d','o','w','s',' ','N','T','\\',
1011 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1012 'S','y','s','t','e','m','L','i','n','k',0};
1015 DWORD type, max_val, max_data, val_len, data_len, index;
1016 WCHAR *value, *data;
1017 WCHAR *entry, *next;
1018 SYSTEM_LINKS *font_link, *system_font_link;
1019 CHILD_FONT *child_font;
1020 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1021 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1022 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1027 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1029 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1030 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1031 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1032 val_len = max_val + 1;
1033 data_len = max_data;
1035 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1037 TRACE("%s:\n", debugstr_w(value));
1039 memset(&fs, 0, sizeof(fs));
1040 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1041 font_link->font_name = strdupW(value);
1042 list_init(&font_link->links);
1043 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1046 CHILD_FONT *child_font;
1048 TRACE("\t%s\n", debugstr_w(entry));
1050 next = entry + strlenW(entry) + 1;
1052 face_name = strchrW(entry, ',');
1056 while(isspaceW(*face_name))
1059 face = find_face_from_filename(entry, face_name);
1062 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1066 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1067 child_font->file_name = strdupA(face->file);
1068 child_font->index = face->face_index;
1069 child_font->font = NULL;
1070 fs.fsCsb[0] |= face->fs.fsCsb[0];
1071 fs.fsCsb[1] |= face->fs.fsCsb[1];
1072 TRACE("Adding file %s index %d\n", child_font->file_name, child_font->index);
1073 list_add_tail(&font_link->links, &child_font->entry);
1075 family = find_family_from_name(font_link->font_name);
1078 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1080 memcpy(&face->fs_links, &fs, sizeof(fs));
1083 list_add_tail(&system_links, &font_link->entry);
1084 val_len = max_val + 1;
1085 data_len = max_data;
1088 HeapFree(GetProcessHeap(), 0, value);
1089 HeapFree(GetProcessHeap(), 0, data);
1093 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1096 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1097 system_font_link->font_name = strdupW(System);
1098 list_init(&system_font_link->links);
1100 face = find_face_from_filename(tahoma_ttf, Tahoma);
1103 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1104 child_font->file_name = strdupA(face->file);
1105 child_font->index = face->face_index;
1106 child_font->font = NULL;
1107 TRACE("Found Tahoma in %s index %d\n", child_font->file_name, child_font->index);
1108 list_add_tail(&system_font_link->links, &child_font->entry);
1110 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1112 if(!strcmpiW(font_link->font_name, Tahoma))
1114 CHILD_FONT *font_link_entry;
1115 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1117 CHILD_FONT *new_child;
1118 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1119 new_child->file_name = strdupA(font_link_entry->file_name);
1120 new_child->index = font_link_entry->index;
1121 new_child->font = NULL;
1122 list_add_tail(&system_font_link->links, &new_child->entry);
1127 list_add_tail(&system_links, &system_font_link->entry);
1131 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1134 struct dirent *dent;
1135 char path[MAX_PATH];
1137 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1139 dir = opendir(dirname);
1141 WARN("Can't open directory %s\n", debugstr_a(dirname));
1144 while((dent = readdir(dir)) != NULL) {
1145 struct stat statbuf;
1147 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1150 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1152 sprintf(path, "%s/%s", dirname, dent->d_name);
1154 if(stat(path, &statbuf) == -1)
1156 WARN("Can't stat %s\n", debugstr_a(path));
1159 if(S_ISDIR(statbuf.st_mode))
1160 ReadFontDir(path, external_fonts);
1162 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1168 static void load_fontconfig_fonts(void)
1170 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1171 void *fc_handle = NULL;
1177 const char *file, *ext;
1179 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1181 TRACE("Wine cannot find the fontconfig library (%s).\n",
1182 SONAME_LIBFONTCONFIG);
1185 #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;}
1186 LOAD_FUNCPTR(FcConfigGetCurrent);
1187 LOAD_FUNCPTR(FcFontList);
1188 LOAD_FUNCPTR(FcFontSetDestroy);
1189 LOAD_FUNCPTR(FcInit);
1190 LOAD_FUNCPTR(FcObjectSetAdd);
1191 LOAD_FUNCPTR(FcObjectSetCreate);
1192 LOAD_FUNCPTR(FcObjectSetDestroy);
1193 LOAD_FUNCPTR(FcPatternCreate);
1194 LOAD_FUNCPTR(FcPatternDestroy);
1195 LOAD_FUNCPTR(FcPatternGetString);
1198 if(!pFcInit()) return;
1200 config = pFcConfigGetCurrent();
1201 pat = pFcPatternCreate();
1202 os = pFcObjectSetCreate();
1203 pFcObjectSetAdd(os, FC_FILE);
1204 fontset = pFcFontList(config, pat, os);
1205 if(!fontset) return;
1206 for(i = 0; i < fontset->nfont; i++) {
1207 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1209 TRACE("fontconfig: %s\n", file);
1211 /* We're just interested in OT/TT fonts for now, so this hack just
1212 picks up the standard extensions to save time loading every other
1214 len = strlen( file );
1215 if(len < 4) continue;
1216 ext = &file[ len - 3 ];
1217 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
1218 AddFontFileToList(file, NULL, ADDFONT_EXTERNAL_FONT);
1220 pFcFontSetDestroy(fontset);
1221 pFcObjectSetDestroy(os);
1222 pFcPatternDestroy(pat);
1228 static BOOL load_font_from_data_dir(LPCWSTR file)
1231 const char *data_dir = wine_get_data_dir();
1233 if (!data_dir) data_dir = wine_get_build_dir();
1240 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1242 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1244 strcpy(unix_name, data_dir);
1245 strcat(unix_name, "/fonts/");
1247 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1249 ret = AddFontFileToList(unix_name, NULL, ADDFONT_FORCE_BITMAP);
1250 HeapFree(GetProcessHeap(), 0, unix_name);
1255 static void load_system_fonts(void)
1258 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1259 const WCHAR **value;
1261 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1264 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1265 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1266 strcatW(windowsdir, fontsW);
1267 for(value = SystemFontValues; *value; value++) {
1268 dlen = sizeof(data);
1269 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1273 sprintfW(pathW, fmtW, windowsdir, data);
1274 if((unixname = wine_get_unix_file_name(pathW))) {
1275 added = AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1276 HeapFree(GetProcessHeap(), 0, unixname);
1279 load_font_from_data_dir(data);
1286 /*************************************************************
1288 * This adds registry entries for any externally loaded fonts
1289 * (fonts from fontconfig or FontDirs). It also deletes entries
1290 * of no longer existing fonts.
1293 static void update_reg_entries(void)
1295 HKEY winkey = 0, externalkey = 0;
1298 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1301 struct list *family_elem_ptr, *face_elem_ptr;
1303 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1304 static const WCHAR spaceW[] = {' ', '\0'};
1307 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1308 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1309 ERR("Can't create Windows font reg key\n");
1312 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1313 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1314 ERR("Can't create external font reg key\n");
1318 /* Delete all external fonts added last time */
1320 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1321 &valuelen, &datalen, NULL, NULL);
1322 valuelen++; /* returned value doesn't include room for '\0' */
1323 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1324 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1326 dlen = datalen * sizeof(WCHAR);
1329 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1330 &dlen) == ERROR_SUCCESS) {
1332 RegDeleteValueW(winkey, valueW);
1333 /* reset dlen and vlen */
1337 HeapFree(GetProcessHeap(), 0, data);
1338 HeapFree(GetProcessHeap(), 0, valueW);
1340 /* Delete the old external fonts key */
1341 RegCloseKey(externalkey);
1343 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1345 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1346 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1347 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1348 ERR("Can't create external font reg key\n");
1352 /* enumerate the fonts and add external ones to the two keys */
1354 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1355 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1356 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1357 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1358 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1359 if(!face->external) continue;
1361 if(strcmpiW(face->StyleName, RegularW))
1362 len = len_fam + strlenW(face->StyleName) + 1;
1363 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1364 strcpyW(valueW, family->FamilyName);
1365 if(len != len_fam) {
1366 strcatW(valueW, spaceW);
1367 strcatW(valueW, face->StyleName);
1369 strcatW(valueW, TrueType);
1370 if((path = strrchr(face->file, '/')) == NULL)
1374 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1376 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1377 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1378 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1379 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1381 HeapFree(GetProcessHeap(), 0, file);
1382 HeapFree(GetProcessHeap(), 0, valueW);
1387 RegCloseKey(externalkey);
1389 RegCloseKey(winkey);
1394 /*************************************************************
1395 * WineEngAddFontResourceEx
1398 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1400 if (ft_handle) /* do it only if we have freetype up and running */
1405 FIXME("Ignoring flags %lx\n", flags);
1407 if((unixname = wine_get_unix_file_name(file)))
1409 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1410 HeapFree(GetProcessHeap(), 0, unixname);
1416 /*************************************************************
1417 * WineEngRemoveFontResourceEx
1420 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1426 static const struct nls_update_font_list
1428 UINT ansi_cp, oem_cp;
1429 const char *oem, *fixed, *system;
1430 const char *courier, *serif, *small, *sserif;
1431 } nls_update_font_list[] =
1433 /* Latin 1 (United States) */
1434 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1435 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1437 /* Latin 1 (Multilingual) */
1438 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1439 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1441 /* Eastern Europe */
1442 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1443 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1446 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1447 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1450 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1451 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1454 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1455 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1458 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1459 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1462 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1463 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1466 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1467 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1470 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1471 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1474 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1475 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1478 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1479 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1481 /* Chinese Simplified */
1482 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1483 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1486 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1487 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1489 /* Chinese Traditional */
1490 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1491 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1495 inline static HKEY create_fonts_NT_registry_key(void)
1499 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1500 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1504 inline static HKEY create_fonts_9x_registry_key(void)
1508 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1509 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1513 inline static HKEY create_config_fonts_registry_key(void)
1517 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1518 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1522 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1524 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1525 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1526 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1527 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1530 static void update_font_info(void)
1535 UINT i, ansi_cp = 0, oem_cp = 0;
1536 LCID lcid = GetUserDefaultLCID();
1538 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) != ERROR_SUCCESS)
1542 if (RegQueryValueExA(hkey, "Locale", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1544 if (strtoul(buf, NULL, 16 ) == lcid) /* already set correctly */
1549 TRACE("updating registry, locale changed %s -> %08lx\n", debugstr_a(buf), lcid);
1551 else TRACE("updating registry, locale changed none -> %08lx\n", lcid);
1553 sprintf(buf, "%08lx", lcid);
1554 RegSetValueExA(hkey, "Locale", 0, REG_SZ, (const BYTE *)buf, strlen(buf)+1);
1557 GetLocaleInfoW(lcid, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1558 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1559 GetLocaleInfoW(lcid, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1560 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1562 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1564 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1565 nls_update_font_list[i].oem_cp == oem_cp)
1569 hkey = create_config_fonts_registry_key();
1570 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1571 RegSetValueExA(hkey, "FIXED.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1572 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1575 hkey = create_fonts_NT_registry_key();
1576 add_font_list(hkey, &nls_update_font_list[i]);
1579 hkey = create_fonts_9x_registry_key();
1580 add_font_list(hkey, &nls_update_font_list[i]);
1586 FIXME("there is no font defaults for lcid %04lx/ansi_cp %u", lcid, ansi_cp);
1589 /*************************************************************
1592 * Initialize FreeType library and create a list of available faces
1594 BOOL WineEngInit(void)
1596 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1597 static const WCHAR pathW[] = {'P','a','t','h',0};
1599 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1601 WCHAR windowsdir[MAX_PATH];
1604 const char *data_dir;
1608 /* update locale dependent font info in registry */
1611 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1614 "Wine cannot find the FreeType font library. To enable Wine to\n"
1615 "use TrueType fonts please install a version of FreeType greater than\n"
1616 "or equal to 2.0.5.\n"
1617 "http://www.freetype.org\n");
1621 #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;}
1623 LOAD_FUNCPTR(FT_Vector_Unit)
1624 LOAD_FUNCPTR(FT_Done_Face)
1625 LOAD_FUNCPTR(FT_Get_Char_Index)
1626 LOAD_FUNCPTR(FT_Get_Module)
1627 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1628 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1629 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1630 LOAD_FUNCPTR(FT_Init_FreeType)
1631 LOAD_FUNCPTR(FT_Load_Glyph)
1632 LOAD_FUNCPTR(FT_Matrix_Multiply)
1633 LOAD_FUNCPTR(FT_MulFix)
1634 LOAD_FUNCPTR(FT_New_Face)
1635 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1636 LOAD_FUNCPTR(FT_Outline_Transform)
1637 LOAD_FUNCPTR(FT_Outline_Translate)
1638 LOAD_FUNCPTR(FT_Select_Charmap)
1639 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1640 LOAD_FUNCPTR(FT_Vector_Transform)
1643 /* Don't warn if this one is missing */
1644 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1645 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1646 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1647 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
1648 #ifdef HAVE_FREETYPE_FTWINFNT_H
1649 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1651 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1652 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1653 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1654 <= 2.0.3 has FT_Sqrt64 */
1658 if(pFT_Init_FreeType(&library) != 0) {
1659 ERR("Can't init FreeType library\n");
1660 wine_dlclose(ft_handle, NULL, 0);
1664 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1665 if (pFT_Library_Version)
1667 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1669 if (FT_Version.major<=0)
1675 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1676 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1677 ((FT_Version.minor << 8) & 0x00ff00) |
1678 ((FT_Version.patch ) & 0x0000ff);
1680 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1681 ERR("Failed to create font mutex\n");
1684 WaitForSingleObject(font_mutex, INFINITE);
1686 /* load the system bitmap fonts */
1687 load_system_fonts();
1689 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1690 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1691 strcatW(windowsdir, fontsW);
1692 if((unixname = wine_get_unix_file_name(windowsdir)))
1694 ReadFontDir(unixname, FALSE);
1695 HeapFree(GetProcessHeap(), 0, unixname);
1698 /* load the system truetype fonts */
1699 data_dir = wine_get_data_dir();
1700 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
1701 strcpy(unixname, data_dir);
1702 strcat(unixname, "/fonts/");
1703 ReadFontDir(unixname, FALSE);
1704 HeapFree(GetProcessHeap(), 0, unixname);
1707 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1708 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1709 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1711 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1712 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1713 &hkey) == ERROR_SUCCESS) {
1715 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1716 &valuelen, &datalen, NULL, NULL);
1718 valuelen++; /* returned value doesn't include room for '\0' */
1719 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1720 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1723 dlen = datalen * sizeof(WCHAR);
1725 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1726 &dlen) == ERROR_SUCCESS) {
1727 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1729 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1731 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1732 HeapFree(GetProcessHeap(), 0, unixname);
1735 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1737 WCHAR pathW[MAX_PATH];
1738 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1741 sprintfW(pathW, fmtW, windowsdir, data);
1742 if((unixname = wine_get_unix_file_name(pathW)))
1744 added = AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1745 HeapFree(GetProcessHeap(), 0, unixname);
1748 load_font_from_data_dir(data);
1750 /* reset dlen and vlen */
1755 HeapFree(GetProcessHeap(), 0, data);
1756 HeapFree(GetProcessHeap(), 0, valueW);
1760 load_fontconfig_fonts();
1762 /* then look in any directories that we've specified in the config file */
1763 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
1764 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
1770 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
1772 len += sizeof(WCHAR);
1773 valueW = HeapAlloc( GetProcessHeap(), 0, len );
1774 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
1776 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
1777 valueA = HeapAlloc( GetProcessHeap(), 0, len );
1778 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
1779 TRACE( "got font path %s\n", debugstr_a(valueA) );
1783 LPSTR next = strchr( ptr, ':' );
1784 if (next) *next++ = 0;
1785 ReadFontDir( ptr, TRUE );
1788 HeapFree( GetProcessHeap(), 0, valueA );
1790 HeapFree( GetProcessHeap(), 0, valueW );
1799 update_reg_entries();
1801 init_system_links();
1803 ReleaseMutex(font_mutex);
1807 "Wine cannot find certain functions that it needs inside the FreeType\n"
1808 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1809 "FreeType to at least version 2.0.5.\n"
1810 "http://www.freetype.org\n");
1811 wine_dlclose(ft_handle, NULL, 0);
1817 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1820 TT_HoriHeader *pHori;
1824 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1825 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1827 if(height == 0) height = 16;
1829 /* Calc. height of EM square:
1831 * For +ve lfHeight we have
1832 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1833 * Re-arranging gives:
1834 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1836 * For -ve lfHeight we have
1838 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1839 * with il = winAscent + winDescent - units_per_em]
1844 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1845 ppem = ft_face->units_per_EM * height /
1846 (pHori->Ascender - pHori->Descender);
1848 ppem = ft_face->units_per_EM * height /
1849 (pOS2->usWinAscent + pOS2->usWinDescent);
1857 static LONG load_VDMX(GdiFont, LONG);
1859 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1864 TRACE("%s, %ld, %ld x %ld\n", debugstr_a(file), face_index, width, height);
1865 err = pFT_New_Face(library, file, face_index, &ft_face);
1867 ERR("FT_New_Face rets %d\n", err);
1871 /* set it here, as load_VDMX needs it */
1872 font->ft_face = ft_face;
1874 if(FT_IS_SCALABLE(ft_face)) {
1875 /* load the VDMX table if we have one */
1876 font->ppem = load_VDMX(font, height);
1878 font->ppem = calc_ppem_for_height(ft_face, height);
1880 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
1881 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, font->ppem, err);
1883 font->ppem = height;
1884 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1885 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1891 static int get_nearest_charset(Face *face, int *cp)
1893 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1894 a single face with the requested charset. The idea is to check if
1895 the selected font supports the current ANSI codepage, if it does
1896 return the corresponding charset, else return the first charset */
1899 int acp = GetACP(), i;
1903 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1904 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1905 return csi.ciCharset;
1907 for(i = 0; i < 32; i++) {
1909 if(face->fs.fsCsb[0] & fs0) {
1910 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
1912 return csi.ciCharset;
1915 FIXME("TCI failing on %lx\n", fs0);
1919 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1920 face->fs.fsCsb[0], face->file);
1922 return DEFAULT_CHARSET;
1925 static GdiFont alloc_font(void)
1927 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1928 ret->gmsize = INIT_GM_SIZE;
1929 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1930 ret->gmsize * sizeof(*ret->gm));
1932 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1933 list_init(&ret->hfontlist);
1934 list_init(&ret->child_fonts);
1938 static void free_font(GdiFont font)
1940 struct list *cursor, *cursor2;
1942 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
1944 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
1945 struct list *first_hfont;
1946 HFONTLIST *hfontlist;
1947 list_remove(cursor);
1950 first_hfont = list_head(&child->font->hfontlist);
1951 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
1952 DeleteObject(hfontlist->hfont);
1953 HeapFree(GetProcessHeap(), 0, hfontlist);
1954 free_font(child->font);
1956 HeapFree(GetProcessHeap(), 0, child->file_name);
1957 HeapFree(GetProcessHeap(), 0, child);
1960 if (font->ft_face) pFT_Done_Face(font->ft_face);
1961 HeapFree(GetProcessHeap(), 0, font->potm);
1962 HeapFree(GetProcessHeap(), 0, font->name);
1963 HeapFree(GetProcessHeap(), 0, font->gm);
1964 HeapFree(GetProcessHeap(), 0, font);
1968 /*************************************************************
1971 * load the vdmx entry for the specified height
1974 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1975 ( ( (FT_ULong)_x4 << 24 ) | \
1976 ( (FT_ULong)_x3 << 16 ) | \
1977 ( (FT_ULong)_x2 << 8 ) | \
1980 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1995 static LONG load_VDMX(GdiFont font, LONG height)
1999 BYTE devXRatio, devYRatio;
2000 USHORT numRecs, numRatios;
2001 DWORD result, offset = -1;
2005 /* For documentation on VDMX records, see
2006 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2009 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2011 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2014 /* FIXME: need the real device aspect ratio */
2018 numRecs = GET_BE_WORD(hdr[1]);
2019 numRatios = GET_BE_WORD(hdr[2]);
2021 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2022 for(i = 0; i < numRatios; i++) {
2025 offset = (3 * 2) + (i * sizeof(Ratios));
2026 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2029 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2031 if((ratio.xRatio == 0 &&
2032 ratio.yStartRatio == 0 &&
2033 ratio.yEndRatio == 0) ||
2034 (devXRatio == ratio.xRatio &&
2035 devYRatio >= ratio.yStartRatio &&
2036 devYRatio <= ratio.yEndRatio))
2038 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2039 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2040 offset = GET_BE_WORD(tmp);
2046 FIXME("No suitable ratio found\n");
2050 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2052 BYTE startsz, endsz;
2055 recs = GET_BE_WORD(group.recs);
2056 startsz = group.startsz;
2057 endsz = group.endsz;
2059 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2061 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2062 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2063 if(result == GDI_ERROR) {
2064 FIXME("Failed to retrieve vTable\n");
2069 for(i = 0; i < recs; i++) {
2070 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2071 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2072 ppem = GET_BE_WORD(vTable[i * 3]);
2074 if(yMax + -yMin == height) {
2077 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2080 if(yMax + -yMin > height) {
2083 goto end; /* failed */
2085 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2086 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2087 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2093 TRACE("ppem not found for height %ld\n", height);
2097 if(ppem < startsz || ppem > endsz)
2100 for(i = 0; i < recs; i++) {
2102 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2104 if(yPelHeight > ppem)
2107 if(yPelHeight == ppem) {
2108 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2109 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2110 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2116 HeapFree(GetProcessHeap(), 0, vTable);
2122 static BOOL fontcmp(GdiFont font, FONT_DESC *fd)
2124 if(font->font_desc.hash != fd->hash) return TRUE;
2125 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2126 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2127 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2130 static void calc_hash(FONT_DESC *pfd)
2132 DWORD hash = 0, *ptr, two_chars;
2136 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2138 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2140 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2142 pwc = (WCHAR *)&two_chars;
2144 *pwc = toupperW(*pwc);
2146 *pwc = toupperW(*pwc);
2154 static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2159 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2161 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2162 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2165 /* try the in-use list */
2166 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2167 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2168 if(!fontcmp(ret, &fd)) {
2169 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2170 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2171 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2172 if(hflist->hfont == hfont)
2175 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2176 hflist->hfont = hfont;
2177 list_add_head(&ret->hfontlist, &hflist->entry);
2182 /* then the unused list */
2183 font_elem_ptr = list_head(&unused_gdi_font_list);
2184 while(font_elem_ptr) {
2185 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2186 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2187 if(!fontcmp(ret, &fd)) {
2188 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2189 assert(list_empty(&ret->hfontlist));
2190 TRACE("Found %p in unused list\n", ret);
2191 list_remove(&ret->entry);
2192 list_add_head(&gdi_font_list, &ret->entry);
2193 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2194 hflist->hfont = hfont;
2195 list_add_head(&ret->hfontlist, &hflist->entry);
2203 /*************************************************************
2204 * create_child_font_list
2206 static BOOL create_child_font_list(GdiFont font)
2209 SYSTEM_LINKS *font_link;
2210 CHILD_FONT *font_link_entry, *new_child;
2212 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2214 if(!strcmpW(font_link->font_name, font->name))
2216 TRACE("found entry in system list\n");
2217 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2219 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2220 new_child->file_name = strdupA(font_link_entry->file_name);
2221 new_child->index = font_link_entry->index;
2222 new_child->font = NULL;
2223 list_add_tail(&font->child_fonts, &new_child->entry);
2224 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
2234 /*************************************************************
2235 * WineEngCreateFontInstance
2238 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2242 Family *family, *last_resort_family;
2243 struct list *family_elem_ptr, *face_elem_ptr;
2244 INT height, width = 0;
2245 signed int diff = 0, newdiff;
2246 BOOL bd, it, can_use_bitmap;
2251 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2253 struct list *first_hfont = list_head(&ret->hfontlist);
2254 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2255 if(hflist->hfont == hfont)
2259 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2260 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2262 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
2263 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2264 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2267 /* check the cache first */
2268 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2269 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2273 TRACE("not in cache\n");
2274 if(list_empty(&font_list)) /* No fonts installed */
2276 TRACE("No fonts installed\n");
2279 if(!have_installed_roman_font)
2281 TRACE("No roman font installed\n");
2287 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2288 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2289 calc_hash(&ret->font_desc);
2290 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2291 hflist->hfont = hfont;
2292 list_add_head(&ret->hfontlist, &hflist->entry);
2295 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2296 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2297 original value lfCharSet. Note this is a special case for
2298 Symbol and doesn't happen at least for "Wingdings*" */
2300 if(!strcmpiW(lf.lfFaceName, SymbolW))
2301 lf.lfCharSet = SYMBOL_CHARSET;
2303 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2304 switch(lf.lfCharSet) {
2305 case DEFAULT_CHARSET:
2306 csi.fs.fsCsb[0] = 0;
2309 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2310 csi.fs.fsCsb[0] = 0;
2316 if(lf.lfFaceName[0] != '\0') {
2318 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2321 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2322 debugstr_w(psub->to.name));
2323 strcpyW(lf.lfFaceName, psub->to.name);
2326 /* We want a match on name and charset or just name if
2327 charset was DEFAULT_CHARSET. If the latter then
2328 we fixup the returned charset later in get_nearest_charset
2329 where we'll either use the charset of the current ansi codepage
2330 or if that's unavailable the first charset that the font supports.
2332 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2333 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2334 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2335 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2336 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2337 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2338 if(face->scalable || can_use_bitmap)
2345 /* If requested charset was DEFAULT_CHARSET then try using charset
2346 corresponding to the current ansi codepage */
2347 if(!csi.fs.fsCsb[0]) {
2349 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
2350 FIXME("TCI failed on codepage %d\n", acp);
2351 csi.fs.fsCsb[0] = 0;
2353 lf.lfCharSet = csi.ciCharset;
2356 /* Face families are in the top 4 bits of lfPitchAndFamily,
2357 so mask with 0xF0 before testing */
2359 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2360 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2361 strcpyW(lf.lfFaceName, defFixed);
2362 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2363 strcpyW(lf.lfFaceName, defSerif);
2364 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2365 strcpyW(lf.lfFaceName, defSans);
2367 strcpyW(lf.lfFaceName, defSans);
2368 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2369 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2370 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2371 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2372 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2373 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2374 if(face->scalable || can_use_bitmap)
2380 last_resort_family = NULL;
2381 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2382 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2383 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2384 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2385 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2388 if(can_use_bitmap && !last_resort_family)
2389 last_resort_family = family;
2394 if(last_resort_family) {
2395 family = last_resort_family;
2396 csi.fs.fsCsb[0] = 0;
2400 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2401 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2402 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2403 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2404 if(face->scalable) {
2405 csi.fs.fsCsb[0] = 0;
2406 FIXME("just using first face for now\n");
2409 if(can_use_bitmap && !last_resort_family)
2410 last_resort_family = family;
2413 if(!last_resort_family) {
2414 FIXME("can't find a single appropriate font - bailing\n");
2419 WARN("could only find a bitmap font - this will probably look awful!\n");
2420 family = last_resort_family;
2421 csi.fs.fsCsb[0] = 0;
2424 it = lf.lfItalic ? 1 : 0;
2425 bd = lf.lfWeight > 550 ? 1 : 0;
2427 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2428 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2431 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2432 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2433 if(!(face->Italic ^ it) && !(face->Bold ^ bd) &&
2434 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])) {
2438 newdiff = height - (signed int)(face->size.y_ppem >> 6);
2440 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
2441 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
2442 (diff < 0 && newdiff > diff)) {
2443 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
2456 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2457 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2458 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]) {
2462 newdiff = height - (signed int)(face->size.y_ppem >> 6);
2464 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
2465 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
2466 (diff < 0 && newdiff > diff)) {
2467 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
2478 if(it && !face->Italic) ret->fake_italic = TRUE;
2479 if(bd && !face->Bold) ret->fake_bold = TRUE;
2482 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2484 if(csi.fs.fsCsb[0]) {
2485 ret->charset = lf.lfCharSet;
2486 ret->codepage = csi.ciACP;
2489 ret->charset = get_nearest_charset(face, &ret->codepage);
2491 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2492 debugstr_w(face->StyleName), face->file, face->face_index);
2494 if(!face->scalable) {
2495 width = face->size.x_ppem >> 6;
2496 height = face->size.y_ppem >> 6;
2498 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2506 if (ret->charset == SYMBOL_CHARSET &&
2507 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2510 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2514 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2517 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2518 ret->name = strdupW(family->FamilyName);
2519 ret->underline = lf.lfUnderline ? 0xff : 0;
2520 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2521 create_child_font_list(ret);
2523 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2525 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
2526 list_add_head(&gdi_font_list, &ret->entry);
2530 static void dump_gdi_font_list(void)
2533 struct list *elem_ptr;
2535 TRACE("---------- gdiFont Cache ----------\n");
2536 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2537 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2538 TRACE("gdiFont=%p %s %ld\n",
2539 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2542 TRACE("---------- Unused gdiFont Cache ----------\n");
2543 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2544 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2545 TRACE("gdiFont=%p %s %ld\n",
2546 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2550 /*************************************************************
2551 * WineEngDestroyFontInstance
2553 * free the gdiFont associated with this handle
2556 BOOL WineEngDestroyFontInstance(HFONT handle)
2561 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2564 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
2566 struct list *first_hfont = list_head(&gdiFont->hfontlist);
2567 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2568 if(hflist->hfont == handle)
2570 TRACE("removing child font %p from child list\n", gdiFont);
2571 list_remove(&gdiFont->entry);
2576 TRACE("destroying hfont=%p\n", handle);
2578 dump_gdi_font_list();
2580 font_elem_ptr = list_head(&gdi_font_list);
2581 while(font_elem_ptr) {
2582 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2583 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
2585 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
2586 while(hfontlist_elem_ptr) {
2587 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2588 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
2589 if(hflist->hfont == handle) {
2590 list_remove(&hflist->entry);
2591 HeapFree(GetProcessHeap(), 0, hflist);
2595 if(list_empty(&gdiFont->hfontlist)) {
2596 TRACE("Moving to Unused list\n");
2597 list_remove(&gdiFont->entry);
2598 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
2603 font_elem_ptr = list_head(&unused_gdi_font_list);
2604 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
2605 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2606 while(font_elem_ptr) {
2607 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2608 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2609 TRACE("freeing %p\n", gdiFont);
2610 list_remove(&gdiFont->entry);
2616 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2617 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
2619 OUTLINETEXTMETRICW *potm = NULL;
2621 TEXTMETRICW tm, *ptm;
2622 GdiFont font = alloc_font();
2625 if(face->scalable) {
2629 height = face->size.y_ppem >> 6;
2630 width = face->size.x_ppem >> 6;
2633 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
2639 font->name = strdupW(face->family->FamilyName);
2641 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
2643 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
2645 potm = HeapAlloc(GetProcessHeap(), 0, size);
2646 WineEngGetOutlineTextMetrics(font, size, potm);
2647 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
2649 WineEngGetTextMetrics(font, &tm);
2653 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
2654 pntm->ntmTm.tmAscent = ptm->tmAscent;
2655 pntm->ntmTm.tmDescent = ptm->tmDescent;
2656 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
2657 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
2658 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
2659 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
2660 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
2661 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
2662 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
2663 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
2664 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
2665 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
2666 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
2667 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
2668 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
2669 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
2670 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
2671 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
2672 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
2673 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
2674 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2675 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2676 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
2678 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
2679 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
2680 *ptype |= RASTER_FONTTYPE;
2682 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2683 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2684 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2686 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
2687 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
2688 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2691 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
2693 lstrcpynW(pelf->elfLogFont.lfFaceName,
2694 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
2696 lstrcpynW(pelf->elfFullName,
2697 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
2699 lstrcpynW(pelf->elfStyle,
2700 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2703 HeapFree(GetProcessHeap(), 0, potm);
2705 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
2707 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2708 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2709 pelf->elfStyle[0] = '\0';
2712 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2717 /*************************************************************
2721 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2725 struct list *family_elem_ptr, *face_elem_ptr;
2727 NEWTEXTMETRICEXW ntm;
2728 DWORD type, ret = 1;
2734 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2736 if(plf->lfFaceName[0]) {
2738 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
2741 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2742 debugstr_w(psub->to.name));
2743 memcpy(&lf, plf, sizeof(lf));
2744 strcpyW(lf.lfFaceName, psub->to.name);
2748 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2749 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2750 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2751 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2752 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2753 GetEnumStructs(face, &elf, &ntm, &type);
2754 for(i = 0; i < 32; i++) {
2755 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2756 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2757 strcpyW(elf.elfScript, OEM_DOSW);
2758 i = 32; /* break out of loop */
2759 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2762 fs.fsCsb[0] = 1L << i;
2764 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2766 csi.ciCharset = DEFAULT_CHARSET;
2767 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2768 if(csi.ciCharset != DEFAULT_CHARSET) {
2769 elf.elfLogFont.lfCharSet =
2770 ntm.ntmTm.tmCharSet = csi.ciCharset;
2772 strcpyW(elf.elfScript, ElfScriptsW[i]);
2774 FIXME("Unknown elfscript for bit %d\n", i);
2777 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2778 debugstr_w(elf.elfLogFont.lfFaceName),
2779 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2780 csi.ciCharset, type, debugstr_w(elf.elfScript),
2781 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2782 ntm.ntmTm.ntmFlags);
2783 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2790 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2791 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2792 face_elem_ptr = list_head(&family->faces);
2793 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2794 GetEnumStructs(face, &elf, &ntm, &type);
2795 for(i = 0; i < 32; i++) {
2796 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2797 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2798 strcpyW(elf.elfScript, OEM_DOSW);
2799 i = 32; /* break out of loop */
2800 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2803 fs.fsCsb[0] = 1L << i;
2805 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2807 csi.ciCharset = DEFAULT_CHARSET;
2808 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2809 if(csi.ciCharset != DEFAULT_CHARSET) {
2810 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2813 strcpyW(elf.elfScript, ElfScriptsW[i]);
2815 FIXME("Unknown elfscript for bit %d\n", i);
2818 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2819 debugstr_w(elf.elfLogFont.lfFaceName),
2820 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2821 csi.ciCharset, type, debugstr_w(elf.elfScript),
2822 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2823 ntm.ntmTm.ntmFlags);
2824 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2833 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2835 pt->x.value = vec->x >> 6;
2836 pt->x.fract = (vec->x & 0x3f) << 10;
2837 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2838 pt->y.value = vec->y >> 6;
2839 pt->y.fract = (vec->y & 0x3f) << 10;
2840 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2844 /***************************************************
2845 * According to the MSDN documentation on WideCharToMultiByte,
2846 * certain codepages cannot set the default_used parameter.
2847 * This returns TRUE if the codepage can set that parameter, false else
2848 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
2850 static BOOL codepage_sets_default_used(UINT codepage)
2863 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2865 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
2866 WCHAR wc = (WCHAR)glyph;
2868 BOOL *default_used_pointer;
2871 default_used_pointer = NULL;
2872 default_used = FALSE;
2873 if (codepage_sets_default_used(font->codepage))
2874 default_used_pointer = &default_used;
2875 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
2878 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
2879 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
2883 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2884 glyph = glyph + 0xf000;
2885 return pFT_Get_Char_Index(font->ft_face, glyph);
2888 /*************************************************************
2889 * WineEngGetGlyphIndices
2891 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2893 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2894 LPWORD pgi, DWORD flags)
2898 for(i = 0; i < count; i++)
2899 pgi[i] = get_glyph_index(font, lpstr[i]);
2904 /*************************************************************
2905 * WineEngGetGlyphOutline
2907 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2908 * except that the first parameter is the HWINEENGFONT of the font in
2909 * question rather than an HDC.
2912 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2913 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2916 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2917 FT_Face ft_face = font->ft_face;
2918 FT_UInt glyph_index;
2919 DWORD width, height, pitch, needed = 0;
2920 FT_Bitmap ft_bitmap;
2922 INT left, right, top = 0, bottom = 0;
2924 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2925 float widthRatio = 1.0;
2926 FT_Matrix transMat = identityMat;
2927 BOOL needsTransform = FALSE;
2930 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2931 buflen, buf, lpmat);
2933 if(format & GGO_GLYPH_INDEX) {
2934 glyph_index = glyph;
2935 format &= ~GGO_GLYPH_INDEX;
2937 glyph_index = get_glyph_index(font, glyph);
2939 if(glyph_index >= font->gmsize) {
2940 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2941 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2942 font->gmsize * sizeof(*font->gm));
2944 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2945 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2946 return 1; /* FIXME */
2950 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2951 load_flags |= FT_LOAD_NO_BITMAP;
2953 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2956 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2960 /* Scaling factor */
2961 if (font->aveWidth && font->potm) {
2962 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2965 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2966 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2968 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2969 font->gm[glyph_index].lsb = left >> 6;
2970 font->gm[glyph_index].bbx = (right - left) >> 6;
2972 /* Scaling transform */
2973 if(font->aveWidth) {
2975 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2978 scaleMat.yy = (1 << 16);
2980 pFT_Matrix_Multiply(&scaleMat, &transMat);
2981 needsTransform = TRUE;
2984 /* Slant transform */
2985 if (font->fake_italic) {
2988 slantMat.xx = (1 << 16);
2989 slantMat.xy = ((1 << 16) >> 2);
2991 slantMat.yy = (1 << 16);
2992 pFT_Matrix_Multiply(&slantMat, &transMat);
2993 needsTransform = TRUE;
2996 /* Rotation transform */
2997 if(font->orientation) {
2998 FT_Matrix rotationMat;
3000 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3001 pFT_Vector_Unit(&vecAngle, angle);
3002 rotationMat.xx = vecAngle.x;
3003 rotationMat.xy = -vecAngle.y;
3004 rotationMat.yx = -rotationMat.xy;
3005 rotationMat.yy = rotationMat.xx;
3007 pFT_Matrix_Multiply(&rotationMat, &transMat);
3008 needsTransform = TRUE;
3011 /* Extra transformation specified by caller */
3014 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3015 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3016 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3017 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3018 pFT_Matrix_Multiply(&extraMat, &transMat);
3019 needsTransform = TRUE;
3022 if(!needsTransform) {
3023 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3024 bottom = (ft_face->glyph->metrics.horiBearingY -
3025 ft_face->glyph->metrics.height) & -64;
3026 lpgm->gmCellIncX = font->gm[glyph_index].adv;
3027 lpgm->gmCellIncY = 0;
3031 for(xc = 0; xc < 2; xc++) {
3032 for(yc = 0; yc < 2; yc++) {
3033 vec.x = (ft_face->glyph->metrics.horiBearingX +
3034 xc * ft_face->glyph->metrics.width);
3035 vec.y = ft_face->glyph->metrics.horiBearingY -
3036 yc * ft_face->glyph->metrics.height;
3037 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3038 pFT_Vector_Transform(&vec, &transMat);
3039 if(xc == 0 && yc == 0) {
3040 left = right = vec.x;
3041 top = bottom = vec.y;
3043 if(vec.x < left) left = vec.x;
3044 else if(vec.x > right) right = vec.x;
3045 if(vec.y < bottom) bottom = vec.y;
3046 else if(vec.y > top) top = vec.y;
3051 right = (right + 63) & -64;
3052 bottom = bottom & -64;
3053 top = (top + 63) & -64;
3055 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3056 vec.x = ft_face->glyph->metrics.horiAdvance;
3058 pFT_Vector_Transform(&vec, &transMat);
3059 lpgm->gmCellIncX = (vec.x+63) >> 6;
3060 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3062 lpgm->gmBlackBoxX = (right - left) >> 6;
3063 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3064 lpgm->gmptGlyphOrigin.x = left >> 6;
3065 lpgm->gmptGlyphOrigin.y = top >> 6;
3067 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
3068 font->gm[glyph_index].init = TRUE;
3070 if(format == GGO_METRICS)
3071 return 1; /* FIXME */
3073 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
3074 TRACE("loaded a bitmap\n");
3080 width = lpgm->gmBlackBoxX;
3081 height = lpgm->gmBlackBoxY;
3082 pitch = ((width + 31) >> 5) << 2;
3083 needed = pitch * height;
3085 if(!buf || !buflen) break;
3087 switch(ft_face->glyph->format) {
3088 case ft_glyph_format_bitmap:
3090 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3091 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3092 INT h = ft_face->glyph->bitmap.rows;
3094 memcpy(dst, src, w);
3095 src += ft_face->glyph->bitmap.pitch;
3101 case ft_glyph_format_outline:
3102 ft_bitmap.width = width;
3103 ft_bitmap.rows = height;
3104 ft_bitmap.pitch = pitch;
3105 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3106 ft_bitmap.buffer = buf;
3108 if(needsTransform) {
3109 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3112 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3114 /* Note: FreeType will only set 'black' bits for us. */
3115 memset(buf, 0, needed);
3116 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3120 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3125 case GGO_GRAY2_BITMAP:
3126 case GGO_GRAY4_BITMAP:
3127 case GGO_GRAY8_BITMAP:
3128 case WINE_GGO_GRAY16_BITMAP:
3130 unsigned int mult, row, col;
3133 width = lpgm->gmBlackBoxX;
3134 height = lpgm->gmBlackBoxY;
3135 pitch = (width + 3) / 4 * 4;
3136 needed = pitch * height;
3138 if(!buf || !buflen) break;
3139 ft_bitmap.width = width;
3140 ft_bitmap.rows = height;
3141 ft_bitmap.pitch = pitch;
3142 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3143 ft_bitmap.buffer = buf;
3145 if(needsTransform) {
3146 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3149 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3151 memset(ft_bitmap.buffer, 0, buflen);
3153 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3155 if(format == GGO_GRAY2_BITMAP)
3157 else if(format == GGO_GRAY4_BITMAP)
3159 else if(format == GGO_GRAY8_BITMAP)
3161 else if(format == WINE_GGO_GRAY16_BITMAP)
3169 for(row = 0; row < height; row++) {
3171 for(col = 0; col < width; col++, ptr++) {
3172 *ptr = (((int)*ptr) * mult + 128) / 256;
3181 int contour, point = 0, first_pt;
3182 FT_Outline *outline = &ft_face->glyph->outline;
3183 TTPOLYGONHEADER *pph;
3185 DWORD pph_start, cpfx, type;
3187 if(buflen == 0) buf = NULL;
3189 if (needsTransform && buf) {
3190 pFT_Outline_Transform(outline, &transMat);
3193 for(contour = 0; contour < outline->n_contours; contour++) {
3195 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3198 pph->dwType = TT_POLYGON_TYPE;
3199 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3201 needed += sizeof(*pph);
3203 while(point <= outline->contours[contour]) {
3204 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3205 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3206 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3210 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3213 } while(point <= outline->contours[contour] &&
3214 (outline->tags[point] & FT_Curve_Tag_On) ==
3215 (outline->tags[point-1] & FT_Curve_Tag_On));
3216 /* At the end of a contour Windows adds the start point, but
3218 if(point > outline->contours[contour] &&
3219 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3221 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3223 } else if(point <= outline->contours[contour] &&
3224 outline->tags[point] & FT_Curve_Tag_On) {
3225 /* add closing pt for bezier */
3227 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3235 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3238 pph->cb = needed - pph_start;
3244 /* Convert the quadratic Beziers to cubic Beziers.
3245 The parametric eqn for a cubic Bezier is, from PLRM:
3246 r(t) = at^3 + bt^2 + ct + r0
3247 with the control points:
3252 A quadratic Beizer has the form:
3253 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3255 So equating powers of t leads to:
3256 r1 = 2/3 p1 + 1/3 p0
3257 r2 = 2/3 p1 + 1/3 p2
3258 and of course r0 = p0, r3 = p2
3261 int contour, point = 0, first_pt;
3262 FT_Outline *outline = &ft_face->glyph->outline;
3263 TTPOLYGONHEADER *pph;
3265 DWORD pph_start, cpfx, type;
3266 FT_Vector cubic_control[4];
3267 if(buflen == 0) buf = NULL;
3269 if (needsTransform && buf) {
3270 pFT_Outline_Transform(outline, &transMat);
3273 for(contour = 0; contour < outline->n_contours; contour++) {
3275 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3278 pph->dwType = TT_POLYGON_TYPE;
3279 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3281 needed += sizeof(*pph);
3283 while(point <= outline->contours[contour]) {
3284 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3285 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3286 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3289 if(type == TT_PRIM_LINE) {
3291 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3295 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3298 /* FIXME: Possible optimization in endpoint calculation
3299 if there are two consecutive curves */
3300 cubic_control[0] = outline->points[point-1];
3301 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3302 cubic_control[0].x += outline->points[point].x + 1;
3303 cubic_control[0].y += outline->points[point].y + 1;
3304 cubic_control[0].x >>= 1;
3305 cubic_control[0].y >>= 1;
3307 if(point+1 > outline->contours[contour])
3308 cubic_control[3] = outline->points[first_pt];
3310 cubic_control[3] = outline->points[point+1];
3311 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3312 cubic_control[3].x += outline->points[point].x + 1;
3313 cubic_control[3].y += outline->points[point].y + 1;
3314 cubic_control[3].x >>= 1;
3315 cubic_control[3].y >>= 1;
3318 /* r1 = 1/3 p0 + 2/3 p1
3319 r2 = 1/3 p2 + 2/3 p1 */
3320 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3321 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3322 cubic_control[2] = cubic_control[1];
3323 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3324 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3325 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3326 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3328 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3329 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3330 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3335 } while(point <= outline->contours[contour] &&
3336 (outline->tags[point] & FT_Curve_Tag_On) ==
3337 (outline->tags[point-1] & FT_Curve_Tag_On));
3338 /* At the end of a contour Windows adds the start point,
3339 but only for Beziers and we've already done that.
3341 if(point <= outline->contours[contour] &&
3342 outline->tags[point] & FT_Curve_Tag_On) {
3343 /* This is the closing pt of a bezier, but we've already
3344 added it, so just inc point and carry on */
3351 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3354 pph->cb = needed - pph_start;
3360 FIXME("Unsupported format %d\n", format);
3366 static BOOL get_bitmap_text_metrics(GdiFont font)
3368 FT_Face ft_face = font->ft_face;
3369 #ifdef HAVE_FREETYPE_FTWINFNT_H
3370 FT_WinFNT_HeaderRec winfnt_header;
3372 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3373 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3374 font->potm->otmSize = size;
3376 #define TM font->potm->otmTextMetrics
3377 #ifdef HAVE_FREETYPE_FTWINFNT_H
3378 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3380 TM.tmHeight = winfnt_header.pixel_height;
3381 TM.tmAscent = winfnt_header.ascent;
3382 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3383 TM.tmInternalLeading = winfnt_header.internal_leading;
3384 TM.tmExternalLeading = winfnt_header.external_leading;
3385 TM.tmAveCharWidth = winfnt_header.avg_width;
3386 TM.tmMaxCharWidth = winfnt_header.max_width;
3387 TM.tmWeight = winfnt_header.weight;
3389 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3390 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3391 TM.tmFirstChar = winfnt_header.first_char;
3392 TM.tmLastChar = winfnt_header.last_char;
3393 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3394 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3395 TM.tmItalic = winfnt_header.italic;
3396 TM.tmUnderlined = font->underline;
3397 TM.tmStruckOut = font->strikeout;
3398 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3399 TM.tmCharSet = winfnt_header.charset;
3404 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3405 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3406 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3407 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3408 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3409 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3410 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3411 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3413 TM.tmDigitizedAspectX = 96; /* FIXME */
3414 TM.tmDigitizedAspectY = 96; /* FIXME */
3416 TM.tmLastChar = 255;
3417 TM.tmDefaultChar = 32;
3418 TM.tmBreakChar = 32;
3419 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3420 TM.tmUnderlined = font->underline;
3421 TM.tmStruckOut = font->strikeout;
3422 /* NB inverted meaning of TMPF_FIXED_PITCH */
3423 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3424 TM.tmCharSet = font->charset;
3431 /*************************************************************
3432 * WineEngGetTextMetrics
3435 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3438 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3439 if(!get_bitmap_text_metrics(font))
3442 if(!font->potm) return FALSE;
3443 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3445 if (font->aveWidth) {
3446 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3452 /*************************************************************
3453 * WineEngGetOutlineTextMetrics
3456 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3457 OUTLINETEXTMETRICW *potm)
3459 FT_Face ft_face = font->ft_face;
3460 UINT needed, lenfam, lensty, ret;
3462 TT_HoriHeader *pHori;
3463 TT_Postscript *pPost;
3464 FT_Fixed x_scale, y_scale;
3465 WCHAR *family_nameW, *style_nameW;
3466 static const WCHAR spaceW[] = {' ', '\0'};
3468 INT ascent, descent;
3470 TRACE("font=%p\n", font);
3472 if(!FT_IS_SCALABLE(ft_face))
3476 if(cbSize >= font->potm->otmSize)
3477 memcpy(potm, font->potm, font->potm->otmSize);
3478 return font->potm->otmSize;
3482 needed = sizeof(*potm);
3484 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3485 family_nameW = strdupW(font->name);
3487 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3489 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3490 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3491 style_nameW, lensty/sizeof(WCHAR));
3493 /* These names should be read from the TT name table */
3495 /* length of otmpFamilyName */
3498 /* length of otmpFaceName */
3499 if(!strcasecmp(ft_face->style_name, "regular")) {
3500 needed += lenfam; /* just the family name */
3502 needed += lenfam + lensty; /* family + " " + style */
3505 /* length of otmpStyleName */
3508 /* length of otmpFullName */
3509 needed += lenfam + lensty;
3512 x_scale = ft_face->size->metrics.x_scale;
3513 y_scale = ft_face->size->metrics.y_scale;
3515 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3517 FIXME("Can't find OS/2 table - not TT font?\n");
3522 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3524 FIXME("Can't find HHEA table - not TT font?\n");
3529 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3531 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",
3532 pOS2->usWinAscent, pOS2->usWinDescent,
3533 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3534 ft_face->ascender, ft_face->descender, ft_face->height,
3535 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3536 ft_face->bbox.yMax, ft_face->bbox.yMin);
3538 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3539 font->potm->otmSize = needed;
3541 #define TM font->potm->otmTextMetrics
3543 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3544 ascent = pHori->Ascender;
3545 descent = -pHori->Descender;
3547 ascent = pOS2->usWinAscent;
3548 descent = pOS2->usWinDescent;
3552 TM.tmAscent = font->yMax;
3553 TM.tmDescent = -font->yMin;
3554 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3556 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
3557 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
3558 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
3559 - ft_face->units_per_EM, y_scale) + 32) >> 6;
3562 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3565 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3567 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
3568 ((ascent + descent) -
3569 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
3571 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
3572 if (TM.tmAveCharWidth == 0) {
3573 TM.tmAveCharWidth = 1;
3575 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
3576 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
3578 TM.tmDigitizedAspectX = 300;
3579 TM.tmDigitizedAspectY = 300;
3580 TM.tmFirstChar = pOS2->usFirstCharIndex;
3581 TM.tmLastChar = pOS2->usLastCharIndex;
3582 TM.tmDefaultChar = pOS2->usDefaultChar;
3583 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
3584 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3585 TM.tmUnderlined = font->underline;
3586 TM.tmStruckOut = font->strikeout;
3588 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3589 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3590 (pOS2->version == 0xFFFFU ||
3591 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3592 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3594 TM.tmPitchAndFamily = 0;
3596 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
3597 case PAN_FAMILY_SCRIPT:
3598 TM.tmPitchAndFamily |= FF_SCRIPT;
3600 case PAN_FAMILY_DECORATIVE:
3601 case PAN_FAMILY_PICTORIAL:
3602 TM.tmPitchAndFamily |= FF_DECORATIVE;
3604 case PAN_FAMILY_TEXT_DISPLAY:
3605 if(TM.tmPitchAndFamily == 0) /* fixed */
3606 TM.tmPitchAndFamily = FF_MODERN;
3608 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
3609 case PAN_SERIF_NORMAL_SANS:
3610 case PAN_SERIF_OBTUSE_SANS:
3611 case PAN_SERIF_PERP_SANS:
3612 TM.tmPitchAndFamily |= FF_SWISS;
3615 TM.tmPitchAndFamily |= FF_ROMAN;
3620 TM.tmPitchAndFamily |= FF_DONTCARE;
3623 if(FT_IS_SCALABLE(ft_face))
3624 TM.tmPitchAndFamily |= TMPF_VECTOR;
3625 if(FT_IS_SFNT(ft_face))
3626 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3628 TM.tmCharSet = font->charset;
3631 font->potm->otmFiller = 0;
3632 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3633 font->potm->otmfsSelection = pOS2->fsSelection;
3634 font->potm->otmfsType = pOS2->fsType;
3635 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
3636 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
3637 font->potm->otmItalicAngle = 0; /* POST table */
3638 font->potm->otmEMSquare = ft_face->units_per_EM;
3639 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
3640 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
3641 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
3642 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
3643 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
3644 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
3645 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
3646 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
3647 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
3648 font->potm->otmMacAscent = 0; /* where do these come from ? */
3649 font->potm->otmMacDescent = 0;
3650 font->potm->otmMacLineGap = 0;
3651 font->potm->otmusMinimumPPEM = 0; /* TT Header */
3652 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
3653 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
3654 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
3655 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
3656 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
3657 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
3658 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
3659 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
3660 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
3661 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
3663 font->potm->otmsUnderscoreSize = 0;
3664 font->potm->otmsUnderscorePosition = 0;
3666 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
3667 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
3670 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
3671 cp = (char*)font->potm + sizeof(*font->potm);
3672 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
3673 strcpyW((WCHAR*)cp, family_nameW);
3675 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
3676 strcpyW((WCHAR*)cp, style_nameW);
3678 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
3679 strcpyW((WCHAR*)cp, family_nameW);
3680 if(strcasecmp(ft_face->style_name, "regular")) {
3681 strcatW((WCHAR*)cp, spaceW);
3682 strcatW((WCHAR*)cp, style_nameW);
3683 cp += lenfam + lensty;
3686 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
3687 strcpyW((WCHAR*)cp, family_nameW);
3688 strcatW((WCHAR*)cp, spaceW);
3689 strcatW((WCHAR*)cp, style_nameW);
3692 if(potm && needed <= cbSize)
3693 memcpy(potm, font->potm, font->potm->otmSize);
3696 HeapFree(GetProcessHeap(), 0, style_nameW);
3697 HeapFree(GetProcessHeap(), 0, family_nameW);
3702 static BOOL load_child_font(GdiFont font, CHILD_FONT *child)
3704 HFONTLIST *hfontlist;
3705 child->font = alloc_font();
3706 child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem);
3707 if(!child->font->ft_face)
3709 free_font(child->font);
3714 child->font->orientation = font->orientation;
3715 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
3716 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
3717 list_add_head(&child->font->hfontlist, &hfontlist->entry);
3718 child->font->base_font = font;
3719 list_add_head(&child_font_list, &child->font->entry);
3720 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
3724 static BOOL get_glyph_index_linked(GdiFont font, UINT c, GdiFont *linked_font, FT_UInt *glyph)
3727 CHILD_FONT *child_font;
3730 font = font->base_font;
3732 *linked_font = font;
3734 if((*glyph = get_glyph_index(font, c)))
3737 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
3739 if(!child_font->font)
3740 if(!load_child_font(font, child_font))
3743 if(!child_font->font->ft_face)
3745 g = get_glyph_index(child_font->font, c);
3749 *linked_font = child_font->font;
3756 /*************************************************************
3757 * WineEngGetCharWidth
3760 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3765 FT_UInt glyph_index;
3766 GdiFont linked_font;
3768 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3770 for(c = firstChar; c <= lastChar; c++) {
3771 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3772 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3773 &gm, 0, NULL, NULL);
3774 buffer[c - firstChar] = linked_font->gm[glyph_index].adv;
3779 /*************************************************************
3780 * WineEngGetCharABCWidths
3783 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3788 FT_UInt glyph_index;
3789 GdiFont linked_font;
3791 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3793 if(!FT_IS_SCALABLE(font->ft_face))
3796 for(c = firstChar; c <= lastChar; c++) {
3797 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3798 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3799 &gm, 0, NULL, NULL);
3800 buffer[c - firstChar].abcA = linked_font->gm[glyph_index].lsb;
3801 buffer[c - firstChar].abcB = linked_font->gm[glyph_index].bbx;
3802 buffer[c - firstChar].abcC = linked_font->gm[glyph_index].adv - linked_font->gm[glyph_index].lsb -
3803 linked_font->gm[glyph_index].bbx;
3808 /*************************************************************
3809 * WineEngGetCharABCWidthsI
3812 BOOL WineEngGetCharABCWidthsI(GdiFont font, UINT firstChar, UINT count, LPWORD pgi,
3817 FT_UInt glyph_index;
3818 GdiFont linked_font;
3820 if(!FT_IS_SCALABLE(font->ft_face))
3823 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
3825 for(c = firstChar; c < firstChar+count; c++) {
3826 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
3827 &gm, 0, NULL, NULL);
3828 buffer[c - firstChar].abcA = linked_font->gm[c].lsb;
3829 buffer[c - firstChar].abcB = linked_font->gm[c].bbx;
3830 buffer[c - firstChar].abcC = linked_font->gm[c].adv - linked_font->gm[c].lsb
3831 - linked_font->gm[c].bbx;
3834 for(c = 0; c < count; c++) {
3835 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
3836 &gm, 0, NULL, NULL);
3837 buffer[c].abcA = linked_font->gm[pgi[c]].lsb;
3838 buffer[c].abcB = linked_font->gm[pgi[c]].bbx;
3839 buffer[c].abcC = linked_font->gm[pgi[c]].adv
3840 - linked_font->gm[pgi[c]].lsb - linked_font->gm[pgi[c]].bbx;
3846 /*************************************************************
3847 * WineEngGetTextExtentPoint
3850 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3856 FT_UInt glyph_index;
3857 GdiFont linked_font;
3859 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
3863 WineEngGetTextMetrics(font, &tm);
3864 size->cy = tm.tmHeight;
3866 for(idx = 0; idx < count; idx++) {
3867 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
3868 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3869 &gm, 0, NULL, NULL);
3870 size->cx += linked_font->gm[glyph_index].adv;
3872 TRACE("return %ld,%ld\n", size->cx, size->cy);
3876 /*************************************************************
3877 * WineEngGetTextExtentPointI
3880 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3887 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3890 WineEngGetTextMetrics(font, &tm);
3891 size->cy = tm.tmHeight;
3893 for(idx = 0; idx < count; idx++) {
3894 WineEngGetGlyphOutline(font, indices[idx],
3895 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3897 size->cx += font->gm[indices[idx]].adv;
3899 TRACE("return %ld,%ld\n", size->cx, size->cy);
3903 /*************************************************************
3904 * WineEngGetFontData
3907 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3910 FT_Face ft_face = font->ft_face;
3914 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3915 font, table, offset, buf, cbData);
3917 if(!FT_IS_SFNT(ft_face))
3925 if(table) { /* MS tags differ in endidness from FT ones */
3926 table = table >> 24 | table << 24 |
3927 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3930 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3931 if(pFT_Load_Sfnt_Table) {
3932 /* make sure value of len is the value freetype says it needs */
3935 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3936 if( !err && needed < len) len = needed;
3938 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3940 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
3941 else { /* Do it the hard way */
3942 TT_Face tt_face = (TT_Face) ft_face;
3943 SFNT_Interface *sfnt;
3944 if (FT_Version.major==2 && FT_Version.minor==0)
3947 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3951 /* A field was added in the middle of the structure in 2.1.x */
3952 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3954 /* make sure value of len is the value freetype says it needs */
3957 err = sfnt->load_any(tt_face, table, offset, NULL, &needed);
3958 if( !err && needed < len) len = needed;
3960 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3966 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
3967 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
3968 "Please upgrade your freetype library.\n");
3971 err = FT_Err_Unimplemented_Feature;
3975 TRACE("Can't find table %08lx.\n", table);
3981 /*************************************************************
3982 * WineEngGetTextFace
3985 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3988 lstrcpynW(str, font->name, count);
3989 return strlenW(font->name);
3991 return strlenW(font->name) + 1;
3994 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3996 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
3997 return font->charset;
4000 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4002 GdiFont font = dc->gdiFont, linked_font;
4003 struct list *first_hfont;
4006 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4007 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4008 if(font == linked_font)
4009 *new_hfont = dc->hFont;
4012 first_hfont = list_head(&linked_font->hfontlist);
4013 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4020 /*************************************************************
4023 BOOL WINAPI FontIsLinked(HDC hdc)
4025 DC *dc = DC_GetDCPtr(hdc);
4028 if(!dc) return FALSE;
4029 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
4031 GDI_ReleaseObj(hdc);
4032 TRACE("returning %d\n", ret);
4036 static BOOL is_hinting_enabled(void)
4040 /* Use the >= 2.2.0 function if available */
4041 if(pFT_Get_TrueType_Engine_Type)
4043 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4044 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4047 /* otherwise if we've been compiled with < 2.2.0 headers
4048 use the internal macro */
4049 #ifdef FT_DRIVER_HAS_HINTER
4050 mod = pFT_Get_Module(library, "truetype");
4051 if(mod && FT_DRIVER_HAS_HINTER(mod))
4058 /*************************************************************************
4059 * GetRasterizerCaps (GDI32.@)
4061 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4063 static int hinting = -1;
4066 hinting = is_hinting_enabled();
4068 lprs->nSize = sizeof(RASTERIZER_STATUS);
4069 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4070 lprs->nLanguageID = 0;
4075 #else /* HAVE_FREETYPE */
4077 BOOL WineEngInit(void)
4081 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
4085 BOOL WineEngDestroyFontInstance(HFONT hfont)
4090 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4095 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
4096 LPWORD pgi, DWORD flags)
4101 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
4102 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4105 ERR("called but we don't have FreeType\n");
4109 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
4111 ERR("called but we don't have FreeType\n");
4115 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
4116 OUTLINETEXTMETRICW *potm)
4118 ERR("called but we don't have FreeType\n");
4122 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
4125 ERR("called but we don't have FreeType\n");
4129 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
4132 ERR("called but we don't have FreeType\n");
4136 BOOL WineEngGetCharABCWidthsI(GdiFont font, UINT firstChar, UINT count, LPWORD pgi,
4139 ERR("called but we don't have FreeType\n");
4143 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
4146 ERR("called but we don't have FreeType\n");
4150 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
4153 ERR("called but we don't have FreeType\n");
4157 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
4160 ERR("called but we don't have FreeType\n");
4164 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
4166 ERR("called but we don't have FreeType\n");
4170 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4176 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4182 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
4185 return DEFAULT_CHARSET;
4188 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4193 BOOL WINAPI FontIsLinked(HDC hdc)
4198 /*************************************************************************
4199 * GetRasterizerCaps (GDI32.@)
4201 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4203 lprs->nSize = sizeof(RASTERIZER_STATUS);
4205 lprs->nLanguageID = 0;
4209 #endif /* HAVE_FREETYPE */