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(FcPatternGet);
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;
1178 const char *file, *ext;
1180 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1182 TRACE("Wine cannot find the fontconfig library (%s).\n",
1183 SONAME_LIBFONTCONFIG);
1186 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1187 LOAD_FUNCPTR(FcConfigGetCurrent);
1188 LOAD_FUNCPTR(FcFontList);
1189 LOAD_FUNCPTR(FcFontSetDestroy);
1190 LOAD_FUNCPTR(FcInit);
1191 LOAD_FUNCPTR(FcObjectSetAdd);
1192 LOAD_FUNCPTR(FcObjectSetCreate);
1193 LOAD_FUNCPTR(FcObjectSetDestroy);
1194 LOAD_FUNCPTR(FcPatternCreate);
1195 LOAD_FUNCPTR(FcPatternDestroy);
1196 LOAD_FUNCPTR(FcPatternGet);
1199 if(!pFcInit()) return;
1201 config = pFcConfigGetCurrent();
1202 pat = pFcPatternCreate();
1203 os = pFcObjectSetCreate();
1204 pFcObjectSetAdd(os, FC_FILE);
1205 fontset = pFcFontList(config, pat, os);
1206 if(!fontset) return;
1207 for(i = 0; i < fontset->nfont; i++) {
1208 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
1210 if(v.type != FcTypeString) continue;
1211 file = (LPCSTR) v.u.s;
1212 TRACE("fontconfig: %s\n", file);
1214 /* We're just interested in OT/TT fonts for now, so this hack just
1215 picks up the standard extensions to save time loading every other
1217 len = strlen( file );
1218 if(len < 4) continue;
1219 ext = &file[ len - 3 ];
1220 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
1221 AddFontFileToList(file, NULL, ADDFONT_EXTERNAL_FONT);
1223 pFcFontSetDestroy(fontset);
1224 pFcObjectSetDestroy(os);
1225 pFcPatternDestroy(pat);
1231 static BOOL load_font_from_data_dir(LPCWSTR file)
1234 const char *data_dir = wine_get_data_dir();
1236 if (!data_dir) data_dir = wine_get_build_dir();
1243 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1245 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1247 strcpy(unix_name, data_dir);
1248 strcat(unix_name, "/fonts/");
1250 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1252 ret = AddFontFileToList(unix_name, NULL, ADDFONT_FORCE_BITMAP);
1253 HeapFree(GetProcessHeap(), 0, unix_name);
1258 static void load_system_fonts(void)
1261 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1262 const WCHAR **value;
1264 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1267 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1268 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1269 strcatW(windowsdir, fontsW);
1270 for(value = SystemFontValues; *value; value++) {
1271 dlen = sizeof(data);
1272 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1276 sprintfW(pathW, fmtW, windowsdir, data);
1277 if((unixname = wine_get_unix_file_name(pathW))) {
1278 added = AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1279 HeapFree(GetProcessHeap(), 0, unixname);
1282 load_font_from_data_dir(data);
1289 /*************************************************************
1291 * This adds registry entries for any externally loaded fonts
1292 * (fonts from fontconfig or FontDirs). It also deletes entries
1293 * of no longer existing fonts.
1296 static void update_reg_entries(void)
1298 HKEY winkey = 0, externalkey = 0;
1301 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1304 struct list *family_elem_ptr, *face_elem_ptr;
1306 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1307 static const WCHAR spaceW[] = {' ', '\0'};
1310 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1311 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1312 ERR("Can't create Windows font reg key\n");
1315 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1316 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1317 ERR("Can't create external font reg key\n");
1321 /* Delete all external fonts added last time */
1323 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1324 &valuelen, &datalen, NULL, NULL);
1325 valuelen++; /* returned value doesn't include room for '\0' */
1326 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1327 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1329 dlen = datalen * sizeof(WCHAR);
1332 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1333 &dlen) == ERROR_SUCCESS) {
1335 RegDeleteValueW(winkey, valueW);
1336 /* reset dlen and vlen */
1340 HeapFree(GetProcessHeap(), 0, data);
1341 HeapFree(GetProcessHeap(), 0, valueW);
1343 /* Delete the old external fonts key */
1344 RegCloseKey(externalkey);
1346 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1348 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1349 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1350 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1351 ERR("Can't create external font reg key\n");
1355 /* enumerate the fonts and add external ones to the two keys */
1357 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1358 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1359 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1360 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1361 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1362 if(!face->external) continue;
1364 if(strcmpiW(face->StyleName, RegularW))
1365 len = len_fam + strlenW(face->StyleName) + 1;
1366 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1367 strcpyW(valueW, family->FamilyName);
1368 if(len != len_fam) {
1369 strcatW(valueW, spaceW);
1370 strcatW(valueW, face->StyleName);
1372 strcatW(valueW, TrueType);
1373 if((path = strrchr(face->file, '/')) == NULL)
1377 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1379 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1380 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1381 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1382 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1384 HeapFree(GetProcessHeap(), 0, file);
1385 HeapFree(GetProcessHeap(), 0, valueW);
1390 RegCloseKey(externalkey);
1392 RegCloseKey(winkey);
1397 /*************************************************************
1398 * WineEngAddFontResourceEx
1401 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1403 if (ft_handle) /* do it only if we have freetype up and running */
1408 FIXME("Ignoring flags %lx\n", flags);
1410 if((unixname = wine_get_unix_file_name(file)))
1412 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1413 HeapFree(GetProcessHeap(), 0, unixname);
1419 /*************************************************************
1420 * WineEngRemoveFontResourceEx
1423 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1429 static const struct nls_update_font_list
1431 UINT ansi_cp, oem_cp;
1432 const char *oem, *fixed, *system;
1433 const char *courier, *serif, *small, *sserif;
1434 } nls_update_font_list[] =
1436 /* Latin 1 (United States) */
1437 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1438 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1440 /* Latin 1 (Multilingual) */
1441 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1442 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1444 /* Eastern Europe */
1445 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1446 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1449 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1450 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1453 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1454 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1457 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1458 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1461 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1462 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1465 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1466 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1469 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1470 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1473 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1474 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1477 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1478 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1481 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1482 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1484 /* Chinese Simplified */
1485 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1486 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1489 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1490 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1492 /* Chinese Traditional */
1493 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1494 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1498 inline static HKEY create_fonts_NT_registry_key(void)
1502 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1503 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1507 inline static HKEY create_fonts_9x_registry_key(void)
1511 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1512 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1516 inline static HKEY create_config_fonts_registry_key(void)
1520 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1521 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1525 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1527 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1528 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1529 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1530 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1533 static void update_font_info(void)
1538 UINT i, ansi_cp = 0, oem_cp = 0;
1539 LCID lcid = GetUserDefaultLCID();
1541 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) != ERROR_SUCCESS)
1545 if (RegQueryValueExA(hkey, "Locale", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1547 if (strtoul(buf, NULL, 16 ) == lcid) /* already set correctly */
1552 TRACE("updating registry, locale changed %s -> %08lx\n", debugstr_a(buf), lcid);
1554 else TRACE("updating registry, locale changed none -> %08lx\n", lcid);
1556 sprintf(buf, "%08lx", lcid);
1557 RegSetValueExA(hkey, "Locale", 0, REG_SZ, (const BYTE *)buf, strlen(buf)+1);
1560 GetLocaleInfoW(lcid, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1561 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1562 GetLocaleInfoW(lcid, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1563 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1565 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1567 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1568 nls_update_font_list[i].oem_cp == oem_cp)
1572 hkey = create_config_fonts_registry_key();
1573 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1574 RegSetValueExA(hkey, "FIXED.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1575 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1578 hkey = create_fonts_NT_registry_key();
1579 add_font_list(hkey, &nls_update_font_list[i]);
1582 hkey = create_fonts_9x_registry_key();
1583 add_font_list(hkey, &nls_update_font_list[i]);
1589 FIXME("there is no font defaults for lcid %04lx/ansi_cp %u", lcid, ansi_cp);
1592 /*************************************************************
1595 * Initialize FreeType library and create a list of available faces
1597 BOOL WineEngInit(void)
1599 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1600 static const WCHAR pathW[] = {'P','a','t','h',0};
1602 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1604 WCHAR windowsdir[MAX_PATH];
1607 const char *data_dir;
1611 /* update locale dependent font info in registry */
1614 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1617 "Wine cannot find the FreeType font library. To enable Wine to\n"
1618 "use TrueType fonts please install a version of FreeType greater than\n"
1619 "or equal to 2.0.5.\n"
1620 "http://www.freetype.org\n");
1624 #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;}
1626 LOAD_FUNCPTR(FT_Vector_Unit)
1627 LOAD_FUNCPTR(FT_Done_Face)
1628 LOAD_FUNCPTR(FT_Get_Char_Index)
1629 LOAD_FUNCPTR(FT_Get_Module)
1630 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1631 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1632 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1633 LOAD_FUNCPTR(FT_Init_FreeType)
1634 LOAD_FUNCPTR(FT_Load_Glyph)
1635 LOAD_FUNCPTR(FT_Matrix_Multiply)
1636 LOAD_FUNCPTR(FT_MulFix)
1637 LOAD_FUNCPTR(FT_New_Face)
1638 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1639 LOAD_FUNCPTR(FT_Outline_Transform)
1640 LOAD_FUNCPTR(FT_Outline_Translate)
1641 LOAD_FUNCPTR(FT_Select_Charmap)
1642 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1643 LOAD_FUNCPTR(FT_Vector_Transform)
1646 /* Don't warn if this one is missing */
1647 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1648 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1649 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1650 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
1651 #ifdef HAVE_FREETYPE_FTWINFNT_H
1652 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1654 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1655 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1656 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1657 <= 2.0.3 has FT_Sqrt64 */
1661 if(pFT_Init_FreeType(&library) != 0) {
1662 ERR("Can't init FreeType library\n");
1663 wine_dlclose(ft_handle, NULL, 0);
1667 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1668 if (pFT_Library_Version)
1670 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1672 if (FT_Version.major<=0)
1678 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1679 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1680 ((FT_Version.minor << 8) & 0x00ff00) |
1681 ((FT_Version.patch ) & 0x0000ff);
1683 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1684 ERR("Failed to create font mutex\n");
1687 WaitForSingleObject(font_mutex, INFINITE);
1689 /* load the system bitmap fonts */
1690 load_system_fonts();
1692 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1693 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1694 strcatW(windowsdir, fontsW);
1695 if((unixname = wine_get_unix_file_name(windowsdir)))
1697 ReadFontDir(unixname, FALSE);
1698 HeapFree(GetProcessHeap(), 0, unixname);
1701 /* load the system truetype fonts */
1702 data_dir = wine_get_data_dir();
1703 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
1704 strcpy(unixname, data_dir);
1705 strcat(unixname, "/fonts/");
1706 ReadFontDir(unixname, FALSE);
1707 HeapFree(GetProcessHeap(), 0, unixname);
1710 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1711 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1712 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1714 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1715 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1716 &hkey) == ERROR_SUCCESS) {
1718 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1719 &valuelen, &datalen, NULL, NULL);
1721 valuelen++; /* returned value doesn't include room for '\0' */
1722 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1723 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1726 dlen = datalen * sizeof(WCHAR);
1728 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1729 &dlen) == ERROR_SUCCESS) {
1730 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1732 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1734 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1735 HeapFree(GetProcessHeap(), 0, unixname);
1738 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1740 WCHAR pathW[MAX_PATH];
1741 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1744 sprintfW(pathW, fmtW, windowsdir, data);
1745 if((unixname = wine_get_unix_file_name(pathW)))
1747 added = AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1748 HeapFree(GetProcessHeap(), 0, unixname);
1751 load_font_from_data_dir(data);
1753 /* reset dlen and vlen */
1758 HeapFree(GetProcessHeap(), 0, data);
1759 HeapFree(GetProcessHeap(), 0, valueW);
1763 load_fontconfig_fonts();
1765 /* then look in any directories that we've specified in the config file */
1766 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
1767 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
1773 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
1775 len += sizeof(WCHAR);
1776 valueW = HeapAlloc( GetProcessHeap(), 0, len );
1777 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
1779 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
1780 valueA = HeapAlloc( GetProcessHeap(), 0, len );
1781 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
1782 TRACE( "got font path %s\n", debugstr_a(valueA) );
1786 LPSTR next = strchr( ptr, ':' );
1787 if (next) *next++ = 0;
1788 ReadFontDir( ptr, TRUE );
1791 HeapFree( GetProcessHeap(), 0, valueA );
1793 HeapFree( GetProcessHeap(), 0, valueW );
1802 update_reg_entries();
1804 init_system_links();
1806 ReleaseMutex(font_mutex);
1810 "Wine cannot find certain functions that it needs inside the FreeType\n"
1811 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1812 "FreeType to at least version 2.0.5.\n"
1813 "http://www.freetype.org\n");
1814 wine_dlclose(ft_handle, NULL, 0);
1820 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1823 TT_HoriHeader *pHori;
1827 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1828 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1830 if(height == 0) height = 16;
1832 /* Calc. height of EM square:
1834 * For +ve lfHeight we have
1835 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1836 * Re-arranging gives:
1837 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1839 * For -ve lfHeight we have
1841 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1842 * with il = winAscent + winDescent - units_per_em]
1847 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1848 ppem = ft_face->units_per_EM * height /
1849 (pHori->Ascender - pHori->Descender);
1851 ppem = ft_face->units_per_EM * height /
1852 (pOS2->usWinAscent + pOS2->usWinDescent);
1860 static LONG load_VDMX(GdiFont, LONG);
1862 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1867 TRACE("%s, %ld, %ld x %ld\n", debugstr_a(file), face_index, width, height);
1868 err = pFT_New_Face(library, file, face_index, &ft_face);
1870 ERR("FT_New_Face rets %d\n", err);
1874 /* set it here, as load_VDMX needs it */
1875 font->ft_face = ft_face;
1877 if(FT_IS_SCALABLE(ft_face)) {
1878 /* load the VDMX table if we have one */
1879 font->ppem = load_VDMX(font, height);
1881 font->ppem = calc_ppem_for_height(ft_face, height);
1883 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
1884 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, font->ppem, err);
1886 font->ppem = height;
1887 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1888 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1894 static int get_nearest_charset(Face *face, int *cp)
1896 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1897 a single face with the requested charset. The idea is to check if
1898 the selected font supports the current ANSI codepage, if it does
1899 return the corresponding charset, else return the first charset */
1902 int acp = GetACP(), i;
1906 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1907 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1908 return csi.ciCharset;
1910 for(i = 0; i < 32; i++) {
1912 if(face->fs.fsCsb[0] & fs0) {
1913 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
1915 return csi.ciCharset;
1918 FIXME("TCI failing on %lx\n", fs0);
1922 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1923 face->fs.fsCsb[0], face->file);
1925 return DEFAULT_CHARSET;
1928 static GdiFont alloc_font(void)
1930 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1931 ret->gmsize = INIT_GM_SIZE;
1932 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1933 ret->gmsize * sizeof(*ret->gm));
1935 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1936 list_init(&ret->hfontlist);
1937 list_init(&ret->child_fonts);
1941 static void free_font(GdiFont font)
1943 struct list *cursor, *cursor2;
1945 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
1947 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
1948 struct list *first_hfont;
1949 HFONTLIST *hfontlist;
1950 list_remove(cursor);
1953 first_hfont = list_head(&child->font->hfontlist);
1954 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
1955 DeleteObject(hfontlist->hfont);
1956 HeapFree(GetProcessHeap(), 0, hfontlist);
1957 free_font(child->font);
1959 HeapFree(GetProcessHeap(), 0, child->file_name);
1960 HeapFree(GetProcessHeap(), 0, child);
1963 if (font->ft_face) pFT_Done_Face(font->ft_face);
1964 HeapFree(GetProcessHeap(), 0, font->potm);
1965 HeapFree(GetProcessHeap(), 0, font->name);
1966 HeapFree(GetProcessHeap(), 0, font->gm);
1967 HeapFree(GetProcessHeap(), 0, font);
1971 /*************************************************************
1974 * load the vdmx entry for the specified height
1977 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1978 ( ( (FT_ULong)_x4 << 24 ) | \
1979 ( (FT_ULong)_x3 << 16 ) | \
1980 ( (FT_ULong)_x2 << 8 ) | \
1983 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1998 static LONG load_VDMX(GdiFont font, LONG height)
2002 BYTE devXRatio, devYRatio;
2003 USHORT numRecs, numRatios;
2004 DWORD result, offset = -1;
2008 /* For documentation on VDMX records, see
2009 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2012 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2014 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2017 /* FIXME: need the real device aspect ratio */
2021 numRecs = GET_BE_WORD(hdr[1]);
2022 numRatios = GET_BE_WORD(hdr[2]);
2024 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2025 for(i = 0; i < numRatios; i++) {
2028 offset = (3 * 2) + (i * sizeof(Ratios));
2029 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2032 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2034 if((ratio.xRatio == 0 &&
2035 ratio.yStartRatio == 0 &&
2036 ratio.yEndRatio == 0) ||
2037 (devXRatio == ratio.xRatio &&
2038 devYRatio >= ratio.yStartRatio &&
2039 devYRatio <= ratio.yEndRatio))
2041 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2042 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2043 offset = GET_BE_WORD(tmp);
2049 FIXME("No suitable ratio found\n");
2053 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2055 BYTE startsz, endsz;
2058 recs = GET_BE_WORD(group.recs);
2059 startsz = group.startsz;
2060 endsz = group.endsz;
2062 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2064 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2065 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2066 if(result == GDI_ERROR) {
2067 FIXME("Failed to retrieve vTable\n");
2072 for(i = 0; i < recs; i++) {
2073 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2074 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2075 ppem = GET_BE_WORD(vTable[i * 3]);
2077 if(yMax + -yMin == height) {
2080 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2083 if(yMax + -yMin > height) {
2086 goto end; /* failed */
2088 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2089 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2090 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2096 TRACE("ppem not found for height %ld\n", height);
2100 if(ppem < startsz || ppem > endsz)
2103 for(i = 0; i < recs; i++) {
2105 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2107 if(yPelHeight > ppem)
2110 if(yPelHeight == ppem) {
2111 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2112 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2113 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2119 HeapFree(GetProcessHeap(), 0, vTable);
2125 static BOOL fontcmp(GdiFont font, FONT_DESC *fd)
2127 if(font->font_desc.hash != fd->hash) return TRUE;
2128 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2129 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2130 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2133 static void calc_hash(FONT_DESC *pfd)
2135 DWORD hash = 0, *ptr, two_chars;
2139 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2141 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2143 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2145 pwc = (WCHAR *)&two_chars;
2147 *pwc = toupperW(*pwc);
2149 *pwc = toupperW(*pwc);
2157 static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2162 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2164 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2165 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2168 /* try the in-use list */
2169 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2170 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2171 if(!fontcmp(ret, &fd)) {
2172 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2173 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2174 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2175 if(hflist->hfont == hfont)
2178 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2179 hflist->hfont = hfont;
2180 list_add_head(&ret->hfontlist, &hflist->entry);
2185 /* then the unused list */
2186 font_elem_ptr = list_head(&unused_gdi_font_list);
2187 while(font_elem_ptr) {
2188 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2189 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2190 if(!fontcmp(ret, &fd)) {
2191 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2192 assert(list_empty(&ret->hfontlist));
2193 TRACE("Found %p in unused list\n", ret);
2194 list_remove(&ret->entry);
2195 list_add_head(&gdi_font_list, &ret->entry);
2196 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2197 hflist->hfont = hfont;
2198 list_add_head(&ret->hfontlist, &hflist->entry);
2206 /*************************************************************
2207 * create_child_font_list
2209 static BOOL create_child_font_list(GdiFont font)
2212 SYSTEM_LINKS *font_link;
2213 CHILD_FONT *font_link_entry, *new_child;
2215 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2217 if(!strcmpW(font_link->font_name, font->name))
2219 TRACE("found entry in system list\n");
2220 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2222 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2223 new_child->file_name = strdupA(font_link_entry->file_name);
2224 new_child->index = font_link_entry->index;
2225 new_child->font = NULL;
2226 list_add_tail(&font->child_fonts, &new_child->entry);
2227 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
2237 /*************************************************************
2238 * WineEngCreateFontInstance
2241 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2245 Family *family, *last_resort_family;
2246 struct list *family_elem_ptr, *face_elem_ptr;
2247 INT height, width = 0;
2248 signed int diff = 0, newdiff;
2249 BOOL bd, it, can_use_bitmap;
2254 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2256 struct list *first_hfont = list_head(&ret->hfontlist);
2257 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2258 if(hflist->hfont == hfont)
2262 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2263 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2265 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
2266 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2267 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2270 /* check the cache first */
2271 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2272 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2276 TRACE("not in cache\n");
2277 if(list_empty(&font_list)) /* No fonts installed */
2279 TRACE("No fonts installed\n");
2282 if(!have_installed_roman_font)
2284 TRACE("No roman font installed\n");
2290 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2291 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2292 calc_hash(&ret->font_desc);
2293 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2294 hflist->hfont = hfont;
2295 list_add_head(&ret->hfontlist, &hflist->entry);
2298 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2299 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2300 original value lfCharSet. Note this is a special case for
2301 Symbol and doesn't happen at least for "Wingdings*" */
2303 if(!strcmpiW(lf.lfFaceName, SymbolW))
2304 lf.lfCharSet = SYMBOL_CHARSET;
2306 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2307 switch(lf.lfCharSet) {
2308 case DEFAULT_CHARSET:
2309 csi.fs.fsCsb[0] = 0;
2312 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2313 csi.fs.fsCsb[0] = 0;
2319 if(lf.lfFaceName[0] != '\0') {
2321 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2324 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2325 debugstr_w(psub->to.name));
2326 strcpyW(lf.lfFaceName, psub->to.name);
2329 /* We want a match on name and charset or just name if
2330 charset was DEFAULT_CHARSET. If the latter then
2331 we fixup the returned charset later in get_nearest_charset
2332 where we'll either use the charset of the current ansi codepage
2333 or if that's unavailable the first charset that the font supports.
2335 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2336 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2337 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2338 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2339 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2340 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2341 if(face->scalable || can_use_bitmap)
2348 /* If requested charset was DEFAULT_CHARSET then try using charset
2349 corresponding to the current ansi codepage */
2350 if(!csi.fs.fsCsb[0]) {
2352 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
2353 FIXME("TCI failed on codepage %d\n", acp);
2354 csi.fs.fsCsb[0] = 0;
2356 lf.lfCharSet = csi.ciCharset;
2359 /* Face families are in the top 4 bits of lfPitchAndFamily,
2360 so mask with 0xF0 before testing */
2362 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2363 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2364 strcpyW(lf.lfFaceName, defFixed);
2365 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2366 strcpyW(lf.lfFaceName, defSerif);
2367 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2368 strcpyW(lf.lfFaceName, defSans);
2370 strcpyW(lf.lfFaceName, defSans);
2371 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2372 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2373 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2374 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2375 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2376 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2377 if(face->scalable || can_use_bitmap)
2383 last_resort_family = NULL;
2384 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2385 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2386 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2387 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2388 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2391 if(can_use_bitmap && !last_resort_family)
2392 last_resort_family = family;
2397 if(last_resort_family) {
2398 family = last_resort_family;
2399 csi.fs.fsCsb[0] = 0;
2403 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2404 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2405 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2406 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2407 if(face->scalable) {
2408 csi.fs.fsCsb[0] = 0;
2409 FIXME("just using first face for now\n");
2412 if(can_use_bitmap && !last_resort_family)
2413 last_resort_family = family;
2416 if(!last_resort_family) {
2417 FIXME("can't find a single appropriate font - bailing\n");
2422 WARN("could only find a bitmap font - this will probably look awful!\n");
2423 family = last_resort_family;
2424 csi.fs.fsCsb[0] = 0;
2427 it = lf.lfItalic ? 1 : 0;
2428 bd = lf.lfWeight > 550 ? 1 : 0;
2430 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2431 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2434 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2435 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2436 if(!(face->Italic ^ it) && !(face->Bold ^ bd) &&
2437 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])) {
2441 newdiff = height - (signed int)(face->size.y_ppem >> 6);
2443 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
2444 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
2445 (diff < 0 && newdiff > diff)) {
2446 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
2459 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2460 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2461 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]) {
2465 newdiff = height - (signed int)(face->size.y_ppem >> 6);
2467 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
2468 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
2469 (diff < 0 && newdiff > diff)) {
2470 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
2481 if(it && !face->Italic) ret->fake_italic = TRUE;
2482 if(bd && !face->Bold) ret->fake_bold = TRUE;
2485 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2487 if(csi.fs.fsCsb[0]) {
2488 ret->charset = lf.lfCharSet;
2489 ret->codepage = csi.ciACP;
2492 ret->charset = get_nearest_charset(face, &ret->codepage);
2494 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2495 debugstr_w(face->StyleName), face->file, face->face_index);
2497 if(!face->scalable) {
2498 width = face->size.x_ppem >> 6;
2499 height = face->size.y_ppem >> 6;
2501 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2509 if (ret->charset == SYMBOL_CHARSET &&
2510 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2513 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2517 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2520 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2521 ret->name = strdupW(family->FamilyName);
2522 ret->underline = lf.lfUnderline ? 0xff : 0;
2523 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2524 create_child_font_list(ret);
2526 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2528 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
2529 list_add_head(&gdi_font_list, &ret->entry);
2533 static void dump_gdi_font_list(void)
2536 struct list *elem_ptr;
2538 TRACE("---------- gdiFont Cache ----------\n");
2539 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2540 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2541 TRACE("gdiFont=%p %s %ld\n",
2542 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2545 TRACE("---------- Unused gdiFont Cache ----------\n");
2546 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2547 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2548 TRACE("gdiFont=%p %s %ld\n",
2549 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2553 /*************************************************************
2554 * WineEngDestroyFontInstance
2556 * free the gdiFont associated with this handle
2559 BOOL WineEngDestroyFontInstance(HFONT handle)
2564 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2567 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
2569 struct list *first_hfont = list_head(&gdiFont->hfontlist);
2570 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2571 if(hflist->hfont == handle)
2573 TRACE("removing child font %p from child list\n", gdiFont);
2574 list_remove(&gdiFont->entry);
2579 TRACE("destroying hfont=%p\n", handle);
2581 dump_gdi_font_list();
2583 font_elem_ptr = list_head(&gdi_font_list);
2584 while(font_elem_ptr) {
2585 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2586 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
2588 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
2589 while(hfontlist_elem_ptr) {
2590 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2591 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
2592 if(hflist->hfont == handle) {
2593 list_remove(&hflist->entry);
2594 HeapFree(GetProcessHeap(), 0, hflist);
2598 if(list_empty(&gdiFont->hfontlist)) {
2599 TRACE("Moving to Unused list\n");
2600 list_remove(&gdiFont->entry);
2601 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
2606 font_elem_ptr = list_head(&unused_gdi_font_list);
2607 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
2608 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2609 while(font_elem_ptr) {
2610 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2611 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2612 TRACE("freeing %p\n", gdiFont);
2613 list_remove(&gdiFont->entry);
2619 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2620 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
2622 OUTLINETEXTMETRICW *potm = NULL;
2624 TEXTMETRICW tm, *ptm;
2625 GdiFont font = alloc_font();
2628 if(face->scalable) {
2632 height = face->size.y_ppem >> 6;
2633 width = face->size.x_ppem >> 6;
2636 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
2642 font->name = strdupW(face->family->FamilyName);
2644 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
2646 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
2648 potm = HeapAlloc(GetProcessHeap(), 0, size);
2649 WineEngGetOutlineTextMetrics(font, size, potm);
2650 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
2652 WineEngGetTextMetrics(font, &tm);
2656 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
2657 pntm->ntmTm.tmAscent = ptm->tmAscent;
2658 pntm->ntmTm.tmDescent = ptm->tmDescent;
2659 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
2660 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
2661 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
2662 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
2663 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
2664 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
2665 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
2666 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
2667 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
2668 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
2669 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
2670 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
2671 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
2672 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
2673 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
2674 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
2675 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
2676 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
2677 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2678 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2679 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
2681 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
2682 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
2683 *ptype |= RASTER_FONTTYPE;
2685 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2686 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2687 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2689 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
2690 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
2691 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2694 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
2696 lstrcpynW(pelf->elfLogFont.lfFaceName,
2697 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
2699 lstrcpynW(pelf->elfFullName,
2700 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
2702 lstrcpynW(pelf->elfStyle,
2703 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2706 HeapFree(GetProcessHeap(), 0, potm);
2708 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
2710 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2711 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2712 pelf->elfStyle[0] = '\0';
2715 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2720 /*************************************************************
2724 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2728 struct list *family_elem_ptr, *face_elem_ptr;
2730 NEWTEXTMETRICEXW ntm;
2731 DWORD type, ret = 1;
2737 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2739 if(plf->lfFaceName[0]) {
2741 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
2744 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2745 debugstr_w(psub->to.name));
2746 memcpy(&lf, plf, sizeof(lf));
2747 strcpyW(lf.lfFaceName, psub->to.name);
2751 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2752 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2753 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2754 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2755 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2756 GetEnumStructs(face, &elf, &ntm, &type);
2757 for(i = 0; i < 32; i++) {
2758 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2759 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2760 strcpyW(elf.elfScript, OEM_DOSW);
2761 i = 32; /* break out of loop */
2762 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2765 fs.fsCsb[0] = 1L << i;
2767 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2769 csi.ciCharset = DEFAULT_CHARSET;
2770 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2771 if(csi.ciCharset != DEFAULT_CHARSET) {
2772 elf.elfLogFont.lfCharSet =
2773 ntm.ntmTm.tmCharSet = csi.ciCharset;
2775 strcpyW(elf.elfScript, ElfScriptsW[i]);
2777 FIXME("Unknown elfscript for bit %d\n", i);
2780 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2781 debugstr_w(elf.elfLogFont.lfFaceName),
2782 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2783 csi.ciCharset, type, debugstr_w(elf.elfScript),
2784 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2785 ntm.ntmTm.ntmFlags);
2786 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2793 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2794 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2795 face_elem_ptr = list_head(&family->faces);
2796 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2797 GetEnumStructs(face, &elf, &ntm, &type);
2798 for(i = 0; i < 32; i++) {
2799 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2800 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2801 strcpyW(elf.elfScript, OEM_DOSW);
2802 i = 32; /* break out of loop */
2803 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2806 fs.fsCsb[0] = 1L << i;
2808 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2810 csi.ciCharset = DEFAULT_CHARSET;
2811 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2812 if(csi.ciCharset != DEFAULT_CHARSET) {
2813 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2816 strcpyW(elf.elfScript, ElfScriptsW[i]);
2818 FIXME("Unknown elfscript for bit %d\n", i);
2821 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2822 debugstr_w(elf.elfLogFont.lfFaceName),
2823 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2824 csi.ciCharset, type, debugstr_w(elf.elfScript),
2825 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2826 ntm.ntmTm.ntmFlags);
2827 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2836 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2838 pt->x.value = vec->x >> 6;
2839 pt->x.fract = (vec->x & 0x3f) << 10;
2840 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2841 pt->y.value = vec->y >> 6;
2842 pt->y.fract = (vec->y & 0x3f) << 10;
2843 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2847 /***************************************************
2848 * According to the MSDN documentation on WideCharToMultiByte,
2849 * certain codepages cannot set the default_used parameter.
2850 * This returns TRUE if the codepage can set that parameter, false else
2851 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
2853 static BOOL codepage_sets_default_used(UINT codepage)
2866 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2868 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
2869 WCHAR wc = (WCHAR)glyph;
2871 BOOL *default_used_pointer;
2874 default_used_pointer = NULL;
2875 default_used = FALSE;
2876 if (codepage_sets_default_used(font->codepage))
2877 default_used_pointer = &default_used;
2878 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
2881 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
2882 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
2886 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2887 glyph = glyph + 0xf000;
2888 return pFT_Get_Char_Index(font->ft_face, glyph);
2891 /*************************************************************
2892 * WineEngGetGlyphIndices
2894 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2896 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2897 LPWORD pgi, DWORD flags)
2901 for(i = 0; i < count; i++)
2902 pgi[i] = get_glyph_index(font, lpstr[i]);
2907 /*************************************************************
2908 * WineEngGetGlyphOutline
2910 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2911 * except that the first parameter is the HWINEENGFONT of the font in
2912 * question rather than an HDC.
2915 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2916 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2919 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2920 FT_Face ft_face = font->ft_face;
2921 FT_UInt glyph_index;
2922 DWORD width, height, pitch, needed = 0;
2923 FT_Bitmap ft_bitmap;
2925 INT left, right, top = 0, bottom = 0;
2927 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2928 float widthRatio = 1.0;
2929 FT_Matrix transMat = identityMat;
2930 BOOL needsTransform = FALSE;
2933 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2934 buflen, buf, lpmat);
2936 if(format & GGO_GLYPH_INDEX) {
2937 glyph_index = glyph;
2938 format &= ~GGO_GLYPH_INDEX;
2940 glyph_index = get_glyph_index(font, glyph);
2942 if(glyph_index >= font->gmsize) {
2943 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2944 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2945 font->gmsize * sizeof(*font->gm));
2947 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2948 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2949 return 1; /* FIXME */
2953 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2954 load_flags |= FT_LOAD_NO_BITMAP;
2956 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2959 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2963 /* Scaling factor */
2964 if (font->aveWidth && font->potm) {
2965 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2968 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2969 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2971 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2972 font->gm[glyph_index].lsb = left >> 6;
2973 font->gm[glyph_index].bbx = (right - left) >> 6;
2975 /* Scaling transform */
2976 if(font->aveWidth) {
2978 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2981 scaleMat.yy = (1 << 16);
2983 pFT_Matrix_Multiply(&scaleMat, &transMat);
2984 needsTransform = TRUE;
2987 /* Slant transform */
2988 if (font->fake_italic) {
2991 slantMat.xx = (1 << 16);
2992 slantMat.xy = ((1 << 16) >> 2);
2994 slantMat.yy = (1 << 16);
2995 pFT_Matrix_Multiply(&slantMat, &transMat);
2996 needsTransform = TRUE;
2999 /* Rotation transform */
3000 if(font->orientation) {
3001 FT_Matrix rotationMat;
3003 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3004 pFT_Vector_Unit(&vecAngle, angle);
3005 rotationMat.xx = vecAngle.x;
3006 rotationMat.xy = -vecAngle.y;
3007 rotationMat.yx = -rotationMat.xy;
3008 rotationMat.yy = rotationMat.xx;
3010 pFT_Matrix_Multiply(&rotationMat, &transMat);
3011 needsTransform = TRUE;
3014 /* Extra transformation specified by caller */
3017 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3018 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3019 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3020 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3021 pFT_Matrix_Multiply(&extraMat, &transMat);
3022 needsTransform = TRUE;
3025 if(!needsTransform) {
3026 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3027 bottom = (ft_face->glyph->metrics.horiBearingY -
3028 ft_face->glyph->metrics.height) & -64;
3029 lpgm->gmCellIncX = font->gm[glyph_index].adv;
3030 lpgm->gmCellIncY = 0;
3034 for(xc = 0; xc < 2; xc++) {
3035 for(yc = 0; yc < 2; yc++) {
3036 vec.x = (ft_face->glyph->metrics.horiBearingX +
3037 xc * ft_face->glyph->metrics.width);
3038 vec.y = ft_face->glyph->metrics.horiBearingY -
3039 yc * ft_face->glyph->metrics.height;
3040 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3041 pFT_Vector_Transform(&vec, &transMat);
3042 if(xc == 0 && yc == 0) {
3043 left = right = vec.x;
3044 top = bottom = vec.y;
3046 if(vec.x < left) left = vec.x;
3047 else if(vec.x > right) right = vec.x;
3048 if(vec.y < bottom) bottom = vec.y;
3049 else if(vec.y > top) top = vec.y;
3054 right = (right + 63) & -64;
3055 bottom = bottom & -64;
3056 top = (top + 63) & -64;
3058 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3059 vec.x = ft_face->glyph->metrics.horiAdvance;
3061 pFT_Vector_Transform(&vec, &transMat);
3062 lpgm->gmCellIncX = (vec.x+63) >> 6;
3063 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3065 lpgm->gmBlackBoxX = (right - left) >> 6;
3066 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3067 lpgm->gmptGlyphOrigin.x = left >> 6;
3068 lpgm->gmptGlyphOrigin.y = top >> 6;
3070 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
3071 font->gm[glyph_index].init = TRUE;
3073 if(format == GGO_METRICS)
3074 return 1; /* FIXME */
3076 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
3077 TRACE("loaded a bitmap\n");
3083 width = lpgm->gmBlackBoxX;
3084 height = lpgm->gmBlackBoxY;
3085 pitch = ((width + 31) >> 5) << 2;
3086 needed = pitch * height;
3088 if(!buf || !buflen) break;
3090 switch(ft_face->glyph->format) {
3091 case ft_glyph_format_bitmap:
3093 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3094 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3095 INT h = ft_face->glyph->bitmap.rows;
3097 memcpy(dst, src, w);
3098 src += ft_face->glyph->bitmap.pitch;
3104 case ft_glyph_format_outline:
3105 ft_bitmap.width = width;
3106 ft_bitmap.rows = height;
3107 ft_bitmap.pitch = pitch;
3108 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3109 ft_bitmap.buffer = buf;
3111 if(needsTransform) {
3112 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3115 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3117 /* Note: FreeType will only set 'black' bits for us. */
3118 memset(buf, 0, needed);
3119 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3123 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3128 case GGO_GRAY2_BITMAP:
3129 case GGO_GRAY4_BITMAP:
3130 case GGO_GRAY8_BITMAP:
3131 case WINE_GGO_GRAY16_BITMAP:
3133 unsigned int mult, row, col;
3136 width = lpgm->gmBlackBoxX;
3137 height = lpgm->gmBlackBoxY;
3138 pitch = (width + 3) / 4 * 4;
3139 needed = pitch * height;
3141 if(!buf || !buflen) break;
3142 ft_bitmap.width = width;
3143 ft_bitmap.rows = height;
3144 ft_bitmap.pitch = pitch;
3145 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3146 ft_bitmap.buffer = buf;
3148 if(needsTransform) {
3149 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3152 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3154 memset(ft_bitmap.buffer, 0, buflen);
3156 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3158 if(format == GGO_GRAY2_BITMAP)
3160 else if(format == GGO_GRAY4_BITMAP)
3162 else if(format == GGO_GRAY8_BITMAP)
3164 else if(format == WINE_GGO_GRAY16_BITMAP)
3172 for(row = 0; row < height; row++) {
3174 for(col = 0; col < width; col++, ptr++) {
3175 *ptr = (((int)*ptr) * mult + 128) / 256;
3184 int contour, point = 0, first_pt;
3185 FT_Outline *outline = &ft_face->glyph->outline;
3186 TTPOLYGONHEADER *pph;
3188 DWORD pph_start, cpfx, type;
3190 if(buflen == 0) buf = NULL;
3192 if (needsTransform && buf) {
3193 pFT_Outline_Transform(outline, &transMat);
3196 for(contour = 0; contour < outline->n_contours; contour++) {
3198 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3201 pph->dwType = TT_POLYGON_TYPE;
3202 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3204 needed += sizeof(*pph);
3206 while(point <= outline->contours[contour]) {
3207 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3208 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3209 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3213 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3216 } while(point <= outline->contours[contour] &&
3217 (outline->tags[point] & FT_Curve_Tag_On) ==
3218 (outline->tags[point-1] & FT_Curve_Tag_On));
3219 /* At the end of a contour Windows adds the start point, but
3221 if(point > outline->contours[contour] &&
3222 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3224 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3226 } else if(point <= outline->contours[contour] &&
3227 outline->tags[point] & FT_Curve_Tag_On) {
3228 /* add closing pt for bezier */
3230 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3238 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3241 pph->cb = needed - pph_start;
3247 /* Convert the quadratic Beziers to cubic Beziers.
3248 The parametric eqn for a cubic Bezier is, from PLRM:
3249 r(t) = at^3 + bt^2 + ct + r0
3250 with the control points:
3255 A quadratic Beizer has the form:
3256 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3258 So equating powers of t leads to:
3259 r1 = 2/3 p1 + 1/3 p0
3260 r2 = 2/3 p1 + 1/3 p2
3261 and of course r0 = p0, r3 = p2
3264 int contour, point = 0, first_pt;
3265 FT_Outline *outline = &ft_face->glyph->outline;
3266 TTPOLYGONHEADER *pph;
3268 DWORD pph_start, cpfx, type;
3269 FT_Vector cubic_control[4];
3270 if(buflen == 0) buf = NULL;
3272 if (needsTransform && buf) {
3273 pFT_Outline_Transform(outline, &transMat);
3276 for(contour = 0; contour < outline->n_contours; contour++) {
3278 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3281 pph->dwType = TT_POLYGON_TYPE;
3282 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3284 needed += sizeof(*pph);
3286 while(point <= outline->contours[contour]) {
3287 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3288 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3289 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3292 if(type == TT_PRIM_LINE) {
3294 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3298 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3301 /* FIXME: Possible optimization in endpoint calculation
3302 if there are two consecutive curves */
3303 cubic_control[0] = outline->points[point-1];
3304 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3305 cubic_control[0].x += outline->points[point].x + 1;
3306 cubic_control[0].y += outline->points[point].y + 1;
3307 cubic_control[0].x >>= 1;
3308 cubic_control[0].y >>= 1;
3310 if(point+1 > outline->contours[contour])
3311 cubic_control[3] = outline->points[first_pt];
3313 cubic_control[3] = outline->points[point+1];
3314 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3315 cubic_control[3].x += outline->points[point].x + 1;
3316 cubic_control[3].y += outline->points[point].y + 1;
3317 cubic_control[3].x >>= 1;
3318 cubic_control[3].y >>= 1;
3321 /* r1 = 1/3 p0 + 2/3 p1
3322 r2 = 1/3 p2 + 2/3 p1 */
3323 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3324 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3325 cubic_control[2] = cubic_control[1];
3326 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3327 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3328 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3329 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3331 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3332 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3333 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3338 } while(point <= outline->contours[contour] &&
3339 (outline->tags[point] & FT_Curve_Tag_On) ==
3340 (outline->tags[point-1] & FT_Curve_Tag_On));
3341 /* At the end of a contour Windows adds the start point,
3342 but only for Beziers and we've already done that.
3344 if(point <= outline->contours[contour] &&
3345 outline->tags[point] & FT_Curve_Tag_On) {
3346 /* This is the closing pt of a bezier, but we've already
3347 added it, so just inc point and carry on */
3354 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3357 pph->cb = needed - pph_start;
3363 FIXME("Unsupported format %d\n", format);
3369 static BOOL get_bitmap_text_metrics(GdiFont font)
3371 FT_Face ft_face = font->ft_face;
3372 #ifdef HAVE_FREETYPE_FTWINFNT_H
3373 FT_WinFNT_HeaderRec winfnt_header;
3375 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3376 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3377 font->potm->otmSize = size;
3379 #define TM font->potm->otmTextMetrics
3380 #ifdef HAVE_FREETYPE_FTWINFNT_H
3381 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3383 TM.tmHeight = winfnt_header.pixel_height;
3384 TM.tmAscent = winfnt_header.ascent;
3385 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3386 TM.tmInternalLeading = winfnt_header.internal_leading;
3387 TM.tmExternalLeading = winfnt_header.external_leading;
3388 TM.tmAveCharWidth = winfnt_header.avg_width;
3389 TM.tmMaxCharWidth = winfnt_header.max_width;
3390 TM.tmWeight = winfnt_header.weight;
3392 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3393 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3394 TM.tmFirstChar = winfnt_header.first_char;
3395 TM.tmLastChar = winfnt_header.last_char;
3396 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3397 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3398 TM.tmItalic = winfnt_header.italic;
3399 TM.tmUnderlined = font->underline;
3400 TM.tmStruckOut = font->strikeout;
3401 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3402 TM.tmCharSet = winfnt_header.charset;
3407 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3408 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3409 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3410 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3411 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3412 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3413 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3414 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3416 TM.tmDigitizedAspectX = 96; /* FIXME */
3417 TM.tmDigitizedAspectY = 96; /* FIXME */
3419 TM.tmLastChar = 255;
3420 TM.tmDefaultChar = 32;
3421 TM.tmBreakChar = 32;
3422 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3423 TM.tmUnderlined = font->underline;
3424 TM.tmStruckOut = font->strikeout;
3425 /* NB inverted meaning of TMPF_FIXED_PITCH */
3426 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3427 TM.tmCharSet = font->charset;
3434 /*************************************************************
3435 * WineEngGetTextMetrics
3438 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3441 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3442 if(!get_bitmap_text_metrics(font))
3445 if(!font->potm) return FALSE;
3446 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3448 if (font->aveWidth) {
3449 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3455 /*************************************************************
3456 * WineEngGetOutlineTextMetrics
3459 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3460 OUTLINETEXTMETRICW *potm)
3462 FT_Face ft_face = font->ft_face;
3463 UINT needed, lenfam, lensty, ret;
3465 TT_HoriHeader *pHori;
3466 TT_Postscript *pPost;
3467 FT_Fixed x_scale, y_scale;
3468 WCHAR *family_nameW, *style_nameW;
3469 static const WCHAR spaceW[] = {' ', '\0'};
3471 INT ascent, descent;
3473 TRACE("font=%p\n", font);
3475 if(!FT_IS_SCALABLE(ft_face))
3479 if(cbSize >= font->potm->otmSize)
3480 memcpy(potm, font->potm, font->potm->otmSize);
3481 return font->potm->otmSize;
3485 needed = sizeof(*potm);
3487 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3488 family_nameW = strdupW(font->name);
3490 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3492 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3493 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3494 style_nameW, lensty/sizeof(WCHAR));
3496 /* These names should be read from the TT name table */
3498 /* length of otmpFamilyName */
3501 /* length of otmpFaceName */
3502 if(!strcasecmp(ft_face->style_name, "regular")) {
3503 needed += lenfam; /* just the family name */
3505 needed += lenfam + lensty; /* family + " " + style */
3508 /* length of otmpStyleName */
3511 /* length of otmpFullName */
3512 needed += lenfam + lensty;
3515 x_scale = ft_face->size->metrics.x_scale;
3516 y_scale = ft_face->size->metrics.y_scale;
3518 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3520 FIXME("Can't find OS/2 table - not TT font?\n");
3525 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3527 FIXME("Can't find HHEA table - not TT font?\n");
3532 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3534 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",
3535 pOS2->usWinAscent, pOS2->usWinDescent,
3536 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3537 ft_face->ascender, ft_face->descender, ft_face->height,
3538 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3539 ft_face->bbox.yMax, ft_face->bbox.yMin);
3541 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3542 font->potm->otmSize = needed;
3544 #define TM font->potm->otmTextMetrics
3546 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3547 ascent = pHori->Ascender;
3548 descent = -pHori->Descender;
3550 ascent = pOS2->usWinAscent;
3551 descent = pOS2->usWinDescent;
3555 TM.tmAscent = font->yMax;
3556 TM.tmDescent = -font->yMin;
3557 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3559 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
3560 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
3561 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
3562 - ft_face->units_per_EM, y_scale) + 32) >> 6;
3565 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3568 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3570 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
3571 ((ascent + descent) -
3572 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
3574 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
3575 if (TM.tmAveCharWidth == 0) {
3576 TM.tmAveCharWidth = 1;
3578 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
3579 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
3581 TM.tmDigitizedAspectX = 300;
3582 TM.tmDigitizedAspectY = 300;
3583 TM.tmFirstChar = pOS2->usFirstCharIndex;
3584 TM.tmLastChar = pOS2->usLastCharIndex;
3585 TM.tmDefaultChar = pOS2->usDefaultChar;
3586 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
3587 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3588 TM.tmUnderlined = font->underline;
3589 TM.tmStruckOut = font->strikeout;
3591 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3592 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3593 (pOS2->version == 0xFFFFU ||
3594 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3595 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3597 TM.tmPitchAndFamily = 0;
3599 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
3600 case PAN_FAMILY_SCRIPT:
3601 TM.tmPitchAndFamily |= FF_SCRIPT;
3603 case PAN_FAMILY_DECORATIVE:
3604 case PAN_FAMILY_PICTORIAL:
3605 TM.tmPitchAndFamily |= FF_DECORATIVE;
3607 case PAN_FAMILY_TEXT_DISPLAY:
3608 if(TM.tmPitchAndFamily == 0) /* fixed */
3609 TM.tmPitchAndFamily = FF_MODERN;
3611 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
3612 case PAN_SERIF_NORMAL_SANS:
3613 case PAN_SERIF_OBTUSE_SANS:
3614 case PAN_SERIF_PERP_SANS:
3615 TM.tmPitchAndFamily |= FF_SWISS;
3618 TM.tmPitchAndFamily |= FF_ROMAN;
3623 TM.tmPitchAndFamily |= FF_DONTCARE;
3626 if(FT_IS_SCALABLE(ft_face))
3627 TM.tmPitchAndFamily |= TMPF_VECTOR;
3628 if(FT_IS_SFNT(ft_face))
3629 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3631 TM.tmCharSet = font->charset;
3634 font->potm->otmFiller = 0;
3635 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3636 font->potm->otmfsSelection = pOS2->fsSelection;
3637 font->potm->otmfsType = pOS2->fsType;
3638 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
3639 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
3640 font->potm->otmItalicAngle = 0; /* POST table */
3641 font->potm->otmEMSquare = ft_face->units_per_EM;
3642 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
3643 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
3644 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
3645 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
3646 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
3647 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
3648 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
3649 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
3650 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
3651 font->potm->otmMacAscent = 0; /* where do these come from ? */
3652 font->potm->otmMacDescent = 0;
3653 font->potm->otmMacLineGap = 0;
3654 font->potm->otmusMinimumPPEM = 0; /* TT Header */
3655 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
3656 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
3657 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
3658 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
3659 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
3660 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
3661 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
3662 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
3663 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
3664 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
3666 font->potm->otmsUnderscoreSize = 0;
3667 font->potm->otmsUnderscorePosition = 0;
3669 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
3670 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
3673 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
3674 cp = (char*)font->potm + sizeof(*font->potm);
3675 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
3676 strcpyW((WCHAR*)cp, family_nameW);
3678 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
3679 strcpyW((WCHAR*)cp, style_nameW);
3681 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
3682 strcpyW((WCHAR*)cp, family_nameW);
3683 if(strcasecmp(ft_face->style_name, "regular")) {
3684 strcatW((WCHAR*)cp, spaceW);
3685 strcatW((WCHAR*)cp, style_nameW);
3686 cp += lenfam + lensty;
3689 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
3690 strcpyW((WCHAR*)cp, family_nameW);
3691 strcatW((WCHAR*)cp, spaceW);
3692 strcatW((WCHAR*)cp, style_nameW);
3695 if(potm && needed <= cbSize)
3696 memcpy(potm, font->potm, font->potm->otmSize);
3699 HeapFree(GetProcessHeap(), 0, style_nameW);
3700 HeapFree(GetProcessHeap(), 0, family_nameW);
3705 static BOOL load_child_font(GdiFont font, CHILD_FONT *child)
3707 HFONTLIST *hfontlist;
3708 child->font = alloc_font();
3709 child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem);
3710 if(!child->font->ft_face)
3712 free_font(child->font);
3717 child->font->orientation = font->orientation;
3718 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
3719 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
3720 list_add_head(&child->font->hfontlist, &hfontlist->entry);
3721 child->font->base_font = font;
3722 list_add_head(&child_font_list, &child->font->entry);
3723 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
3727 static BOOL get_glyph_index_linked(GdiFont font, UINT c, GdiFont *linked_font, FT_UInt *glyph)
3730 CHILD_FONT *child_font;
3733 font = font->base_font;
3735 *linked_font = font;
3737 if((*glyph = get_glyph_index(font, c)))
3740 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
3742 if(!child_font->font)
3743 if(!load_child_font(font, child_font))
3746 if(!child_font->font->ft_face)
3748 g = get_glyph_index(child_font->font, c);
3752 *linked_font = child_font->font;
3759 /*************************************************************
3760 * WineEngGetCharWidth
3763 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3768 FT_UInt glyph_index;
3769 GdiFont linked_font;
3771 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3773 for(c = firstChar; c <= lastChar; c++) {
3774 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3775 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3776 &gm, 0, NULL, NULL);
3777 buffer[c - firstChar] = linked_font->gm[glyph_index].adv;
3782 /*************************************************************
3783 * WineEngGetCharABCWidths
3786 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3791 FT_UInt glyph_index;
3792 GdiFont linked_font;
3794 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3796 if(!FT_IS_SCALABLE(font->ft_face))
3799 for(c = firstChar; c <= lastChar; c++) {
3800 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
3801 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3802 &gm, 0, NULL, NULL);
3803 buffer[c - firstChar].abcA = linked_font->gm[glyph_index].lsb;
3804 buffer[c - firstChar].abcB = linked_font->gm[glyph_index].bbx;
3805 buffer[c - firstChar].abcC = linked_font->gm[glyph_index].adv - linked_font->gm[glyph_index].lsb -
3806 linked_font->gm[glyph_index].bbx;
3811 /*************************************************************
3812 * WineEngGetTextExtentPoint
3815 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3821 FT_UInt glyph_index;
3822 GdiFont linked_font;
3824 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
3828 WineEngGetTextMetrics(font, &tm);
3829 size->cy = tm.tmHeight;
3831 for(idx = 0; idx < count; idx++) {
3832 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
3833 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3834 &gm, 0, NULL, NULL);
3835 size->cx += linked_font->gm[glyph_index].adv;
3837 TRACE("return %ld,%ld\n", size->cx, size->cy);
3841 /*************************************************************
3842 * WineEngGetTextExtentPointI
3845 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3852 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3855 WineEngGetTextMetrics(font, &tm);
3856 size->cy = tm.tmHeight;
3858 for(idx = 0; idx < count; idx++) {
3859 WineEngGetGlyphOutline(font, indices[idx],
3860 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3862 size->cx += font->gm[indices[idx]].adv;
3864 TRACE("return %ld,%ld\n", size->cx, size->cy);
3868 /*************************************************************
3869 * WineEngGetFontData
3872 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3875 FT_Face ft_face = font->ft_face;
3879 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3880 font, table, offset, buf, cbData);
3882 if(!FT_IS_SFNT(ft_face))
3890 if(table) { /* MS tags differ in endidness from FT ones */
3891 table = table >> 24 | table << 24 |
3892 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3895 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3896 if(pFT_Load_Sfnt_Table) {
3897 /* make sure value of len is the value freetype says it needs */
3900 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3901 if( !err && needed < len) len = needed;
3903 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3905 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
3906 else { /* Do it the hard way */
3907 TT_Face tt_face = (TT_Face) ft_face;
3908 SFNT_Interface *sfnt;
3909 if (FT_Version.major==2 && FT_Version.minor==0)
3912 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3916 /* A field was added in the middle of the structure in 2.1.x */
3917 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3919 /* make sure value of len is the value freetype says it needs */
3922 err = sfnt->load_any(tt_face, table, offset, NULL, &needed);
3923 if( !err && needed < len) len = needed;
3925 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3931 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
3932 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
3933 "Please upgrade your freetype library.\n");
3936 err = FT_Err_Unimplemented_Feature;
3940 TRACE("Can't find table %08lx.\n", table);
3946 /*************************************************************
3947 * WineEngGetTextFace
3950 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3953 lstrcpynW(str, font->name, count);
3954 return strlenW(font->name);
3956 return strlenW(font->name) + 1;
3959 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3961 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
3962 return font->charset;
3965 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
3967 GdiFont font = dc->gdiFont, linked_font;
3968 struct list *first_hfont;
3971 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
3972 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
3973 if(font == linked_font)
3974 *new_hfont = dc->hFont;
3977 first_hfont = list_head(&linked_font->hfontlist);
3978 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
3985 /*************************************************************
3988 BOOL WINAPI FontIsLinked(HDC hdc)
3990 DC *dc = DC_GetDCPtr(hdc);
3993 if(!dc) return FALSE;
3994 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
3996 GDI_ReleaseObj(hdc);
3997 TRACE("returning %d\n", ret);
4001 static BOOL is_hinting_enabled(void)
4005 /* Use the >= 2.2.0 function if available */
4006 if(pFT_Get_TrueType_Engine_Type)
4008 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4009 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4012 /* otherwise if we've been compiled with < 2.2.0 headers
4013 use the internal macro */
4014 #ifdef FT_DRIVER_HAS_HINTER
4015 mod = pFT_Get_Module(library, "truetype");
4016 if(mod && FT_DRIVER_HAS_HINTER(mod))
4023 /*************************************************************************
4024 * GetRasterizerCaps (GDI32.@)
4026 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4028 static int hinting = -1;
4031 hinting = is_hinting_enabled();
4033 lprs->nSize = sizeof(RASTERIZER_STATUS);
4034 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4035 lprs->nLanguageID = 0;
4040 #else /* HAVE_FREETYPE */
4042 BOOL WineEngInit(void)
4046 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
4050 BOOL WineEngDestroyFontInstance(HFONT hfont)
4055 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4060 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
4061 LPWORD pgi, DWORD flags)
4066 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
4067 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4070 ERR("called but we don't have FreeType\n");
4074 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
4076 ERR("called but we don't have FreeType\n");
4080 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
4081 OUTLINETEXTMETRICW *potm)
4083 ERR("called but we don't have FreeType\n");
4087 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
4090 ERR("called but we don't have FreeType\n");
4094 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
4097 ERR("called but we don't have FreeType\n");
4101 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
4104 ERR("called but we don't have FreeType\n");
4108 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
4111 ERR("called but we don't have FreeType\n");
4115 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
4118 ERR("called but we don't have FreeType\n");
4122 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
4124 ERR("called but we don't have FreeType\n");
4128 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4134 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4140 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
4143 return DEFAULT_CHARSET;
4146 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4151 BOOL WINAPI FontIsLinked(HDC hdc)
4156 /*************************************************************************
4157 * GetRasterizerCaps (GDI32.@)
4159 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4161 lprs->nSize = sizeof(RASTERIZER_STATUS);
4163 lprs->nLanguageID = 0;
4167 #endif /* HAVE_FREETYPE */