2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
40 #ifdef HAVE_CARBON_CARBON_H
41 #define LoadResource __carbon_LoadResource
42 #define CompareString __carbon_CompareString
43 #define GetCurrentThread __carbon_GetCurrentThread
44 #define GetCurrentProcess __carbon_GetCurrentProcess
45 #define AnimatePalette __carbon_AnimatePalette
46 #define EqualRgn __carbon_EqualRgn
47 #define FillRgn __carbon_FillRgn
48 #define FrameRgn __carbon_FrameRgn
49 #define GetPixel __carbon_GetPixel
50 #define InvertRgn __carbon_InvertRgn
51 #define LineTo __carbon_LineTo
52 #define OffsetRgn __carbon_OffsetRgn
53 #define PaintRgn __carbon_PaintRgn
54 #define Polygon __carbon_Polygon
55 #define ResizePalette __carbon_ResizePalette
56 #define SetRectRgn __carbon_SetRectRgn
57 #include <Carbon/Carbon.h>
60 #undef GetCurrentThread
63 #undef GetCurrentProcess
76 #endif /* HAVE_CARBON_CARBON_H */
84 #include "gdi_private.h"
85 #include "wine/unicode.h"
86 #include "wine/debug.h"
87 #include "wine/list.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(font);
93 #ifdef HAVE_FT2BUILD_H
96 #ifdef HAVE_FREETYPE_FREETYPE_H
97 #include <freetype/freetype.h>
99 #ifdef HAVE_FREETYPE_FTGLYPH_H
100 #include <freetype/ftglyph.h>
102 #ifdef HAVE_FREETYPE_TTTABLES_H
103 #include <freetype/tttables.h>
105 #ifdef HAVE_FREETYPE_FTTYPES_H
106 #include <freetype/fttypes.h>
108 #ifdef HAVE_FREETYPE_FTSNAMES_H
109 #include <freetype/ftsnames.h>
111 # ifdef HAVE_FREETYPE_FTNAMES_H
112 # include <freetype/ftnames.h>
115 #ifdef HAVE_FREETYPE_TTNAMEID_H
116 #include <freetype/ttnameid.h>
118 #ifdef HAVE_FREETYPE_FTOUTLN_H
119 #include <freetype/ftoutln.h>
121 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
122 #include <freetype/internal/sfnt.h>
124 #ifdef HAVE_FREETYPE_FTTRIGON_H
125 #include <freetype/fttrigon.h>
127 #ifdef HAVE_FREETYPE_FTWINFNT_H
128 #include <freetype/ftwinfnt.h>
130 #ifdef HAVE_FREETYPE_FTMODAPI_H
131 #include <freetype/ftmodapi.h>
134 #ifndef HAVE_FT_TRUETYPEENGINETYPE
137 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
138 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
139 FT_TRUETYPE_ENGINE_TYPE_PATENTED
140 } FT_TrueTypeEngineType;
143 static FT_Library library = 0;
150 static FT_Version_t FT_Version;
151 static DWORD FT_SimpleVersion;
153 static void *ft_handle = NULL;
155 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
156 MAKE_FUNCPTR(FT_Vector_Unit);
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_Module);
160 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
163 MAKE_FUNCPTR(FT_Init_FreeType);
164 MAKE_FUNCPTR(FT_Load_Glyph);
165 MAKE_FUNCPTR(FT_Matrix_Multiply);
166 MAKE_FUNCPTR(FT_MulFix);
167 MAKE_FUNCPTR(FT_New_Face);
168 MAKE_FUNCPTR(FT_New_Memory_Face);
169 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
170 MAKE_FUNCPTR(FT_Outline_Transform);
171 MAKE_FUNCPTR(FT_Outline_Translate);
172 MAKE_FUNCPTR(FT_Select_Charmap);
173 MAKE_FUNCPTR(FT_Set_Charmap);
174 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
175 MAKE_FUNCPTR(FT_Vector_Transform);
176 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
177 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
178 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
179 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
180 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
181 #ifdef HAVE_FREETYPE_FTWINFNT_H
182 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
185 #ifdef SONAME_LIBFONTCONFIG
186 #include <fontconfig/fontconfig.h>
187 MAKE_FUNCPTR(FcConfigGetCurrent);
188 MAKE_FUNCPTR(FcFontList);
189 MAKE_FUNCPTR(FcFontSetDestroy);
190 MAKE_FUNCPTR(FcInit);
191 MAKE_FUNCPTR(FcObjectSetAdd);
192 MAKE_FUNCPTR(FcObjectSetCreate);
193 MAKE_FUNCPTR(FcObjectSetDestroy);
194 MAKE_FUNCPTR(FcPatternCreate);
195 MAKE_FUNCPTR(FcPatternDestroy);
196 MAKE_FUNCPTR(FcPatternGetBool);
197 MAKE_FUNCPTR(FcPatternGetString);
203 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
204 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
205 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
208 #ifndef ft_encoding_none
209 #define FT_ENCODING_NONE ft_encoding_none
211 #ifndef ft_encoding_ms_symbol
212 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
214 #ifndef ft_encoding_unicode
215 #define FT_ENCODING_UNICODE ft_encoding_unicode
217 #ifndef ft_encoding_apple_roman
218 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
221 #ifdef WORDS_BIGENDIAN
222 #define GET_BE_WORD(x) (x)
224 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
227 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
234 FT_Short internal_leading;
237 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
238 So to let this compile on older versions of FreeType we'll define the
239 new structure here. */
241 FT_Short height, width;
242 FT_Pos size, x_ppem, y_ppem;
248 NEWTEXTMETRICEXW ntm;
252 typedef struct tagFace {
257 DWORD font_data_size;
260 FONTSIGNATURE fs_links;
262 FT_Fixed font_version;
264 Bitmap_Size size; /* set if face is a bitmap */
265 BOOL external; /* TRUE if we should manually add this font to the registry */
266 struct tagFamily *family;
267 /* Cached data for Enum */
268 struct enum_data *cached_enum_data;
271 typedef struct tagFamily {
273 const WCHAR *FamilyName;
279 INT adv; /* These three hold to widths of the unrotated chars */
297 typedef struct tagHFONTLIST {
312 struct list hfontlist;
313 OUTLINETEXTMETRICW *potm;
314 DWORD total_kern_pairs;
315 KERNINGPAIR *kern_pairs;
316 struct list child_fonts;
318 /* the following members can be accessed without locking, they are never modified after creation */
320 struct font_mapping *mapping;
342 const WCHAR *font_name;
346 #define GM_BLOCK_SIZE 128
347 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
349 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
350 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
351 #define UNUSED_CACHE_SIZE 10
352 static struct list child_font_list = LIST_INIT(child_font_list);
353 static struct list system_links = LIST_INIT(system_links);
355 static struct list font_subst_list = LIST_INIT(font_subst_list);
357 static struct list font_list = LIST_INIT(font_list);
359 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
360 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
361 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
363 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
364 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
365 'W','i','n','d','o','w','s','\\',
366 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
367 'F','o','n','t','s','\0'};
369 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
370 'W','i','n','d','o','w','s',' ','N','T','\\',
371 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
372 'F','o','n','t','s','\0'};
374 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
375 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
376 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
377 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
379 static const WCHAR * const SystemFontValues[4] = {
386 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
387 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
389 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
390 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
391 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
392 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
393 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
394 'E','u','r','o','p','e','a','n','\0'};
395 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
396 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
397 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
398 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
399 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
400 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
401 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
402 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
403 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
404 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
405 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
406 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
408 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
418 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
426 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
435 typedef struct tagFontSubst {
451 static struct list mappings_list = LIST_INIT( mappings_list );
453 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
455 static CRITICAL_SECTION freetype_cs;
456 static CRITICAL_SECTION_DEBUG critsect_debug =
459 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
460 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
462 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
464 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
466 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
467 static BOOL use_default_fallback = FALSE;
469 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
471 /****************************************
472 * Notes on .fon files
474 * The fonts System, FixedSys and Terminal are special. There are typically multiple
475 * versions installed for different resolutions and codepages. Windows stores which one to use
476 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
478 * FIXEDFON.FON FixedSys
480 * OEMFONT.FON Terminal
481 * LogPixels Current dpi set by the display control panel applet
482 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
483 * also has a LogPixels value that appears to mirror this)
485 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
486 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
487 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
488 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
489 * so that makes sense.
491 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
492 * to be mapped into the registry on Windows 2000 at least).
495 * ega80woa.fon=ega80850.fon
496 * ega40woa.fon=ega40850.fon
497 * cga80woa.fon=cga80850.fon
498 * cga40woa.fon=cga40850.fon
501 /* These are all structures needed for the GSUB table */
503 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
504 #define TATEGAKI_LOWER_BOUND 0x02F1
520 GSUB_ScriptRecord ScriptRecord[1];
526 } GSUB_LangSysRecord;
531 GSUB_LangSysRecord LangSysRecord[1];
535 WORD LookupOrder; /* Reserved */
536 WORD ReqFeatureIndex;
538 WORD FeatureIndex[1];
544 } GSUB_FeatureRecord;
548 GSUB_FeatureRecord FeatureRecord[1];
552 WORD FeatureParams; /* Reserved */
554 WORD LookupListIndex[1];
573 } GSUB_CoverageFormat1;
578 WORD StartCoverageIndex;
584 GSUB_RangeRecord RangeRecord[1];
585 } GSUB_CoverageFormat2;
588 WORD SubstFormat; /* = 1 */
591 } GSUB_SingleSubstFormat1;
594 WORD SubstFormat; /* = 2 */
598 }GSUB_SingleSubstFormat2;
600 #ifdef HAVE_CARBON_CARBON_H
601 static char *find_cache_dir(void)
605 static char cached_path[MAX_PATH];
606 static const char *wine = "/Wine", *fonts = "/Fonts";
608 if(*cached_path) return cached_path;
610 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
613 WARN("can't create cached data folder\n");
616 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
619 WARN("can't create cached data path\n");
623 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
625 ERR("Could not create full path\n");
629 strcat(cached_path, wine);
631 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
633 WARN("Couldn't mkdir %s\n", cached_path);
637 strcat(cached_path, fonts);
638 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
640 WARN("Couldn't mkdir %s\n", cached_path);
647 /******************************************************************
650 * Extracts individual TrueType font files from a Mac suitcase font
651 * and saves them into the user's caches directory (see
653 * Returns a NULL terminated array of filenames.
655 * We do this because they are apps that try to read ttf files
656 * themselves and they don't like Mac suitcase files.
658 static char **expand_mac_font(const char *path)
665 const char *filename;
669 unsigned int size, max_size;
672 TRACE("path %s\n", path);
674 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
677 WARN("failed to get ref\n");
681 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
684 TRACE("no data fork, so trying resource fork\n");
685 res_ref = FSOpenResFile(&ref, fsRdPerm);
688 TRACE("unable to open resource fork\n");
695 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
698 CloseResFile(res_ref);
702 out_dir = find_cache_dir();
704 filename = strrchr(path, '/');
705 if(!filename) filename = path;
708 /* output filename has the form out_dir/filename_%04x.ttf */
709 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
716 unsigned short *num_faces_ptr, num_faces, face;
719 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
721 fond = Get1IndResource(fond_res, idx);
723 TRACE("got fond resource %d\n", idx);
726 fam_rec = *(FamRec**)fond;
727 num_faces_ptr = (unsigned short *)(fam_rec + 1);
728 num_faces = GET_BE_WORD(*num_faces_ptr);
730 assoc = (AsscEntry*)(num_faces_ptr + 1);
731 TRACE("num faces %04x\n", num_faces);
732 for(face = 0; face < num_faces; face++, assoc++)
735 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
736 unsigned short size, font_id;
739 size = GET_BE_WORD(assoc->fontSize);
740 font_id = GET_BE_WORD(assoc->fontID);
743 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
747 TRACE("trying to load sfnt id %04x\n", font_id);
748 sfnt = GetResource(sfnt_res, font_id);
751 TRACE("can't get sfnt resource %04x\n", font_id);
755 output = HeapAlloc(GetProcessHeap(), 0, output_len);
760 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
762 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
763 if(fd != -1 || errno == EEXIST)
767 unsigned char *sfnt_data;
770 sfnt_data = *(unsigned char**)sfnt;
771 write(fd, sfnt_data, GetHandleSize(sfnt));
775 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
778 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
780 ret.array[ret.size++] = output;
784 WARN("unable to create %s\n", output);
785 HeapFree(GetProcessHeap(), 0, output);
788 ReleaseResource(sfnt);
791 ReleaseResource(fond);
794 CloseResFile(res_ref);
799 #endif /* HAVE_CARBON_CARBON_H */
801 static inline BOOL is_win9x(void)
803 return GetVersion() & 0x80000000;
806 This function builds an FT_Fixed from a float. It puts the integer part
807 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
808 It fails if the integer part of the float number is greater than SHORT_MAX.
810 static inline FT_Fixed FT_FixedFromFloat(double f)
813 unsigned short fract = (f - value) * 0xFFFF;
814 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
818 This function builds an FT_Fixed from a FIXED. It simply put f.value
819 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
821 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
823 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
827 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
832 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
833 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
835 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
836 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
838 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
840 if(face_name && strcmpiW(face_name, family->FamilyName))
842 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
846 file = strrchr(face->file, '/');
851 if(!strcasecmp(file, file_nameA))
853 HeapFree(GetProcessHeap(), 0, file_nameA);
858 HeapFree(GetProcessHeap(), 0, file_nameA);
862 static Family *find_family_from_name(const WCHAR *name)
866 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
868 if(!strcmpiW(family->FamilyName, name))
875 static void DumpSubstList(void)
879 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
881 if(psub->from.charset != -1 || psub->to.charset != -1)
882 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
883 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
885 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
886 debugstr_w(psub->to.name));
891 static LPWSTR strdupW(LPCWSTR p)
894 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
895 ret = HeapAlloc(GetProcessHeap(), 0, len);
900 static LPSTR strdupA(LPCSTR p)
903 DWORD len = (strlen(p) + 1);
904 ret = HeapAlloc(GetProcessHeap(), 0, len);
909 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
914 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
916 if(!strcmpiW(element->from.name, from_name) &&
917 (element->from.charset == from_charset ||
918 element->from.charset == -1))
925 #define ADD_FONT_SUBST_FORCE 1
927 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
929 FontSubst *from_exist, *to_exist;
931 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
933 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
935 list_remove(&from_exist->entry);
936 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
937 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
938 HeapFree(GetProcessHeap(), 0, from_exist);
944 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
948 HeapFree(GetProcessHeap(), 0, subst->to.name);
949 subst->to.name = strdupW(to_exist->to.name);
952 list_add_tail(subst_list, &subst->entry);
957 HeapFree(GetProcessHeap(), 0, subst->from.name);
958 HeapFree(GetProcessHeap(), 0, subst->to.name);
959 HeapFree(GetProcessHeap(), 0, subst);
963 static void split_subst_info(NameCs *nc, LPSTR str)
965 CHAR *p = strrchr(str, ',');
970 nc->charset = strtol(p+1, NULL, 10);
973 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
974 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
975 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
978 static void LoadSubstList(void)
982 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
986 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
987 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
988 &hkey) == ERROR_SUCCESS) {
990 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
991 &valuelen, &datalen, NULL, NULL);
993 valuelen++; /* returned value doesn't include room for '\0' */
994 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
995 data = HeapAlloc(GetProcessHeap(), 0, datalen);
999 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1000 &dlen) == ERROR_SUCCESS) {
1001 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1003 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1004 split_subst_info(&psub->from, value);
1005 split_subst_info(&psub->to, data);
1007 /* Win 2000 doesn't allow mapping between different charsets
1008 or mapping of DEFAULT_CHARSET */
1009 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1010 psub->to.charset == DEFAULT_CHARSET) {
1011 HeapFree(GetProcessHeap(), 0, psub->to.name);
1012 HeapFree(GetProcessHeap(), 0, psub->from.name);
1013 HeapFree(GetProcessHeap(), 0, psub);
1015 add_font_subst(&font_subst_list, psub, 0);
1017 /* reset dlen and vlen */
1021 HeapFree(GetProcessHeap(), 0, data);
1022 HeapFree(GetProcessHeap(), 0, value);
1027 static WCHAR *get_familyname(FT_Face ft_face)
1029 WCHAR *family = NULL;
1031 FT_UInt num_names, name_index, i;
1033 if(FT_IS_SFNT(ft_face))
1035 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1037 for(name_index = 0; name_index < num_names; name_index++)
1039 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1041 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
1042 (name.language_id == GetUserDefaultLCID()) &&
1043 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
1044 (name.encoding_id == TT_MS_ID_UNICODE_CS))
1046 /* String is not nul terminated and string_len is a byte length. */
1047 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1048 for(i = 0; i < name.string_len / 2; i++)
1050 WORD *tmp = (WORD *)&name.string[i * 2];
1051 family[i] = GET_BE_WORD(*tmp);
1055 TRACE("Got localised name %s\n", debugstr_w(family));
1066 /*****************************************************************
1069 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1070 * of FreeType that don't export this function.
1073 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1078 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1079 if(pFT_Load_Sfnt_Table)
1081 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1083 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1084 else /* Do it the hard way */
1086 TT_Face tt_face = (TT_Face) ft_face;
1087 SFNT_Interface *sfnt;
1088 if (FT_Version.major==2 && FT_Version.minor==0)
1091 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1095 /* A field was added in the middle of the structure in 2.1.x */
1096 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1098 err = sfnt->load_any(tt_face, table, offset, buf, len);
1106 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1107 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1108 "Please upgrade your freetype library.\n");
1111 err = FT_Err_Unimplemented_Feature;
1117 static inline int TestStyles(DWORD flags, DWORD styles)
1119 return (flags & styles) == styles;
1122 static int StyleOrdering(Face *face)
1124 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1126 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1128 if (TestStyles(face->ntmFlags, NTM_BOLD))
1130 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1133 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1134 debugstr_w(face->family->FamilyName),
1135 debugstr_w(face->StyleName),
1141 /* Add a style of face to a font family using an ordering of the list such
1142 that regular fonts come before bold and italic, and single styles come
1143 before compound styles. */
1144 static void AddFaceToFamily(Face *face, Family *family)
1148 LIST_FOR_EACH( entry, &family->faces )
1150 Face *ent = LIST_ENTRY(entry, Face, entry);
1151 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1153 list_add_before( entry, &face->entry );
1156 #define ADDFONT_EXTERNAL_FONT 0x01
1157 #define ADDFONT_FORCE_BITMAP 0x02
1158 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1162 TT_Header *pHeader = NULL;
1163 WCHAR *english_family, *localised_family, *StyleW;
1167 struct list *family_elem_ptr, *face_elem_ptr;
1169 FT_Long face_index = 0, num_faces;
1170 #ifdef HAVE_FREETYPE_FTWINFNT_H
1171 FT_WinFNT_HeaderRec winfnt_header;
1173 int i, bitmap_num, internal_leading;
1176 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1177 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1179 #ifdef HAVE_CARBON_CARBON_H
1180 if(file && !fake_family)
1182 char **mac_list = expand_mac_font(file);
1185 BOOL had_one = FALSE;
1187 for(cursor = mac_list; *cursor; cursor++)
1190 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1191 HeapFree(GetProcessHeap(), 0, *cursor);
1193 HeapFree(GetProcessHeap(), 0, mac_list);
1198 #endif /* HAVE_CARBON_CARBON_H */
1201 char *family_name = fake_family;
1205 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1206 err = pFT_New_Face(library, file, face_index, &ft_face);
1209 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1210 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1214 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1218 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*/
1219 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1220 pFT_Done_Face(ft_face);
1224 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1225 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1226 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1227 pFT_Done_Face(ft_face);
1231 if(FT_IS_SFNT(ft_face))
1233 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1234 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1235 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1237 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1238 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1239 pFT_Done_Face(ft_face);
1243 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1244 we don't want to load these. */
1245 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1249 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1251 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1252 pFT_Done_Face(ft_face);
1258 if(!ft_face->family_name || !ft_face->style_name) {
1259 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1260 pFT_Done_Face(ft_face);
1264 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1266 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1267 pFT_Done_Face(ft_face);
1273 localised_family = get_familyname(ft_face);
1274 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1276 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1277 HeapFree(GetProcessHeap(), 0, localised_family);
1278 num_faces = ft_face->num_faces;
1279 pFT_Done_Face(ft_face);
1282 HeapFree(GetProcessHeap(), 0, localised_family);
1286 family_name = ft_face->family_name;
1290 My_FT_Bitmap_Size *size = NULL;
1293 if(!FT_IS_SCALABLE(ft_face))
1294 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1296 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1297 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1298 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1300 localised_family = NULL;
1302 localised_family = get_familyname(ft_face);
1303 if(localised_family && !strcmpW(localised_family, english_family)) {
1304 HeapFree(GetProcessHeap(), 0, localised_family);
1305 localised_family = NULL;
1310 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1311 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1312 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1317 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1318 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1319 list_init(&family->faces);
1320 list_add_tail(&font_list, &family->entry);
1322 if(localised_family) {
1323 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1324 subst->from.name = strdupW(english_family);
1325 subst->from.charset = -1;
1326 subst->to.name = strdupW(localised_family);
1327 subst->to.charset = -1;
1328 add_font_subst(&font_subst_list, subst, 0);
1331 HeapFree(GetProcessHeap(), 0, localised_family);
1332 HeapFree(GetProcessHeap(), 0, english_family);
1334 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1335 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1336 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1338 internal_leading = 0;
1339 memset(&fs, 0, sizeof(fs));
1341 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1343 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1344 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1345 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1346 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1347 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1348 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1349 if(pOS2->version == 0) {
1352 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1353 fs.fsCsb[0] |= FS_LATIN1;
1355 fs.fsCsb[0] |= FS_SYMBOL;
1358 #ifdef HAVE_FREETYPE_FTWINFNT_H
1359 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1361 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1362 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1363 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1365 internal_leading = winfnt_header.internal_leading;
1369 face_elem_ptr = list_head(&family->faces);
1370 while(face_elem_ptr) {
1371 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1372 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1373 if(!strcmpW(face->StyleName, StyleW) &&
1374 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1375 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1376 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1377 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1380 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1381 HeapFree(GetProcessHeap(), 0, StyleW);
1382 pFT_Done_Face(ft_face);
1385 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1386 TRACE("Original font is newer so skipping this one\n");
1387 HeapFree(GetProcessHeap(), 0, StyleW);
1388 pFT_Done_Face(ft_face);
1391 TRACE("Replacing original with this one\n");
1392 list_remove(&face->entry);
1393 HeapFree(GetProcessHeap(), 0, face->file);
1394 HeapFree(GetProcessHeap(), 0, face->StyleName);
1395 HeapFree(GetProcessHeap(), 0, face);
1400 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1401 face->cached_enum_data = NULL;
1402 face->StyleName = StyleW;
1405 face->file = strdupA(file);
1406 face->font_data_ptr = NULL;
1407 face->font_data_size = 0;
1412 face->font_data_ptr = font_data_ptr;
1413 face->font_data_size = font_data_size;
1415 face->face_index = face_index;
1417 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1418 face->ntmFlags |= NTM_ITALIC;
1419 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1420 face->ntmFlags |= NTM_BOLD;
1421 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1422 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1423 face->family = family;
1424 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1426 memset(&face->fs_links, 0, sizeof(face->fs_links));
1428 if(FT_IS_SCALABLE(ft_face)) {
1429 memset(&face->size, 0, sizeof(face->size));
1430 face->scalable = TRUE;
1432 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1433 size->height, size->width, size->size >> 6,
1434 size->x_ppem >> 6, size->y_ppem >> 6);
1435 face->size.height = size->height;
1436 face->size.width = size->width;
1437 face->size.size = size->size;
1438 face->size.x_ppem = size->x_ppem;
1439 face->size.y_ppem = size->y_ppem;
1440 face->size.internal_leading = internal_leading;
1441 face->scalable = FALSE;
1444 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1446 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1448 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1449 face->ntmFlags |= NTM_PS_OPENTYPE;
1452 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1453 face->fs.fsCsb[0], face->fs.fsCsb[1],
1454 face->fs.fsUsb[0], face->fs.fsUsb[1],
1455 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1458 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1459 for(i = 0; i < ft_face->num_charmaps; i++) {
1460 switch(ft_face->charmaps[i]->encoding) {
1461 case FT_ENCODING_UNICODE:
1462 case FT_ENCODING_APPLE_ROMAN:
1463 face->fs.fsCsb[0] |= FS_LATIN1;
1465 case FT_ENCODING_MS_SYMBOL:
1466 face->fs.fsCsb[0] |= FS_SYMBOL;
1474 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1475 have_installed_roman_font = TRUE;
1477 AddFaceToFamily(face, family);
1479 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1481 num_faces = ft_face->num_faces;
1482 pFT_Done_Face(ft_face);
1483 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1484 debugstr_w(StyleW));
1485 } while(num_faces > ++face_index);
1489 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1491 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1494 static void DumpFontList(void)
1498 struct list *family_elem_ptr, *face_elem_ptr;
1500 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1501 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1502 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1503 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1504 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1505 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1507 TRACE(" %d", face->size.height);
1514 /***********************************************************
1515 * The replacement list is a way to map an entire font
1516 * family onto another family. For example adding
1518 * [HKCU\Software\Wine\Fonts\Replacements]
1519 * "Wingdings"="Winedings"
1521 * would enumerate the Winedings font both as Winedings and
1522 * Wingdings. However if a real Wingdings font is present the
1523 * replacement does not take place.
1526 static void LoadReplaceList(void)
1529 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1534 struct list *family_elem_ptr, *face_elem_ptr;
1537 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1538 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1540 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1541 &valuelen, &datalen, NULL, NULL);
1543 valuelen++; /* returned value doesn't include room for '\0' */
1544 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1545 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1549 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1550 &dlen) == ERROR_SUCCESS) {
1551 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1552 /* "NewName"="Oldname" */
1553 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1555 /* Find the old family and hence all of the font files
1557 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1558 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1559 if(!strcmpiW(family->FamilyName, data)) {
1560 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1561 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1562 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1563 debugstr_w(face->StyleName), familyA);
1564 /* Now add a new entry with the new family name */
1565 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1570 /* reset dlen and vlen */
1574 HeapFree(GetProcessHeap(), 0, data);
1575 HeapFree(GetProcessHeap(), 0, value);
1580 /*************************************************************
1583 static BOOL init_system_links(void)
1585 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1586 'W','i','n','d','o','w','s',' ','N','T','\\',
1587 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1588 'S','y','s','t','e','m','L','i','n','k',0};
1591 DWORD type, max_val, max_data, val_len, data_len, index;
1592 WCHAR *value, *data;
1593 WCHAR *entry, *next;
1594 SYSTEM_LINKS *font_link, *system_font_link;
1595 CHILD_FONT *child_font;
1596 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1597 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1598 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1604 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1606 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1607 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1608 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1609 val_len = max_val + 1;
1610 data_len = max_data;
1612 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1614 TRACE("%s:\n", debugstr_w(value));
1616 memset(&fs, 0, sizeof(fs));
1617 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1618 psub = get_font_subst(&font_subst_list, value, -1);
1619 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1620 list_init(&font_link->links);
1621 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1624 CHILD_FONT *child_font;
1626 TRACE("\t%s\n", debugstr_w(entry));
1628 next = entry + strlenW(entry) + 1;
1630 face_name = strchrW(entry, ',');
1634 while(isspaceW(*face_name))
1637 psub = get_font_subst(&font_subst_list, face_name, -1);
1639 face_name = psub->to.name;
1641 face = find_face_from_filename(entry, face_name);
1644 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1648 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1649 child_font->face = face;
1650 child_font->font = NULL;
1651 fs.fsCsb[0] |= face->fs.fsCsb[0];
1652 fs.fsCsb[1] |= face->fs.fsCsb[1];
1653 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1654 list_add_tail(&font_link->links, &child_font->entry);
1656 family = find_family_from_name(font_link->font_name);
1659 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1661 face->fs_links = fs;
1664 list_add_tail(&system_links, &font_link->entry);
1665 val_len = max_val + 1;
1666 data_len = max_data;
1669 HeapFree(GetProcessHeap(), 0, value);
1670 HeapFree(GetProcessHeap(), 0, data);
1674 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1677 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1678 system_font_link->font_name = strdupW(System);
1679 list_init(&system_font_link->links);
1681 face = find_face_from_filename(tahoma_ttf, Tahoma);
1684 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1685 child_font->face = face;
1686 child_font->font = NULL;
1687 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1688 list_add_tail(&system_font_link->links, &child_font->entry);
1690 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1692 if(!strcmpiW(font_link->font_name, Tahoma))
1694 CHILD_FONT *font_link_entry;
1695 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1697 CHILD_FONT *new_child;
1698 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1699 new_child->face = font_link_entry->face;
1700 new_child->font = NULL;
1701 list_add_tail(&system_font_link->links, &new_child->entry);
1706 list_add_tail(&system_links, &system_font_link->entry);
1710 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1713 struct dirent *dent;
1714 char path[MAX_PATH];
1716 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1718 dir = opendir(dirname);
1720 WARN("Can't open directory %s\n", debugstr_a(dirname));
1723 while((dent = readdir(dir)) != NULL) {
1724 struct stat statbuf;
1726 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1729 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1731 sprintf(path, "%s/%s", dirname, dent->d_name);
1733 if(stat(path, &statbuf) == -1)
1735 WARN("Can't stat %s\n", debugstr_a(path));
1738 if(S_ISDIR(statbuf.st_mode))
1739 ReadFontDir(path, external_fonts);
1741 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1747 static void load_fontconfig_fonts(void)
1749 #ifdef SONAME_LIBFONTCONFIG
1750 void *fc_handle = NULL;
1759 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1761 TRACE("Wine cannot find the fontconfig library (%s).\n",
1762 SONAME_LIBFONTCONFIG);
1765 #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;}
1766 LOAD_FUNCPTR(FcConfigGetCurrent);
1767 LOAD_FUNCPTR(FcFontList);
1768 LOAD_FUNCPTR(FcFontSetDestroy);
1769 LOAD_FUNCPTR(FcInit);
1770 LOAD_FUNCPTR(FcObjectSetAdd);
1771 LOAD_FUNCPTR(FcObjectSetCreate);
1772 LOAD_FUNCPTR(FcObjectSetDestroy);
1773 LOAD_FUNCPTR(FcPatternCreate);
1774 LOAD_FUNCPTR(FcPatternDestroy);
1775 LOAD_FUNCPTR(FcPatternGetBool);
1776 LOAD_FUNCPTR(FcPatternGetString);
1779 if(!pFcInit()) return;
1781 config = pFcConfigGetCurrent();
1782 pat = pFcPatternCreate();
1783 os = pFcObjectSetCreate();
1784 pFcObjectSetAdd(os, FC_FILE);
1785 pFcObjectSetAdd(os, FC_SCALABLE);
1786 fontset = pFcFontList(config, pat, os);
1787 if(!fontset) return;
1788 for(i = 0; i < fontset->nfont; i++) {
1791 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1793 TRACE("fontconfig: %s\n", file);
1795 /* We're just interested in OT/TT fonts for now, so this hack just
1796 picks up the scalable fonts without extensions .pf[ab] to save time
1797 loading every other font */
1799 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1801 TRACE("not scalable\n");
1805 len = strlen( file );
1806 if(len < 4) continue;
1807 ext = &file[ len - 3 ];
1808 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1809 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1811 pFcFontSetDestroy(fontset);
1812 pFcObjectSetDestroy(os);
1813 pFcPatternDestroy(pat);
1819 static BOOL load_font_from_data_dir(LPCWSTR file)
1822 const char *data_dir = wine_get_data_dir();
1824 if (!data_dir) data_dir = wine_get_build_dir();
1831 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1833 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1835 strcpy(unix_name, data_dir);
1836 strcat(unix_name, "/fonts/");
1838 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1840 EnterCriticalSection( &freetype_cs );
1841 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1842 LeaveCriticalSection( &freetype_cs );
1843 HeapFree(GetProcessHeap(), 0, unix_name);
1848 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1850 static const WCHAR slashW[] = {'\\','\0'};
1852 WCHAR windowsdir[MAX_PATH];
1855 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1856 strcatW(windowsdir, fontsW);
1857 strcatW(windowsdir, slashW);
1858 strcatW(windowsdir, file);
1859 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1860 EnterCriticalSection( &freetype_cs );
1861 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1862 LeaveCriticalSection( &freetype_cs );
1863 HeapFree(GetProcessHeap(), 0, unixname);
1868 static void load_system_fonts(void)
1871 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1872 const WCHAR * const *value;
1874 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1877 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1878 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1879 strcatW(windowsdir, fontsW);
1880 for(value = SystemFontValues; *value; value++) {
1881 dlen = sizeof(data);
1882 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1886 sprintfW(pathW, fmtW, windowsdir, data);
1887 if((unixname = wine_get_unix_file_name(pathW))) {
1888 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1889 HeapFree(GetProcessHeap(), 0, unixname);
1892 load_font_from_data_dir(data);
1899 /*************************************************************
1901 * This adds registry entries for any externally loaded fonts
1902 * (fonts from fontconfig or FontDirs). It also deletes entries
1903 * of no longer existing fonts.
1906 static void update_reg_entries(void)
1908 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1913 struct list *family_elem_ptr, *face_elem_ptr;
1915 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1916 static const WCHAR spaceW[] = {' ', '\0'};
1919 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1920 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1921 ERR("Can't create Windows font reg key\n");
1925 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1926 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1927 ERR("Can't create Windows font reg key\n");
1931 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1932 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1933 ERR("Can't create external font reg key\n");
1937 /* enumerate the fonts and add external ones to the two keys */
1939 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1940 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1941 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1942 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1943 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1944 if(!face->external) continue;
1946 if (!(face->ntmFlags & NTM_REGULAR))
1947 len = len_fam + strlenW(face->StyleName) + 1;
1948 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1949 strcpyW(valueW, family->FamilyName);
1950 if(len != len_fam) {
1951 strcatW(valueW, spaceW);
1952 strcatW(valueW, face->StyleName);
1954 strcatW(valueW, TrueType);
1956 file = wine_get_dos_file_name(face->file);
1958 len = strlenW(file) + 1;
1961 if((path = strrchr(face->file, '/')) == NULL)
1965 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1967 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1968 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1970 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1971 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1972 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1974 HeapFree(GetProcessHeap(), 0, file);
1975 HeapFree(GetProcessHeap(), 0, valueW);
1979 if(external_key) RegCloseKey(external_key);
1980 if(win9x_key) RegCloseKey(win9x_key);
1981 if(winnt_key) RegCloseKey(winnt_key);
1985 static void delete_external_font_keys(void)
1987 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1988 DWORD dlen, vlen, datalen, valuelen, i, type;
1992 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1993 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1994 ERR("Can't create Windows font reg key\n");
1998 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1999 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2000 ERR("Can't create Windows font reg key\n");
2004 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2005 ERR("Can't create external font reg key\n");
2009 /* Delete all external fonts added last time */
2011 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2012 &valuelen, &datalen, NULL, NULL);
2013 valuelen++; /* returned value doesn't include room for '\0' */
2014 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2015 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2017 dlen = datalen * sizeof(WCHAR);
2020 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2021 &dlen) == ERROR_SUCCESS) {
2023 RegDeleteValueW(winnt_key, valueW);
2024 RegDeleteValueW(win9x_key, valueW);
2025 /* reset dlen and vlen */
2029 HeapFree(GetProcessHeap(), 0, data);
2030 HeapFree(GetProcessHeap(), 0, valueW);
2032 /* Delete the old external fonts key */
2033 RegCloseKey(external_key);
2034 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2037 if(win9x_key) RegCloseKey(win9x_key);
2038 if(winnt_key) RegCloseKey(winnt_key);
2041 /*************************************************************
2042 * WineEngAddFontResourceEx
2045 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2048 if (ft_handle) /* do it only if we have freetype up and running */
2053 FIXME("Ignoring flags %x\n", flags);
2055 if((unixname = wine_get_unix_file_name(file)))
2057 EnterCriticalSection( &freetype_cs );
2058 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2059 LeaveCriticalSection( &freetype_cs );
2060 HeapFree(GetProcessHeap(), 0, unixname);
2062 if (!ret && !strchrW(file, '\\')) {
2063 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2064 ret = load_font_from_winfonts_dir(file);
2066 /* Try in datadir/fonts (or builddir/fonts),
2067 * needed for Magic the Gathering Online
2069 ret = load_font_from_data_dir(file);
2076 /*************************************************************
2077 * WineEngAddFontMemResourceEx
2080 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2082 if (ft_handle) /* do it only if we have freetype up and running */
2084 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2086 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2087 memcpy(pFontCopy, pbFont, cbFont);
2089 EnterCriticalSection( &freetype_cs );
2090 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2091 LeaveCriticalSection( &freetype_cs );
2095 TRACE("AddFontToList failed\n");
2096 HeapFree(GetProcessHeap(), 0, pFontCopy);
2099 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2100 * For now return something unique but quite random
2102 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2103 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2110 /*************************************************************
2111 * WineEngRemoveFontResourceEx
2114 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2120 static const struct nls_update_font_list
2122 UINT ansi_cp, oem_cp;
2123 const char *oem, *fixed, *system;
2124 const char *courier, *serif, *small, *sserif;
2125 /* these are for font substitutes */
2126 const char *shelldlg, *tmsrmn;
2127 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2131 const char *from, *to;
2132 } arial_0, courier_new_0, times_new_roman_0;
2133 } nls_update_font_list[] =
2135 /* Latin 1 (United States) */
2136 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2137 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2138 "Tahoma","Times New Roman",
2139 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2142 /* Latin 1 (Multilingual) */
2143 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2144 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2145 "Tahoma","Times New Roman", /* FIXME unverified */
2146 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2149 /* Eastern Europe */
2150 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2151 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2152 "Tahoma","Times New Roman", /* FIXME unverified */
2153 "Fixedsys,238", "System,238",
2154 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2155 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2156 { "Arial CE,0", "Arial,238" },
2157 { "Courier New CE,0", "Courier New,238" },
2158 { "Times New Roman CE,0", "Times New Roman,238" }
2161 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2162 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2163 "Tahoma","Times New Roman", /* FIXME unverified */
2164 "Fixedsys,204", "System,204",
2165 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2166 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2167 { "Arial Cyr,0", "Arial,204" },
2168 { "Courier New Cyr,0", "Courier New,204" },
2169 { "Times New Roman Cyr,0", "Times New Roman,204" }
2172 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2173 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2174 "Tahoma","Times New Roman", /* FIXME unverified */
2175 "Fixedsys,161", "System,161",
2176 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2177 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2178 { "Arial Greek,0", "Arial,161" },
2179 { "Courier New Greek,0", "Courier New,161" },
2180 { "Times New Roman Greek,0", "Times New Roman,161" }
2183 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2184 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2185 "Tahoma","Times New Roman", /* FIXME unverified */
2186 "Fixedsys,162", "System,162",
2187 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2188 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2189 { "Arial Tur,0", "Arial,162" },
2190 { "Courier New Tur,0", "Courier New,162" },
2191 { "Times New Roman Tur,0", "Times New Roman,162" }
2194 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2195 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2196 "Tahoma","Times New Roman", /* FIXME unverified */
2197 "Fixedsys,177", "System,177",
2198 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2199 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2203 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2204 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2205 "Tahoma","Times New Roman", /* FIXME unverified */
2206 "Fixedsys,178", "System,178",
2207 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2208 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2212 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2213 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2214 "Tahoma","Times New Roman", /* FIXME unverified */
2215 "Fixedsys,186", "System,186",
2216 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2217 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2218 { "Arial Baltic,0", "Arial,186" },
2219 { "Courier New Baltic,0", "Courier New,186" },
2220 { "Times New Roman Baltic,0", "Times New Roman,186" }
2223 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2224 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2225 "Tahoma","Times New Roman", /* FIXME unverified */
2226 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2230 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2231 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2232 "Tahoma","Times New Roman", /* FIXME unverified */
2233 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2237 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2238 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2239 "MS UI Gothic","MS Serif",
2240 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2243 /* Chinese Simplified */
2244 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2245 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2246 "Tahoma", "Times New Roman", /* FIXME unverified */
2247 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2251 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2252 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2254 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2257 /* Chinese Traditional */
2258 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2259 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2260 "PMingLiU", "MingLiU",
2261 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2266 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2268 return ( ansi_cp == 932 /* CP932 for Japanese */
2269 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2270 || ansi_cp == 949 /* CP949 for Korean */
2271 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2274 static inline HKEY create_fonts_NT_registry_key(void)
2278 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2279 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2283 static inline HKEY create_fonts_9x_registry_key(void)
2287 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2288 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2292 static inline HKEY create_config_fonts_registry_key(void)
2296 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2297 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2301 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2303 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2304 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2305 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2306 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2309 static void set_value_key(HKEY hkey, const char *name, const char *value)
2312 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2314 RegDeleteValueA(hkey, name);
2317 static void update_font_info(void)
2319 char buf[40], cpbuf[40];
2322 UINT i, ansi_cp = 0, oem_cp = 0;
2325 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2328 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2329 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2330 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2331 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2332 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2334 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2335 if (is_dbcs_ansi_cp(ansi_cp))
2336 use_default_fallback = TRUE;
2339 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2341 if (!strcmp( buf, cpbuf )) /* already set correctly */
2346 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2348 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2350 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2353 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2357 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2358 nls_update_font_list[i].oem_cp == oem_cp)
2360 hkey = create_config_fonts_registry_key();
2361 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2362 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2363 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2366 hkey = create_fonts_NT_registry_key();
2367 add_font_list(hkey, &nls_update_font_list[i]);
2370 hkey = create_fonts_9x_registry_key();
2371 add_font_list(hkey, &nls_update_font_list[i]);
2374 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2376 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2377 strlen(nls_update_font_list[i].shelldlg)+1);
2378 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2379 strlen(nls_update_font_list[i].tmsrmn)+1);
2381 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2382 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2383 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2384 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2385 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2386 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2387 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2388 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2390 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2391 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2392 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2400 /* Delete the FontSubstitutes from other locales */
2401 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2403 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2404 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2405 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2411 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2415 static BOOL init_freetype(void)
2417 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2420 "Wine cannot find the FreeType font library. To enable Wine to\n"
2421 "use TrueType fonts please install a version of FreeType greater than\n"
2422 "or equal to 2.0.5.\n"
2423 "http://www.freetype.org\n");
2427 #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;}
2429 LOAD_FUNCPTR(FT_Vector_Unit)
2430 LOAD_FUNCPTR(FT_Done_Face)
2431 LOAD_FUNCPTR(FT_Get_Char_Index)
2432 LOAD_FUNCPTR(FT_Get_Module)
2433 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2434 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2435 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2436 LOAD_FUNCPTR(FT_Init_FreeType)
2437 LOAD_FUNCPTR(FT_Load_Glyph)
2438 LOAD_FUNCPTR(FT_Matrix_Multiply)
2439 LOAD_FUNCPTR(FT_MulFix)
2440 LOAD_FUNCPTR(FT_New_Face)
2441 LOAD_FUNCPTR(FT_New_Memory_Face)
2442 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2443 LOAD_FUNCPTR(FT_Outline_Transform)
2444 LOAD_FUNCPTR(FT_Outline_Translate)
2445 LOAD_FUNCPTR(FT_Select_Charmap)
2446 LOAD_FUNCPTR(FT_Set_Charmap)
2447 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2448 LOAD_FUNCPTR(FT_Vector_Transform)
2451 /* Don't warn if these ones are missing */
2452 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2453 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2454 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2455 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2456 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2457 #ifdef HAVE_FREETYPE_FTWINFNT_H
2458 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2460 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2461 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2462 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2463 <= 2.0.3 has FT_Sqrt64 */
2467 if(pFT_Init_FreeType(&library) != 0) {
2468 ERR("Can't init FreeType library\n");
2469 wine_dlclose(ft_handle, NULL, 0);
2473 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2474 if (pFT_Library_Version)
2475 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2477 if (FT_Version.major<=0)
2483 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2484 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2485 ((FT_Version.minor << 8) & 0x00ff00) |
2486 ((FT_Version.patch ) & 0x0000ff);
2492 "Wine cannot find certain functions that it needs inside the FreeType\n"
2493 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2494 "FreeType to at least version 2.0.5.\n"
2495 "http://www.freetype.org\n");
2496 wine_dlclose(ft_handle, NULL, 0);
2501 /*************************************************************
2504 * Initialize FreeType library and create a list of available faces
2506 BOOL WineEngInit(void)
2508 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2509 static const WCHAR pathW[] = {'P','a','t','h',0};
2511 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2513 WCHAR windowsdir[MAX_PATH];
2516 const char *data_dir;
2520 /* update locale dependent font info in registry */
2523 if(!init_freetype()) return FALSE;
2525 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2526 ERR("Failed to create font mutex\n");
2529 WaitForSingleObject(font_mutex, INFINITE);
2531 delete_external_font_keys();
2533 /* load the system bitmap fonts */
2534 load_system_fonts();
2536 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2537 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2538 strcatW(windowsdir, fontsW);
2539 if((unixname = wine_get_unix_file_name(windowsdir)))
2541 ReadFontDir(unixname, FALSE);
2542 HeapFree(GetProcessHeap(), 0, unixname);
2545 /* load the system truetype fonts */
2546 data_dir = wine_get_data_dir();
2547 if (!data_dir) data_dir = wine_get_build_dir();
2548 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2549 strcpy(unixname, data_dir);
2550 strcat(unixname, "/fonts/");
2551 ReadFontDir(unixname, TRUE);
2552 HeapFree(GetProcessHeap(), 0, unixname);
2555 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2556 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2557 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2559 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2560 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2561 &hkey) == ERROR_SUCCESS) {
2563 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2564 &valuelen, &datalen, NULL, NULL);
2566 valuelen++; /* returned value doesn't include room for '\0' */
2567 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2568 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2571 dlen = datalen * sizeof(WCHAR);
2573 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2574 &dlen) == ERROR_SUCCESS) {
2575 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2577 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2579 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2580 HeapFree(GetProcessHeap(), 0, unixname);
2583 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2585 WCHAR pathW[MAX_PATH];
2586 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2589 sprintfW(pathW, fmtW, windowsdir, data);
2590 if((unixname = wine_get_unix_file_name(pathW)))
2592 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2593 HeapFree(GetProcessHeap(), 0, unixname);
2596 load_font_from_data_dir(data);
2598 /* reset dlen and vlen */
2603 HeapFree(GetProcessHeap(), 0, data);
2604 HeapFree(GetProcessHeap(), 0, valueW);
2608 load_fontconfig_fonts();
2610 /* then look in any directories that we've specified in the config file */
2611 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2612 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2618 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2620 len += sizeof(WCHAR);
2621 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2622 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2624 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2625 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2626 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2627 TRACE( "got font path %s\n", debugstr_a(valueA) );
2631 LPSTR next = strchr( ptr, ':' );
2632 if (next) *next++ = 0;
2633 ReadFontDir( ptr, TRUE );
2636 HeapFree( GetProcessHeap(), 0, valueA );
2638 HeapFree( GetProcessHeap(), 0, valueW );
2647 update_reg_entries();
2649 init_system_links();
2651 ReleaseMutex(font_mutex);
2656 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2659 TT_HoriHeader *pHori;
2663 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2664 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2666 if(height == 0) height = 16;
2668 /* Calc. height of EM square:
2670 * For +ve lfHeight we have
2671 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2672 * Re-arranging gives:
2673 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2675 * For -ve lfHeight we have
2677 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2678 * with il = winAscent + winDescent - units_per_em]
2683 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2684 ppem = MulDiv(ft_face->units_per_EM, height,
2685 pHori->Ascender - pHori->Descender);
2687 ppem = MulDiv(ft_face->units_per_EM, height,
2688 pOS2->usWinAscent + pOS2->usWinDescent);
2696 static struct font_mapping *map_font_file( const char *name )
2698 struct font_mapping *mapping;
2702 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2703 if (fstat( fd, &st ) == -1) goto error;
2705 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2707 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2709 mapping->refcount++;
2714 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2717 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2720 if (mapping->data == MAP_FAILED)
2722 HeapFree( GetProcessHeap(), 0, mapping );
2725 mapping->refcount = 1;
2726 mapping->dev = st.st_dev;
2727 mapping->ino = st.st_ino;
2728 mapping->size = st.st_size;
2729 list_add_tail( &mappings_list, &mapping->entry );
2737 static void unmap_font_file( struct font_mapping *mapping )
2739 if (!--mapping->refcount)
2741 list_remove( &mapping->entry );
2742 munmap( mapping->data, mapping->size );
2743 HeapFree( GetProcessHeap(), 0, mapping );
2747 static LONG load_VDMX(GdiFont*, LONG);
2749 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2756 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2760 if (!(font->mapping = map_font_file( face->file )))
2762 WARN("failed to map %s\n", debugstr_a(face->file));
2765 data_ptr = font->mapping->data;
2766 data_size = font->mapping->size;
2770 data_ptr = face->font_data_ptr;
2771 data_size = face->font_data_size;
2774 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2776 ERR("FT_New_Face rets %d\n", err);
2780 /* set it here, as load_VDMX needs it */
2781 font->ft_face = ft_face;
2783 if(FT_IS_SCALABLE(ft_face)) {
2784 /* load the VDMX table if we have one */
2785 font->ppem = load_VDMX(font, height);
2787 font->ppem = calc_ppem_for_height(ft_face, height);
2788 TRACE("height %d => ppem %d\n", height, font->ppem);
2790 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2791 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2793 font->ppem = height;
2794 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2795 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2801 static int get_nearest_charset(Face *face, int *cp)
2803 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2804 a single face with the requested charset. The idea is to check if
2805 the selected font supports the current ANSI codepage, if it does
2806 return the corresponding charset, else return the first charset */
2809 int acp = GetACP(), i;
2813 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2814 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2815 return csi.ciCharset;
2817 for(i = 0; i < 32; i++) {
2819 if(face->fs.fsCsb[0] & fs0) {
2820 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2822 return csi.ciCharset;
2825 FIXME("TCI failing on %x\n", fs0);
2829 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2830 face->fs.fsCsb[0], face->file);
2832 return DEFAULT_CHARSET;
2835 static GdiFont *alloc_font(void)
2837 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2839 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2840 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2842 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2843 ret->total_kern_pairs = (DWORD)-1;
2844 ret->kern_pairs = NULL;
2845 list_init(&ret->hfontlist);
2846 list_init(&ret->child_fonts);
2850 static void free_font(GdiFont *font)
2852 struct list *cursor, *cursor2;
2855 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2857 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2858 struct list *first_hfont;
2859 HFONTLIST *hfontlist;
2860 list_remove(cursor);
2863 first_hfont = list_head(&child->font->hfontlist);
2864 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2865 DeleteObject(hfontlist->hfont);
2866 HeapFree(GetProcessHeap(), 0, hfontlist);
2867 free_font(child->font);
2869 HeapFree(GetProcessHeap(), 0, child);
2872 if (font->ft_face) pFT_Done_Face(font->ft_face);
2873 if (font->mapping) unmap_font_file( font->mapping );
2874 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2875 HeapFree(GetProcessHeap(), 0, font->potm);
2876 HeapFree(GetProcessHeap(), 0, font->name);
2877 for (i = 0; i < font->gmsize; i++)
2878 HeapFree(GetProcessHeap(),0,font->gm[i]);
2879 HeapFree(GetProcessHeap(), 0, font->gm);
2880 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2881 HeapFree(GetProcessHeap(), 0, font);
2885 /*************************************************************
2888 * load the vdmx entry for the specified height
2891 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2892 ( ( (FT_ULong)_x4 << 24 ) | \
2893 ( (FT_ULong)_x3 << 16 ) | \
2894 ( (FT_ULong)_x2 << 8 ) | \
2897 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2912 static LONG load_VDMX(GdiFont *font, LONG height)
2916 BYTE devXRatio, devYRatio;
2917 USHORT numRecs, numRatios;
2918 DWORD result, offset = -1;
2922 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2924 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2927 /* FIXME: need the real device aspect ratio */
2931 numRecs = GET_BE_WORD(hdr[1]);
2932 numRatios = GET_BE_WORD(hdr[2]);
2934 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2935 for(i = 0; i < numRatios; i++) {
2938 offset = (3 * 2) + (i * sizeof(Ratios));
2939 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2942 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2944 if((ratio.xRatio == 0 &&
2945 ratio.yStartRatio == 0 &&
2946 ratio.yEndRatio == 0) ||
2947 (devXRatio == ratio.xRatio &&
2948 devYRatio >= ratio.yStartRatio &&
2949 devYRatio <= ratio.yEndRatio))
2951 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2952 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2953 offset = GET_BE_WORD(tmp);
2959 FIXME("No suitable ratio found\n");
2963 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2965 BYTE startsz, endsz;
2968 recs = GET_BE_WORD(group.recs);
2969 startsz = group.startsz;
2970 endsz = group.endsz;
2972 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2974 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2975 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2976 if(result == GDI_ERROR) {
2977 FIXME("Failed to retrieve vTable\n");
2982 for(i = 0; i < recs; i++) {
2983 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2984 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2985 ppem = GET_BE_WORD(vTable[i * 3]);
2987 if(yMax + -yMin == height) {
2990 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2993 if(yMax + -yMin > height) {
2996 goto end; /* failed */
2998 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2999 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3000 ppem = GET_BE_WORD(vTable[i * 3]);
3001 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3007 TRACE("ppem not found for height %d\n", height);
3011 if(ppem < startsz || ppem > endsz)
3014 for(i = 0; i < recs; i++) {
3016 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3018 if(yPelHeight > ppem)
3021 if(yPelHeight == ppem) {
3022 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3023 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3024 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
3030 HeapFree(GetProcessHeap(), 0, vTable);
3036 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3038 if(font->font_desc.hash != fd->hash) return TRUE;
3039 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3040 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3041 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3042 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3045 static void calc_hash(FONT_DESC *pfd)
3047 DWORD hash = 0, *ptr, two_chars;
3051 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3053 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3055 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3057 pwc = (WCHAR *)&two_chars;
3059 *pwc = toupperW(*pwc);
3061 *pwc = toupperW(*pwc);
3065 hash ^= !pfd->can_use_bitmap;
3070 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const XFORM *pxf, BOOL can_use_bitmap)
3075 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3078 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
3079 fd.can_use_bitmap = can_use_bitmap;
3082 /* try the in-use list */
3083 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3084 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3085 if(!fontcmp(ret, &fd)) {
3086 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3087 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3088 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3089 if(hflist->hfont == hfont)
3092 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3093 hflist->hfont = hfont;
3094 list_add_head(&ret->hfontlist, &hflist->entry);
3099 /* then the unused list */
3100 font_elem_ptr = list_head(&unused_gdi_font_list);
3101 while(font_elem_ptr) {
3102 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3103 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3104 if(!fontcmp(ret, &fd)) {
3105 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3106 assert(list_empty(&ret->hfontlist));
3107 TRACE("Found %p in unused list\n", ret);
3108 list_remove(&ret->entry);
3109 list_add_head(&gdi_font_list, &ret->entry);
3110 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3111 hflist->hfont = hfont;
3112 list_add_head(&ret->hfontlist, &hflist->entry);
3120 /*************************************************************
3121 * create_child_font_list
3123 static BOOL create_child_font_list(GdiFont *font)
3126 SYSTEM_LINKS *font_link;
3127 CHILD_FONT *font_link_entry, *new_child;
3129 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3131 if(!strcmpW(font_link->font_name, font->name))
3133 TRACE("found entry in system list\n");
3134 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3136 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3137 new_child->face = font_link_entry->face;
3138 new_child->font = NULL;
3139 list_add_tail(&font->child_fonts, &new_child->entry);
3140 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3147 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3148 * Sans Serif. This is how asian windows get default fallbacks for fonts
3150 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3151 font->charset != OEM_CHARSET &&
3152 strcmpW(font->name,szDefaultFallbackLink) != 0)
3153 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3155 if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3157 TRACE("found entry in default fallback list\n");
3158 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3160 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3161 new_child->face = font_link_entry->face;
3162 new_child->font = NULL;
3163 list_add_tail(&font->child_fonts, &new_child->entry);
3164 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3174 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3176 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3178 if (pFT_Set_Charmap)
3181 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3183 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3185 for (i = 0; i < ft_face->num_charmaps; i++)
3187 if (ft_face->charmaps[i]->encoding == encoding)
3189 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3190 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3192 switch (ft_face->charmaps[i]->platform_id)
3195 cmap_def = ft_face->charmaps[i];
3197 case 0: /* Apple Unicode */
3198 cmap0 = ft_face->charmaps[i];
3200 case 1: /* Macintosh */
3201 cmap1 = ft_face->charmaps[i];
3204 cmap2 = ft_face->charmaps[i];
3206 case 3: /* Microsoft */
3207 cmap3 = ft_face->charmaps[i];
3212 if (cmap3) /* prefer Microsoft cmap table */
3213 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3215 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3217 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3219 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3221 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3223 return ft_err == FT_Err_Ok;
3226 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3229 /*************************************************************
3230 * WineEngCreateFontInstance
3233 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3236 Face *face, *best, *best_bitmap;
3237 Family *family, *last_resort_family;
3238 struct list *family_elem_ptr, *face_elem_ptr;
3239 INT height, width = 0;
3240 unsigned int score = 0, new_score;
3241 signed int diff = 0, newdiff;
3242 BOOL bd, it, can_use_bitmap;
3246 FontSubst *psub = NULL;
3248 EnterCriticalSection( &freetype_cs );
3250 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
3252 struct list *first_hfont = list_head(&ret->hfontlist);
3253 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3254 if(hflist->hfont == hfont)
3256 LeaveCriticalSection( &freetype_cs );
3261 if (!GetObjectW( hfont, sizeof(lf), &lf ))
3263 LeaveCriticalSection( &freetype_cs );
3266 lf.lfWidth = abs(lf.lfWidth);
3268 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3270 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3271 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3272 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3275 TRACE("DC transform %f %f %f %f %f %f\n",
3276 dc->xformWorld2Vport.eM11, dc->xformWorld2Vport.eM12,
3277 dc->xformWorld2Vport.eM21, dc->xformWorld2Vport.eM22,
3278 dc->xformWorld2Vport.eDx, dc->xformWorld2Vport.eDy);
3280 /* check the cache first */
3281 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
3282 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3283 LeaveCriticalSection( &freetype_cs );
3287 TRACE("not in cache\n");
3288 if(list_empty(&font_list)) /* No fonts installed */
3290 TRACE("No fonts installed\n");
3291 LeaveCriticalSection( &freetype_cs );
3294 if(!have_installed_roman_font)
3296 TRACE("No roman font installed\n");
3297 LeaveCriticalSection( &freetype_cs );
3303 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
3304 ret->font_desc.lf = lf;
3305 ret->font_desc.can_use_bitmap = can_use_bitmap;
3306 calc_hash(&ret->font_desc);
3307 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3308 hflist->hfont = hfont;
3309 list_add_head(&ret->hfontlist, &hflist->entry);
3312 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3313 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3314 original value lfCharSet. Note this is a special case for
3315 Symbol and doesn't happen at least for "Wingdings*" */
3317 if(!strcmpiW(lf.lfFaceName, SymbolW))
3318 lf.lfCharSet = SYMBOL_CHARSET;
3320 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3321 switch(lf.lfCharSet) {
3322 case DEFAULT_CHARSET:
3323 csi.fs.fsCsb[0] = 0;
3326 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3327 csi.fs.fsCsb[0] = 0;
3333 if(lf.lfFaceName[0] != '\0') {
3334 SYSTEM_LINKS *font_link;
3335 CHILD_FONT *font_link_entry;
3336 LPWSTR FaceName = lf.lfFaceName;
3339 * Check for a leading '@' this signals that the font is being
3340 * requested in tategaki mode (vertical writing substitution) but
3341 * does not affect the fontface that is to be selected.
3343 if (lf.lfFaceName[0]=='@')
3344 FaceName = &lf.lfFaceName[1];
3346 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3349 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3350 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3351 if (psub->to.charset != -1)
3352 lf.lfCharSet = psub->to.charset;
3355 /* We want a match on name and charset or just name if
3356 charset was DEFAULT_CHARSET. If the latter then
3357 we fixup the returned charset later in get_nearest_charset
3358 where we'll either use the charset of the current ansi codepage
3359 or if that's unavailable the first charset that the font supports.
3361 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3362 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3363 if (!strcmpiW(family->FamilyName, FaceName) ||
3364 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3366 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3367 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3368 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3369 if(face->scalable || can_use_bitmap)
3376 * Try check the SystemLink list first for a replacement font.
3377 * We may find good replacements there.
3379 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3381 if(!strcmpiW(font_link->font_name, FaceName))
3383 TRACE("found entry in system list\n");
3384 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3386 face = font_link_entry->face;
3387 family = face->family;
3388 if(csi.fs.fsCsb[0] &
3389 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3391 if(face->scalable || can_use_bitmap)
3399 psub = NULL; /* substitution is no more relevant */
3401 /* If requested charset was DEFAULT_CHARSET then try using charset
3402 corresponding to the current ansi codepage */
3403 if (!csi.fs.fsCsb[0] || lf.lfWeight == FW_DONTCARE)
3406 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3407 FIXME("TCI failed on codepage %d\n", acp);
3408 csi.fs.fsCsb[0] = 0;
3410 lf.lfCharSet = csi.ciCharset;
3413 /* Face families are in the top 4 bits of lfPitchAndFamily,
3414 so mask with 0xF0 before testing */
3416 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3417 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3418 strcpyW(lf.lfFaceName, defFixed);
3419 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3420 strcpyW(lf.lfFaceName, defSerif);
3421 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3422 strcpyW(lf.lfFaceName, defSans);
3424 strcpyW(lf.lfFaceName, defSans);
3425 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3426 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3427 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3428 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3429 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3430 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3431 if(face->scalable || can_use_bitmap)
3437 last_resort_family = NULL;
3438 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3439 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3440 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3441 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3442 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3445 if(can_use_bitmap && !last_resort_family)
3446 last_resort_family = family;
3451 if(last_resort_family) {
3452 family = last_resort_family;
3453 csi.fs.fsCsb[0] = 0;
3457 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3458 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3459 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3460 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3461 if(face->scalable) {
3462 csi.fs.fsCsb[0] = 0;
3463 WARN("just using first face for now\n");
3466 if(can_use_bitmap && !last_resort_family)
3467 last_resort_family = family;
3470 if(!last_resort_family) {
3471 FIXME("can't find a single appropriate font - bailing\n");
3473 LeaveCriticalSection( &freetype_cs );
3477 WARN("could only find a bitmap font - this will probably look awful!\n");
3478 family = last_resort_family;
3479 csi.fs.fsCsb[0] = 0;
3482 it = lf.lfItalic ? 1 : 0;
3483 bd = lf.lfWeight > 550 ? 1 : 0;
3485 height = lf.lfHeight;
3487 face = best = best_bitmap = NULL;
3488 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3490 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3494 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3495 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3496 new_score = (italic ^ it) + (bold ^ bd);
3497 if(!best || new_score <= score)
3499 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3500 italic, bold, it, bd);
3503 if(best->scalable && score == 0) break;
3507 newdiff = height - (signed int)(best->size.height);
3509 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3510 if(!best_bitmap || new_score < score ||
3511 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3513 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3516 if(score == 0 && diff == 0) break;
3523 face = best->scalable ? best : best_bitmap;
3524 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3525 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3529 if(csi.fs.fsCsb[0]) {
3530 ret->charset = lf.lfCharSet;
3531 ret->codepage = csi.ciACP;
3534 ret->charset = get_nearest_charset(face, &ret->codepage);
3536 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3537 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3539 ret->aveWidth = height ? lf.lfWidth : 0;
3541 if(!face->scalable) {
3542 /* Windows uses integer scaling factors for bitmap fonts */
3543 INT scale, scaled_height;
3545 if (height != 0) height = diff;
3546 height += face->size.height;
3548 scale = (height + face->size.height - 1) / face->size.height;
3549 scaled_height = scale * face->size.height;
3550 /* XP allows not more than 10% deviation */
3551 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3552 ret->scale_y = scale;
3554 width = face->size.x_ppem >> 6;
3555 height = face->size.y_ppem >> 6;
3559 TRACE("font scale y: %f\n", ret->scale_y);
3561 ret->ft_face = OpenFontFace(ret, face, width, height);
3566 LeaveCriticalSection( &freetype_cs );
3570 ret->ntmFlags = face->ntmFlags;
3572 if (ret->charset == SYMBOL_CHARSET &&
3573 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3576 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3580 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3583 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3584 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3585 ret->underline = lf.lfUnderline ? 0xff : 0;
3586 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3587 create_child_font_list(ret);
3589 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3591 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3592 if (length != GDI_ERROR)
3594 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3595 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3596 TRACE("Loaded GSUB table of %i bytes\n",length);
3600 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3602 list_add_head(&gdi_font_list, &ret->entry);
3603 LeaveCriticalSection( &freetype_cs );
3607 static void dump_gdi_font_list(void)
3610 struct list *elem_ptr;
3612 TRACE("---------- gdiFont Cache ----------\n");
3613 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3614 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3615 TRACE("gdiFont=%p %s %d\n",
3616 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3619 TRACE("---------- Unused gdiFont Cache ----------\n");
3620 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3621 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3622 TRACE("gdiFont=%p %s %d\n",
3623 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3627 /*************************************************************
3628 * WineEngDestroyFontInstance
3630 * free the gdiFont associated with this handle
3633 BOOL WineEngDestroyFontInstance(HFONT handle)
3638 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3641 EnterCriticalSection( &freetype_cs );
3643 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3645 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3646 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3647 if(hflist->hfont == handle)
3649 TRACE("removing child font %p from child list\n", gdiFont);
3650 list_remove(&gdiFont->entry);
3651 LeaveCriticalSection( &freetype_cs );
3656 TRACE("destroying hfont=%p\n", handle);
3658 dump_gdi_font_list();
3660 font_elem_ptr = list_head(&gdi_font_list);
3661 while(font_elem_ptr) {
3662 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3663 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3665 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3666 while(hfontlist_elem_ptr) {
3667 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3668 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3669 if(hflist->hfont == handle) {
3670 list_remove(&hflist->entry);
3671 HeapFree(GetProcessHeap(), 0, hflist);
3675 if(list_empty(&gdiFont->hfontlist)) {
3676 TRACE("Moving to Unused list\n");
3677 list_remove(&gdiFont->entry);
3678 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3683 font_elem_ptr = list_head(&unused_gdi_font_list);
3684 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3685 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3686 while(font_elem_ptr) {
3687 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3688 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3689 TRACE("freeing %p\n", gdiFont);
3690 list_remove(&gdiFont->entry);
3693 LeaveCriticalSection( &freetype_cs );
3697 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3698 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3703 if (face->cached_enum_data)
3706 *pelf = face->cached_enum_data->elf;
3707 *pntm = face->cached_enum_data->ntm;
3708 *ptype = face->cached_enum_data->type;
3712 font = alloc_font();
3714 if(face->scalable) {
3715 height = -2048; /* 2048 is the most common em size */
3718 height = face->size.y_ppem >> 6;
3719 width = face->size.x_ppem >> 6;
3721 font->scale_y = 1.0;
3723 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3729 font->name = strdupW(face->family->FamilyName);
3730 font->ntmFlags = face->ntmFlags;
3732 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3734 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3736 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3738 lstrcpynW(pelf->elfLogFont.lfFaceName,
3739 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3741 lstrcpynW(pelf->elfFullName,
3742 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3744 lstrcpynW(pelf->elfStyle,
3745 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3750 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3752 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3754 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3755 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3756 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3759 pntm->ntmTm.ntmFlags = face->ntmFlags;
3760 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3761 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3762 pntm->ntmFontSig = face->fs;
3764 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3766 pelf->elfLogFont.lfEscapement = 0;
3767 pelf->elfLogFont.lfOrientation = 0;
3768 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3769 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3770 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3771 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3772 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3773 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3774 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3775 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3776 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3777 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3778 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3781 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3782 *ptype |= TRUETYPE_FONTTYPE;
3783 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3784 *ptype |= DEVICE_FONTTYPE;
3785 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3786 *ptype |= RASTER_FONTTYPE;
3788 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3789 if (face->cached_enum_data)
3791 face->cached_enum_data->elf = *pelf;
3792 face->cached_enum_data->ntm = *pntm;
3793 face->cached_enum_data->type = *ptype;
3799 /*************************************************************
3803 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3807 struct list *family_elem_ptr, *face_elem_ptr;
3809 NEWTEXTMETRICEXW ntm;
3818 lf.lfCharSet = DEFAULT_CHARSET;
3819 lf.lfPitchAndFamily = 0;
3820 lf.lfFaceName[0] = 0;
3824 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3826 EnterCriticalSection( &freetype_cs );
3827 if(plf->lfFaceName[0]) {
3829 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3832 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3833 debugstr_w(psub->to.name));
3835 strcpyW(lf.lfFaceName, psub->to.name);
3839 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3840 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3841 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3842 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3843 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3844 GetEnumStructs(face, &elf, &ntm, &type);
3845 for(i = 0; i < 32; i++) {
3846 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3847 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3848 strcpyW(elf.elfScript, OEM_DOSW);
3849 i = 32; /* break out of loop */
3850 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3853 fs.fsCsb[0] = 1L << i;
3855 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3857 csi.ciCharset = DEFAULT_CHARSET;
3858 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3859 if(csi.ciCharset != DEFAULT_CHARSET) {
3860 elf.elfLogFont.lfCharSet =
3861 ntm.ntmTm.tmCharSet = csi.ciCharset;
3863 strcpyW(elf.elfScript, ElfScriptsW[i]);
3865 FIXME("Unknown elfscript for bit %d\n", i);
3868 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3869 debugstr_w(elf.elfLogFont.lfFaceName),
3870 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3871 csi.ciCharset, type, debugstr_w(elf.elfScript),
3872 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3873 ntm.ntmTm.ntmFlags);
3874 /* release section before callback (FIXME) */
3875 LeaveCriticalSection( &freetype_cs );
3876 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3877 EnterCriticalSection( &freetype_cs );
3883 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3884 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3885 face_elem_ptr = list_head(&family->faces);
3886 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3887 GetEnumStructs(face, &elf, &ntm, &type);
3888 for(i = 0; i < 32; i++) {
3889 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3890 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3891 strcpyW(elf.elfScript, OEM_DOSW);
3892 i = 32; /* break out of loop */
3893 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3896 fs.fsCsb[0] = 1L << i;
3898 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3900 csi.ciCharset = DEFAULT_CHARSET;
3901 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3902 if(csi.ciCharset != DEFAULT_CHARSET) {
3903 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3906 strcpyW(elf.elfScript, ElfScriptsW[i]);
3908 FIXME("Unknown elfscript for bit %d\n", i);
3911 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3912 debugstr_w(elf.elfLogFont.lfFaceName),
3913 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3914 csi.ciCharset, type, debugstr_w(elf.elfScript),
3915 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3916 ntm.ntmTm.ntmFlags);
3917 /* release section before callback (FIXME) */
3918 LeaveCriticalSection( &freetype_cs );
3919 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3920 EnterCriticalSection( &freetype_cs );
3924 LeaveCriticalSection( &freetype_cs );
3928 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3930 pt->x.value = vec->x >> 6;
3931 pt->x.fract = (vec->x & 0x3f) << 10;
3932 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3933 pt->y.value = vec->y >> 6;
3934 pt->y.fract = (vec->y & 0x3f) << 10;
3935 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3939 /***************************************************
3940 * According to the MSDN documentation on WideCharToMultiByte,
3941 * certain codepages cannot set the default_used parameter.
3942 * This returns TRUE if the codepage can set that parameter, false else
3943 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3945 static BOOL codepage_sets_default_used(UINT codepage)
3959 * GSUB Table handling functions
3962 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
3964 const GSUB_CoverageFormat1* cf1;
3966 cf1 = (GSUB_CoverageFormat1*)table;
3968 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
3970 int count = GET_BE_WORD(cf1->GlyphCount);
3972 TRACE("Coverage Format 1, %i glyphs\n",count);
3973 for (i = 0; i < count; i++)
3974 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
3978 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
3980 const GSUB_CoverageFormat2* cf2;
3983 cf2 = (GSUB_CoverageFormat2*)cf1;
3985 count = GET_BE_WORD(cf2->RangeCount);
3986 TRACE("Coverage Format 2, %i ranges\n",count);
3987 for (i = 0; i < count; i++)
3989 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
3991 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
3992 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
3994 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
3995 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4001 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4006 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4008 const GSUB_ScriptList *script;
4009 const GSUB_Script *deflt = NULL;
4011 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
4013 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4014 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4016 const GSUB_Script *scr;
4019 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4020 scr = (GSUB_Script*)((LPBYTE)script + offset);
4022 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4024 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4030 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4034 const GSUB_LangSys *Lang;
4036 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4038 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4040 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4041 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4043 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4046 offset = GET_BE_WORD(script->DefaultLangSys);
4049 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4055 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4058 const GSUB_FeatureList *feature;
4059 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
4061 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4062 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4064 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4065 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4067 const GSUB_Feature *feat;
4068 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4075 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4079 const GSUB_LookupList *lookup;
4080 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
4082 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4083 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4085 const GSUB_LookupTable *look;
4086 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4087 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
4088 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4089 if (GET_BE_WORD(look->LookupType) != 1)
4090 FIXME("We only handle SubType 1\n");
4095 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4097 const GSUB_SingleSubstFormat1 *ssf1;
4098 offset = GET_BE_WORD(look->SubTable[j]);
4099 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
4100 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4102 int offset = GET_BE_WORD(ssf1->Coverage);
4103 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4104 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
4106 TRACE(" Glyph 0x%x ->",glyph);
4107 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4108 TRACE(" 0x%x\n",glyph);
4113 const GSUB_SingleSubstFormat2 *ssf2;
4117 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
4118 offset = GET_BE_WORD(ssf1->Coverage);
4119 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4120 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
4121 TRACE(" Coverage index %i\n",index);
4124 TRACE(" Glyph is 0x%x ->",glyph);
4125 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4126 TRACE("0x%x\n",glyph);
4135 static const char* get_opentype_script(const GdiFont *font)
4138 * I am not sure if this is the correct way to generate our script tag
4141 switch (font->charset)
4143 case ANSI_CHARSET: return "latn";
4144 case BALTIC_CHARSET: return "latn"; /* ?? */
4145 case CHINESEBIG5_CHARSET: return "hani";
4146 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4147 case GB2312_CHARSET: return "hani";
4148 case GREEK_CHARSET: return "grek";
4149 case HANGUL_CHARSET: return "hang";
4150 case RUSSIAN_CHARSET: return "cyrl";
4151 case SHIFTJIS_CHARSET: return "kana";
4152 case TURKISH_CHARSET: return "latn"; /* ?? */
4153 case VIETNAMESE_CHARSET: return "latn";
4154 case JOHAB_CHARSET: return "latn"; /* ?? */
4155 case ARABIC_CHARSET: return "arab";
4156 case HEBREW_CHARSET: return "hebr";
4157 case THAI_CHARSET: return "thai";
4158 default: return "latn";
4162 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4164 const GSUB_Header *header;
4165 const GSUB_Script *script;
4166 const GSUB_LangSys *language;
4167 const GSUB_Feature *feature;
4169 if (!font->GSUB_Table)
4172 header = font->GSUB_Table;
4174 script = GSUB_get_script_table(header, get_opentype_script(font));
4177 TRACE("Script not found\n");
4180 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4183 TRACE("Language not found\n");
4186 feature = GSUB_get_feature(header, language, "vrt2");
4188 feature = GSUB_get_feature(header, language, "vert");
4191 TRACE("vrt2/vert feature not found\n");
4194 return GSUB_apply_feature(header, feature, glyph);
4197 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4201 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4202 WCHAR wc = (WCHAR)glyph;
4204 BOOL *default_used_pointer;
4207 default_used_pointer = NULL;
4208 default_used = FALSE;
4209 if (codepage_sets_default_used(font->codepage))
4210 default_used_pointer = &default_used;
4211 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4214 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4215 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4216 return get_GSUB_vert_glyph(font,ret);
4219 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4220 glyph = glyph + 0xf000;
4221 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4222 return get_GSUB_vert_glyph(font,glyphId);
4225 /*************************************************************
4226 * WineEngGetGlyphIndices
4229 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4230 LPWORD pgi, DWORD flags)
4233 int default_char = -1;
4235 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4237 for(i = 0; i < count; i++)
4239 pgi[i] = get_glyph_index(font, lpstr[i]);
4242 if (default_char == -1)
4244 if (FT_IS_SFNT(font->ft_face))
4246 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4247 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4252 WineEngGetTextMetrics(font, &textm);
4253 default_char = textm.tmDefaultChar;
4256 pgi[i] = default_char;
4262 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4264 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4265 return !memcmp(matrix, &identity, sizeof(FMAT2));
4268 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4270 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4271 return !memcmp(matrix, &identity, sizeof(MAT2));
4274 /*************************************************************
4275 * WineEngGetGlyphOutline
4277 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4278 * except that the first parameter is the HWINEENGFONT of the font in
4279 * question rather than an HDC.
4282 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4283 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4286 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4287 FT_Face ft_face = incoming_font->ft_face;
4288 GdiFont *font = incoming_font;
4289 FT_UInt glyph_index;
4290 DWORD width, height, pitch, needed = 0;
4291 FT_Bitmap ft_bitmap;
4293 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4295 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4296 double widthRatio = 1.0;
4297 FT_Matrix transMat = identityMat;
4298 BOOL needsTransform = FALSE;
4299 BOOL tategaki = (font->GSUB_Table != NULL);
4300 UINT original_index;
4302 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4303 buflen, buf, lpmat);
4305 TRACE("font transform %f %f %f %f\n",
4306 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4307 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4309 EnterCriticalSection( &freetype_cs );
4311 if(format & GGO_GLYPH_INDEX) {
4312 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4313 original_index = glyph;
4314 format &= ~GGO_GLYPH_INDEX;
4316 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4317 ft_face = font->ft_face;
4318 original_index = glyph_index;
4321 /* tategaki never appears to happen to lower glyph index */
4322 if (glyph_index < TATEGAKI_LOWER_BOUND )
4325 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4326 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4327 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4328 font->gmsize * sizeof(GM*));
4330 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4331 FONT_GM(font,original_index)->init && (!lpmat || is_identity_MAT2(lpmat)))
4333 *lpgm = FONT_GM(font,original_index)->gm;
4334 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4335 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4336 lpgm->gmCellIncX, lpgm->gmCellIncY);
4337 LeaveCriticalSection( &freetype_cs );
4338 return 1; /* FIXME */
4342 if (!font->gm[original_index / GM_BLOCK_SIZE])
4343 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4345 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || lpmat)
4346 load_flags |= FT_LOAD_NO_BITMAP;
4348 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4351 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4352 LeaveCriticalSection( &freetype_cs );
4356 /* Scaling factor */
4357 if (font->aveWidth && font->potm)
4359 widthRatio = (double)font->aveWidth;
4360 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4363 widthRatio = font->scale_y;
4365 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4366 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4368 adv = (INT)((ft_face->glyph->metrics.horiAdvance) + 63) >> 6;
4370 bbx = (right - left) >> 6;
4372 /* Scaling transform */
4373 if (widthRatio != 1.0 || font->scale_y != 1.0)
4376 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4379 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4381 pFT_Matrix_Multiply(&scaleMat, &transMat);
4382 needsTransform = TRUE;
4385 /* Slant transform */
4386 if (font->fake_italic) {
4389 slantMat.xx = (1 << 16);
4390 slantMat.xy = ((1 << 16) >> 2);
4392 slantMat.yy = (1 << 16);
4393 pFT_Matrix_Multiply(&slantMat, &transMat);
4394 needsTransform = TRUE;
4397 /* Rotation transform */
4398 if(font->orientation && !tategaki) {
4399 FT_Matrix rotationMat;
4401 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4402 pFT_Vector_Unit(&vecAngle, angle);
4403 rotationMat.xx = vecAngle.x;
4404 rotationMat.xy = -vecAngle.y;
4405 rotationMat.yx = -rotationMat.xy;
4406 rotationMat.yy = rotationMat.xx;
4408 pFT_Matrix_Multiply(&rotationMat, &transMat);
4409 needsTransform = TRUE;
4412 /* World transform */
4413 if (!is_identity_FMAT2(&font->font_desc.matrix))
4416 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4417 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4418 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4419 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4420 pFT_Matrix_Multiply(&worldMat, &transMat);
4421 needsTransform = TRUE;
4424 /* Extra transformation specified by caller */
4425 if (lpmat && !is_identity_MAT2(lpmat))
4428 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4429 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
4430 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
4431 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4432 pFT_Matrix_Multiply(&extraMat, &transMat);
4433 needsTransform = TRUE;
4436 if(!needsTransform) {
4437 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4438 bottom = (ft_face->glyph->metrics.horiBearingY -
4439 ft_face->glyph->metrics.height) & -64;
4440 lpgm->gmCellIncX = adv;
4441 lpgm->gmCellIncY = 0;
4445 for(xc = 0; xc < 2; xc++) {
4446 for(yc = 0; yc < 2; yc++) {
4447 vec.x = (ft_face->glyph->metrics.horiBearingX +
4448 xc * ft_face->glyph->metrics.width);
4449 vec.y = ft_face->glyph->metrics.horiBearingY -
4450 yc * ft_face->glyph->metrics.height;
4451 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4452 pFT_Vector_Transform(&vec, &transMat);
4453 if(xc == 0 && yc == 0) {
4454 left = right = vec.x;
4455 top = bottom = vec.y;
4457 if(vec.x < left) left = vec.x;
4458 else if(vec.x > right) right = vec.x;
4459 if(vec.y < bottom) bottom = vec.y;
4460 else if(vec.y > top) top = vec.y;
4465 right = (right + 63) & -64;
4466 bottom = bottom & -64;
4467 top = (top + 63) & -64;
4469 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4470 vec.x = ft_face->glyph->metrics.horiAdvance;
4472 pFT_Vector_Transform(&vec, &transMat);
4473 adv = lpgm->gmCellIncX = (vec.x+63) >> 6;
4474 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4476 lpgm->gmBlackBoxX = (right - left) >> 6;
4477 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4478 lpgm->gmptGlyphOrigin.x = left >> 6;
4479 lpgm->gmptGlyphOrigin.y = top >> 6;
4481 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4482 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4483 lpgm->gmCellIncX, lpgm->gmCellIncY);
4485 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4486 (!lpmat || is_identity_MAT2(lpmat))) /* don't cache custom transforms */
4488 FONT_GM(font,original_index)->gm = *lpgm;
4489 FONT_GM(font,original_index)->adv = adv;
4490 FONT_GM(font,original_index)->lsb = lsb;
4491 FONT_GM(font,original_index)->bbx = bbx;
4492 FONT_GM(font,original_index)->init = TRUE;
4495 if(format == GGO_METRICS)
4497 LeaveCriticalSection( &freetype_cs );
4498 return 1; /* FIXME */
4501 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
4502 TRACE("loaded a bitmap\n");
4503 LeaveCriticalSection( &freetype_cs );
4509 width = lpgm->gmBlackBoxX;
4510 height = lpgm->gmBlackBoxY;
4511 pitch = ((width + 31) >> 5) << 2;
4512 needed = pitch * height;
4514 if(!buf || !buflen) break;
4516 switch(ft_face->glyph->format) {
4517 case ft_glyph_format_bitmap:
4519 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4520 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4521 INT h = ft_face->glyph->bitmap.rows;
4523 memcpy(dst, src, w);
4524 src += ft_face->glyph->bitmap.pitch;
4530 case ft_glyph_format_outline:
4531 ft_bitmap.width = width;
4532 ft_bitmap.rows = height;
4533 ft_bitmap.pitch = pitch;
4534 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4535 ft_bitmap.buffer = buf;
4537 if(needsTransform) {
4538 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4541 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4543 /* Note: FreeType will only set 'black' bits for us. */
4544 memset(buf, 0, needed);
4545 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4549 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4550 LeaveCriticalSection( &freetype_cs );
4555 case GGO_GRAY2_BITMAP:
4556 case GGO_GRAY4_BITMAP:
4557 case GGO_GRAY8_BITMAP:
4558 case WINE_GGO_GRAY16_BITMAP:
4560 unsigned int mult, row, col;
4563 width = lpgm->gmBlackBoxX;
4564 height = lpgm->gmBlackBoxY;
4565 pitch = (width + 3) / 4 * 4;
4566 needed = pitch * height;
4568 if(!buf || !buflen) break;
4570 switch(ft_face->glyph->format) {
4571 case ft_glyph_format_bitmap:
4573 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4574 INT h = ft_face->glyph->bitmap.rows;
4577 for(x = 0; x < pitch; x++)
4579 if(x < ft_face->glyph->bitmap.width)
4580 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4584 src += ft_face->glyph->bitmap.pitch;
4587 LeaveCriticalSection( &freetype_cs );
4590 case ft_glyph_format_outline:
4592 ft_bitmap.width = width;
4593 ft_bitmap.rows = height;
4594 ft_bitmap.pitch = pitch;
4595 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4596 ft_bitmap.buffer = buf;
4599 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4601 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4603 memset(ft_bitmap.buffer, 0, buflen);
4605 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4607 if(format == GGO_GRAY2_BITMAP)
4609 else if(format == GGO_GRAY4_BITMAP)
4611 else if(format == GGO_GRAY8_BITMAP)
4613 else /* format == WINE_GGO_GRAY16_BITMAP */
4615 LeaveCriticalSection( &freetype_cs );
4621 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4622 LeaveCriticalSection( &freetype_cs );
4627 for(row = 0; row < height; row++) {
4629 for(col = 0; col < width; col++, ptr++) {
4630 *ptr = (((int)*ptr) * mult + 128) / 256;
4639 int contour, point = 0, first_pt;
4640 FT_Outline *outline = &ft_face->glyph->outline;
4641 TTPOLYGONHEADER *pph;
4643 DWORD pph_start, cpfx, type;
4645 if(buflen == 0) buf = NULL;
4647 if (needsTransform && buf) {
4648 pFT_Outline_Transform(outline, &transMat);
4651 for(contour = 0; contour < outline->n_contours; contour++) {
4653 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4656 pph->dwType = TT_POLYGON_TYPE;
4657 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4659 needed += sizeof(*pph);
4661 while(point <= outline->contours[contour]) {
4662 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4663 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4664 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4668 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4671 } while(point <= outline->contours[contour] &&
4672 (outline->tags[point] & FT_Curve_Tag_On) ==
4673 (outline->tags[point-1] & FT_Curve_Tag_On));
4674 /* At the end of a contour Windows adds the start point, but
4676 if(point > outline->contours[contour] &&
4677 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4679 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4681 } else if(point <= outline->contours[contour] &&
4682 outline->tags[point] & FT_Curve_Tag_On) {
4683 /* add closing pt for bezier */
4685 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4693 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4696 pph->cb = needed - pph_start;
4702 /* Convert the quadratic Beziers to cubic Beziers.
4703 The parametric eqn for a cubic Bezier is, from PLRM:
4704 r(t) = at^3 + bt^2 + ct + r0
4705 with the control points:
4710 A quadratic Beizer has the form:
4711 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4713 So equating powers of t leads to:
4714 r1 = 2/3 p1 + 1/3 p0
4715 r2 = 2/3 p1 + 1/3 p2
4716 and of course r0 = p0, r3 = p2
4719 int contour, point = 0, first_pt;
4720 FT_Outline *outline = &ft_face->glyph->outline;
4721 TTPOLYGONHEADER *pph;
4723 DWORD pph_start, cpfx, type;
4724 FT_Vector cubic_control[4];
4725 if(buflen == 0) buf = NULL;
4727 if (needsTransform && buf) {
4728 pFT_Outline_Transform(outline, &transMat);
4731 for(contour = 0; contour < outline->n_contours; contour++) {
4733 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4736 pph->dwType = TT_POLYGON_TYPE;
4737 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4739 needed += sizeof(*pph);
4741 while(point <= outline->contours[contour]) {
4742 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4743 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4744 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4747 if(type == TT_PRIM_LINE) {
4749 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4753 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4756 /* FIXME: Possible optimization in endpoint calculation
4757 if there are two consecutive curves */
4758 cubic_control[0] = outline->points[point-1];
4759 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4760 cubic_control[0].x += outline->points[point].x + 1;
4761 cubic_control[0].y += outline->points[point].y + 1;
4762 cubic_control[0].x >>= 1;
4763 cubic_control[0].y >>= 1;
4765 if(point+1 > outline->contours[contour])
4766 cubic_control[3] = outline->points[first_pt];
4768 cubic_control[3] = outline->points[point+1];
4769 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4770 cubic_control[3].x += outline->points[point].x + 1;
4771 cubic_control[3].y += outline->points[point].y + 1;
4772 cubic_control[3].x >>= 1;
4773 cubic_control[3].y >>= 1;
4776 /* r1 = 1/3 p0 + 2/3 p1
4777 r2 = 1/3 p2 + 2/3 p1 */
4778 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4779 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4780 cubic_control[2] = cubic_control[1];
4781 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4782 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4783 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4784 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4786 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4787 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4788 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4793 } while(point <= outline->contours[contour] &&
4794 (outline->tags[point] & FT_Curve_Tag_On) ==
4795 (outline->tags[point-1] & FT_Curve_Tag_On));
4796 /* At the end of a contour Windows adds the start point,
4797 but only for Beziers and we've already done that.
4799 if(point <= outline->contours[contour] &&
4800 outline->tags[point] & FT_Curve_Tag_On) {
4801 /* This is the closing pt of a bezier, but we've already
4802 added it, so just inc point and carry on */
4809 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4812 pph->cb = needed - pph_start;
4818 FIXME("Unsupported format %d\n", format);
4819 LeaveCriticalSection( &freetype_cs );
4822 LeaveCriticalSection( &freetype_cs );
4826 static BOOL get_bitmap_text_metrics(GdiFont *font)
4828 FT_Face ft_face = font->ft_face;
4829 #ifdef HAVE_FREETYPE_FTWINFNT_H
4830 FT_WinFNT_HeaderRec winfnt_header;
4832 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4833 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4834 font->potm->otmSize = size;
4836 #define TM font->potm->otmTextMetrics
4837 #ifdef HAVE_FREETYPE_FTWINFNT_H
4838 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4840 TM.tmHeight = winfnt_header.pixel_height;
4841 TM.tmAscent = winfnt_header.ascent;
4842 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4843 TM.tmInternalLeading = winfnt_header.internal_leading;
4844 TM.tmExternalLeading = winfnt_header.external_leading;
4845 TM.tmAveCharWidth = winfnt_header.avg_width;
4846 TM.tmMaxCharWidth = winfnt_header.max_width;
4847 TM.tmWeight = winfnt_header.weight;
4849 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4850 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4851 TM.tmFirstChar = winfnt_header.first_char;
4852 TM.tmLastChar = winfnt_header.last_char;
4853 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4854 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4855 TM.tmItalic = winfnt_header.italic;
4856 TM.tmUnderlined = font->underline;
4857 TM.tmStruckOut = font->strikeout;
4858 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4859 TM.tmCharSet = winfnt_header.charset;
4864 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4865 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4866 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4867 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4868 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4869 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4870 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4871 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4873 TM.tmDigitizedAspectX = 96; /* FIXME */
4874 TM.tmDigitizedAspectY = 96; /* FIXME */
4876 TM.tmLastChar = 255;
4877 TM.tmDefaultChar = 32;
4878 TM.tmBreakChar = 32;
4879 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4880 TM.tmUnderlined = font->underline;
4881 TM.tmStruckOut = font->strikeout;
4882 /* NB inverted meaning of TMPF_FIXED_PITCH */
4883 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4884 TM.tmCharSet = font->charset;
4892 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
4894 double scale_x, scale_y;
4898 scale_x = (double)font->aveWidth;
4899 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4902 scale_x = font->scale_y;
4904 scale_x *= fabs(font->font_desc.matrix.eM11);
4905 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
4907 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
4908 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
4910 SCALE_Y(ptm->tmHeight);
4911 SCALE_Y(ptm->tmAscent);
4912 SCALE_Y(ptm->tmDescent);
4913 SCALE_Y(ptm->tmInternalLeading);
4914 SCALE_Y(ptm->tmExternalLeading);
4915 SCALE_Y(ptm->tmOverhang);
4917 SCALE_X(ptm->tmAveCharWidth);
4918 SCALE_X(ptm->tmMaxCharWidth);
4924 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
4926 double scale_x, scale_y;
4930 scale_x = (double)font->aveWidth;
4931 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4934 scale_x = font->scale_y;
4936 scale_x *= fabs(font->font_desc.matrix.eM11);
4937 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
4939 scale_font_metrics(font, &potm->otmTextMetrics);
4941 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
4942 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
4944 SCALE_Y(potm->otmAscent);
4945 SCALE_Y(potm->otmDescent);
4946 SCALE_Y(potm->otmLineGap);
4947 SCALE_Y(potm->otmsCapEmHeight);
4948 SCALE_Y(potm->otmsXHeight);
4949 SCALE_Y(potm->otmrcFontBox.top);
4950 SCALE_Y(potm->otmrcFontBox.bottom);
4951 SCALE_X(potm->otmrcFontBox.left);
4952 SCALE_X(potm->otmrcFontBox.right);
4953 SCALE_Y(potm->otmMacAscent);
4954 SCALE_Y(potm->otmMacDescent);
4955 SCALE_Y(potm->otmMacLineGap);
4956 SCALE_X(potm->otmptSubscriptSize.x);
4957 SCALE_Y(potm->otmptSubscriptSize.y);
4958 SCALE_X(potm->otmptSubscriptOffset.x);
4959 SCALE_Y(potm->otmptSubscriptOffset.y);
4960 SCALE_X(potm->otmptSuperscriptSize.x);
4961 SCALE_Y(potm->otmptSuperscriptSize.y);
4962 SCALE_X(potm->otmptSuperscriptOffset.x);
4963 SCALE_Y(potm->otmptSuperscriptOffset.y);
4964 SCALE_Y(potm->otmsStrikeoutSize);
4965 SCALE_Y(potm->otmsStrikeoutPosition);
4966 SCALE_Y(potm->otmsUnderscoreSize);
4967 SCALE_Y(potm->otmsUnderscorePosition);
4973 /*************************************************************
4974 * WineEngGetTextMetrics
4977 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4979 EnterCriticalSection( &freetype_cs );
4981 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
4982 if(!get_bitmap_text_metrics(font))
4984 LeaveCriticalSection( &freetype_cs );
4990 LeaveCriticalSection( &freetype_cs );
4993 *ptm = font->potm->otmTextMetrics;
4994 scale_font_metrics(font, ptm);
4995 LeaveCriticalSection( &freetype_cs );
5000 /*************************************************************
5001 * WineEngGetOutlineTextMetrics
5004 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5005 OUTLINETEXTMETRICW *potm)
5007 FT_Face ft_face = font->ft_face;
5008 UINT needed, lenfam, lensty, ret;
5010 TT_HoriHeader *pHori;
5011 TT_Postscript *pPost;
5012 FT_Fixed x_scale, y_scale;
5013 WCHAR *family_nameW, *style_nameW;
5014 static const WCHAR spaceW[] = {' ', '\0'};
5016 INT ascent, descent;
5018 TRACE("font=%p\n", font);
5020 if(!FT_IS_SCALABLE(ft_face))
5023 EnterCriticalSection( &freetype_cs );
5026 if(cbSize >= font->potm->otmSize)
5028 memcpy(potm, font->potm, font->potm->otmSize);
5029 scale_outline_font_metrics(font, potm);
5031 LeaveCriticalSection( &freetype_cs );
5032 return font->potm->otmSize;
5036 needed = sizeof(*potm);
5038 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5039 family_nameW = strdupW(font->name);
5041 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5043 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5044 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5045 style_nameW, lensty/sizeof(WCHAR));
5047 /* These names should be read from the TT name table */
5049 /* length of otmpFamilyName */
5052 /* length of otmpFaceName */
5053 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5054 needed += lenfam; /* just the family name */
5056 needed += lenfam + lensty; /* family + " " + style */
5059 /* length of otmpStyleName */
5062 /* length of otmpFullName */
5063 needed += lenfam + lensty;
5066 x_scale = ft_face->size->metrics.x_scale;
5067 y_scale = ft_face->size->metrics.y_scale;
5069 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5071 FIXME("Can't find OS/2 table - not TT font?\n");
5076 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5078 FIXME("Can't find HHEA table - not TT font?\n");
5083 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5085 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",
5086 pOS2->usWinAscent, pOS2->usWinDescent,
5087 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5088 ft_face->ascender, ft_face->descender, ft_face->height,
5089 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5090 ft_face->bbox.yMax, ft_face->bbox.yMin);
5092 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5093 font->potm->otmSize = needed;
5095 #define TM font->potm->otmTextMetrics
5097 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5098 ascent = pHori->Ascender;
5099 descent = -pHori->Descender;
5101 ascent = pOS2->usWinAscent;
5102 descent = pOS2->usWinDescent;
5106 TM.tmAscent = font->yMax;
5107 TM.tmDescent = -font->yMin;
5108 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5110 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5111 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5112 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5113 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5116 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5119 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5121 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5122 ((ascent + descent) -
5123 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5125 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5126 if (TM.tmAveCharWidth == 0) {
5127 TM.tmAveCharWidth = 1;
5129 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5130 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
5132 TM.tmDigitizedAspectX = 300;
5133 TM.tmDigitizedAspectY = 300;
5134 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5135 * symbol range to 0 - f0ff
5137 if (font->charset == SYMBOL_CHARSET)
5140 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
5144 TM.tmFirstChar = pOS2->usFirstCharIndex;
5145 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0xffff;
5147 TM.tmLastChar = pOS2->usLastCharIndex;
5148 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
5149 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5150 TM.tmUnderlined = font->underline;
5151 TM.tmStruckOut = font->strikeout;
5153 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5154 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5155 (pOS2->version == 0xFFFFU ||
5156 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5157 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5159 TM.tmPitchAndFamily = 0;
5161 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
5162 case PAN_FAMILY_SCRIPT:
5163 TM.tmPitchAndFamily |= FF_SCRIPT;
5165 case PAN_FAMILY_DECORATIVE:
5166 case PAN_FAMILY_PICTORIAL:
5167 TM.tmPitchAndFamily |= FF_DECORATIVE;
5169 case PAN_FAMILY_TEXT_DISPLAY:
5170 if(TM.tmPitchAndFamily == 0) /* fixed */
5171 TM.tmPitchAndFamily = FF_MODERN;
5173 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
5174 case PAN_SERIF_NORMAL_SANS:
5175 case PAN_SERIF_OBTUSE_SANS:
5176 case PAN_SERIF_PERP_SANS:
5177 TM.tmPitchAndFamily |= FF_SWISS;
5180 TM.tmPitchAndFamily |= FF_ROMAN;
5185 TM.tmPitchAndFamily |= FF_DONTCARE;
5188 if(FT_IS_SCALABLE(ft_face))
5189 TM.tmPitchAndFamily |= TMPF_VECTOR;
5191 if(FT_IS_SFNT(ft_face))
5193 if (font->ntmFlags & NTM_PS_OPENTYPE)
5194 TM.tmPitchAndFamily |= TMPF_DEVICE;
5196 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5199 TM.tmCharSet = font->charset;
5201 font->potm->otmFiller = 0;
5202 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5203 font->potm->otmfsSelection = pOS2->fsSelection;
5204 font->potm->otmfsType = pOS2->fsType;
5205 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5206 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5207 font->potm->otmItalicAngle = 0; /* POST table */
5208 font->potm->otmEMSquare = ft_face->units_per_EM;
5209 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5210 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5211 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5212 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5213 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5214 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5215 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5216 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5217 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5218 font->potm->otmMacAscent = TM.tmAscent;
5219 font->potm->otmMacDescent = -TM.tmDescent;
5220 font->potm->otmMacLineGap = font->potm->otmLineGap;
5221 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5222 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5223 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5224 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5225 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5226 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5227 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5228 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5229 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5230 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5231 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5233 font->potm->otmsUnderscoreSize = 0;
5234 font->potm->otmsUnderscorePosition = 0;
5236 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5237 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5241 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5242 cp = (char*)font->potm + sizeof(*font->potm);
5243 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5244 strcpyW((WCHAR*)cp, family_nameW);
5246 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5247 strcpyW((WCHAR*)cp, style_nameW);
5249 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5250 strcpyW((WCHAR*)cp, family_nameW);
5251 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5252 strcatW((WCHAR*)cp, spaceW);
5253 strcatW((WCHAR*)cp, style_nameW);
5254 cp += lenfam + lensty;
5257 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5258 strcpyW((WCHAR*)cp, family_nameW);
5259 strcatW((WCHAR*)cp, spaceW);
5260 strcatW((WCHAR*)cp, style_nameW);
5263 if(potm && needed <= cbSize)
5265 memcpy(potm, font->potm, font->potm->otmSize);
5266 scale_outline_font_metrics(font, potm);
5270 HeapFree(GetProcessHeap(), 0, style_nameW);
5271 HeapFree(GetProcessHeap(), 0, family_nameW);
5273 LeaveCriticalSection( &freetype_cs );
5277 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5279 HFONTLIST *hfontlist;
5280 child->font = alloc_font();
5281 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5282 if(!child->font->ft_face)
5284 free_font(child->font);
5289 child->font->ntmFlags = child->face->ntmFlags;
5290 child->font->orientation = font->orientation;
5291 child->font->scale_y = font->scale_y;
5292 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5293 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5294 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5295 child->font->base_font = font;
5296 list_add_head(&child_font_list, &child->font->entry);
5297 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5301 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5304 CHILD_FONT *child_font;
5307 font = font->base_font;
5309 *linked_font = font;
5311 if((*glyph = get_glyph_index(font, c)))
5314 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5316 if(!child_font->font)
5317 if(!load_child_font(font, child_font))
5320 if(!child_font->font->ft_face)
5322 g = get_glyph_index(child_font->font, c);
5326 *linked_font = child_font->font;
5333 /*************************************************************
5334 * WineEngGetCharWidth
5337 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5342 FT_UInt glyph_index;
5343 GdiFont *linked_font;
5345 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5347 EnterCriticalSection( &freetype_cs );
5348 for(c = firstChar; c <= lastChar; c++) {
5349 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5350 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5351 &gm, 0, NULL, NULL);
5352 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5354 LeaveCriticalSection( &freetype_cs );
5358 /*************************************************************
5359 * WineEngGetCharABCWidths
5362 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5367 FT_UInt glyph_index;
5368 GdiFont *linked_font;
5370 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5372 if(!FT_IS_SCALABLE(font->ft_face))
5375 EnterCriticalSection( &freetype_cs );
5377 for(c = firstChar; c <= lastChar; c++) {
5378 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5379 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5380 &gm, 0, NULL, NULL);
5381 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5382 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5383 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5384 FONT_GM(linked_font,glyph_index)->bbx;
5386 LeaveCriticalSection( &freetype_cs );
5390 /*************************************************************
5391 * WineEngGetCharABCWidthsI
5394 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5399 FT_UInt glyph_index;
5400 GdiFont *linked_font;
5402 if(!FT_HAS_HORIZONTAL(font->ft_face))
5405 EnterCriticalSection( &freetype_cs );
5407 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5409 for(c = firstChar; c < firstChar+count; c++) {
5410 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5411 &gm, 0, NULL, NULL);
5412 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5413 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5414 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5415 - FONT_GM(linked_font,c)->bbx;
5418 for(c = 0; c < count; c++) {
5419 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5420 &gm, 0, NULL, NULL);
5421 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5422 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5423 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5424 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5427 LeaveCriticalSection( &freetype_cs );
5431 /*************************************************************
5432 * WineEngGetTextExtentExPoint
5435 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5436 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5442 FT_UInt glyph_index;
5443 GdiFont *linked_font;
5445 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5448 EnterCriticalSection( &freetype_cs );
5451 WineEngGetTextMetrics(font, &tm);
5452 size->cy = tm.tmHeight;
5454 for(idx = 0; idx < count; idx++) {
5455 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5456 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5457 &gm, 0, NULL, NULL);
5458 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5460 if (! pnfit || ext <= max_ext) {
5470 LeaveCriticalSection( &freetype_cs );
5471 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5475 /*************************************************************
5476 * WineEngGetTextExtentExPointI
5479 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5480 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5487 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5489 EnterCriticalSection( &freetype_cs );
5492 WineEngGetTextMetrics(font, &tm);
5493 size->cy = tm.tmHeight;
5495 for(idx = 0; idx < count; idx++) {
5496 WineEngGetGlyphOutline(font, indices[idx],
5497 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
5499 size->cx += FONT_GM(font,indices[idx])->adv;
5501 if (! pnfit || ext <= max_ext) {
5511 LeaveCriticalSection( &freetype_cs );
5512 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5516 /*************************************************************
5517 * WineEngGetFontData
5520 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5523 FT_Face ft_face = font->ft_face;
5527 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5528 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
5529 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
5531 if(!FT_IS_SFNT(ft_face))
5539 if(table) { /* MS tags differ in endianness from FT ones */
5540 table = table >> 24 | table << 24 |
5541 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
5544 /* make sure value of len is the value freetype says it needs */
5547 FT_ULong needed = 0;
5548 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
5549 if( !err && needed < len) len = needed;
5551 err = load_sfnt_table(ft_face, table, offset, buf, &len);
5554 TRACE("Can't find table %c%c%c%c\n",
5555 /* bytes were reversed */
5556 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
5557 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
5563 /*************************************************************
5564 * WineEngGetTextFace
5567 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5570 lstrcpynW(str, font->name, count);
5571 return strlenW(font->name);
5573 return strlenW(font->name) + 1;
5576 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5578 if (fs) *fs = font->fs;
5579 return font->charset;
5582 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5584 GdiFont *font = dc->gdiFont, *linked_font;
5585 struct list *first_hfont;
5588 EnterCriticalSection( &freetype_cs );
5589 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
5590 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
5591 if(font == linked_font)
5592 *new_hfont = dc->hFont;
5595 first_hfont = list_head(&linked_font->hfontlist);
5596 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
5598 LeaveCriticalSection( &freetype_cs );
5602 /* Retrieve a list of supported Unicode ranges for a given font.
5603 * Can be called with NULL gs to calculate the buffer size. Returns
5604 * the number of ranges found.
5606 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
5608 DWORD num_ranges = 0;
5610 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5613 FT_ULong char_code, char_code_prev;
5616 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
5618 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5619 face->num_glyphs, glyph_code, char_code);
5621 if (!glyph_code) return 0;
5625 gs->ranges[0].wcLow = (USHORT)char_code;
5626 gs->ranges[0].cGlyphs = 0;
5627 gs->cGlyphsSupported = 0;
5633 if (char_code < char_code_prev)
5635 ERR("expected increasing char code from FT_Get_Next_Char\n");
5638 if (char_code - char_code_prev > 1)
5643 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5644 gs->ranges[num_ranges - 1].cGlyphs = 1;
5645 gs->cGlyphsSupported++;
5650 gs->ranges[num_ranges - 1].cGlyphs++;
5651 gs->cGlyphsSupported++;
5653 char_code_prev = char_code;
5654 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5658 FIXME("encoding %u not supported\n", face->charmap->encoding);
5663 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5666 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
5668 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5671 glyphset->cbThis = size;
5672 glyphset->cRanges = num_ranges;
5677 /*************************************************************
5680 BOOL WineEngFontIsLinked(GdiFont *font)
5683 EnterCriticalSection( &freetype_cs );
5684 ret = !list_empty(&font->child_fonts);
5685 LeaveCriticalSection( &freetype_cs );
5689 static BOOL is_hinting_enabled(void)
5691 /* Use the >= 2.2.0 function if available */
5692 if(pFT_Get_TrueType_Engine_Type)
5694 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
5695 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
5697 #ifdef FT_DRIVER_HAS_HINTER
5702 /* otherwise if we've been compiled with < 2.2.0 headers
5703 use the internal macro */
5704 mod = pFT_Get_Module(library, "truetype");
5705 if(mod && FT_DRIVER_HAS_HINTER(mod))
5713 /*************************************************************************
5714 * GetRasterizerCaps (GDI32.@)
5716 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5718 static int hinting = -1;
5722 hinting = is_hinting_enabled();
5723 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
5726 lprs->nSize = sizeof(RASTERIZER_STATUS);
5727 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
5728 lprs->nLanguageID = 0;
5732 /*************************************************************************
5733 * Kerning support for TrueType fonts
5735 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5737 struct TT_kern_table
5743 struct TT_kern_subtable
5752 USHORT horizontal : 1;
5754 USHORT cross_stream: 1;
5755 USHORT override : 1;
5756 USHORT reserved1 : 4;
5762 struct TT_format0_kern_subtable
5766 USHORT entrySelector;
5777 static DWORD parse_format0_kern_subtable(GdiFont *font,
5778 const struct TT_format0_kern_subtable *tt_f0_ks,
5779 const USHORT *glyph_to_char,
5780 KERNINGPAIR *kern_pair, DWORD cPairs)
5783 const struct TT_kern_pair *tt_kern_pair;
5785 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
5787 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
5789 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5790 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
5791 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
5793 if (!kern_pair || !cPairs)
5796 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
5798 nPairs = min(nPairs, cPairs);
5800 for (i = 0; i < nPairs; i++)
5802 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
5803 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
5804 /* this algorithm appears to better match what Windows does */
5805 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
5806 if (kern_pair->iKernAmount < 0)
5808 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
5809 kern_pair->iKernAmount -= font->ppem;
5811 else if (kern_pair->iKernAmount > 0)
5813 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
5814 kern_pair->iKernAmount += font->ppem;
5816 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
5818 TRACE("left %u right %u value %d\n",
5819 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
5823 TRACE("copied %u entries\n", nPairs);
5827 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5831 const struct TT_kern_table *tt_kern_table;
5832 const struct TT_kern_subtable *tt_kern_subtable;
5834 USHORT *glyph_to_char;
5836 EnterCriticalSection( &freetype_cs );
5837 if (font->total_kern_pairs != (DWORD)-1)
5839 if (cPairs && kern_pair)
5841 cPairs = min(cPairs, font->total_kern_pairs);
5842 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5843 LeaveCriticalSection( &freetype_cs );
5846 LeaveCriticalSection( &freetype_cs );
5847 return font->total_kern_pairs;
5850 font->total_kern_pairs = 0;
5852 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5854 if (length == GDI_ERROR)
5856 TRACE("no kerning data in the font\n");
5857 LeaveCriticalSection( &freetype_cs );
5861 buf = HeapAlloc(GetProcessHeap(), 0, length);
5864 WARN("Out of memory\n");
5865 LeaveCriticalSection( &freetype_cs );
5869 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5871 /* build a glyph index to char code map */
5872 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5875 WARN("Out of memory allocating a glyph index to char code map\n");
5876 HeapFree(GetProcessHeap(), 0, buf);
5877 LeaveCriticalSection( &freetype_cs );
5881 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5887 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5889 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5890 font->ft_face->num_glyphs, glyph_code, char_code);
5894 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5896 /* FIXME: This doesn't match what Windows does: it does some fancy
5897 * things with duplicate glyph index to char code mappings, while
5898 * we just avoid overriding existing entries.
5900 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5901 glyph_to_char[glyph_code] = (USHORT)char_code;
5903 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5910 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5911 for (n = 0; n <= 65535; n++)
5912 glyph_to_char[n] = (USHORT)n;
5915 tt_kern_table = buf;
5916 nTables = GET_BE_WORD(tt_kern_table->nTables);
5917 TRACE("version %u, nTables %u\n",
5918 GET_BE_WORD(tt_kern_table->version), nTables);
5920 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5922 for (i = 0; i < nTables; i++)
5924 struct TT_kern_subtable tt_kern_subtable_copy;
5926 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5927 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5928 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5930 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5931 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
5932 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
5934 /* According to the TrueType specification this is the only format
5935 * that will be properly interpreted by Windows and OS/2
5937 if (tt_kern_subtable_copy.coverage.bits.format == 0)
5939 DWORD new_chunk, old_total = font->total_kern_pairs;
5941 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5942 glyph_to_char, NULL, 0);
5943 font->total_kern_pairs += new_chunk;
5945 if (!font->kern_pairs)
5946 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
5947 font->total_kern_pairs * sizeof(*font->kern_pairs));
5949 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
5950 font->total_kern_pairs * sizeof(*font->kern_pairs));
5952 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5953 glyph_to_char, font->kern_pairs + old_total, new_chunk);
5956 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
5958 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
5961 HeapFree(GetProcessHeap(), 0, glyph_to_char);
5962 HeapFree(GetProcessHeap(), 0, buf);
5964 if (cPairs && kern_pair)
5966 cPairs = min(cPairs, font->total_kern_pairs);
5967 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5968 LeaveCriticalSection( &freetype_cs );
5971 LeaveCriticalSection( &freetype_cs );
5972 return font->total_kern_pairs;
5975 #else /* HAVE_FREETYPE */
5977 /*************************************************************************/
5979 BOOL WineEngInit(void)
5983 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
5987 BOOL WineEngDestroyFontInstance(HFONT hfont)
5992 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
5997 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
5998 LPWORD pgi, DWORD flags)
6003 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6004 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6007 ERR("called but we don't have FreeType\n");
6011 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6013 ERR("called but we don't have FreeType\n");
6017 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6018 OUTLINETEXTMETRICW *potm)
6020 ERR("called but we don't have FreeType\n");
6024 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6027 ERR("called but we don't have FreeType\n");
6031 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6034 ERR("called but we don't have FreeType\n");
6038 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6041 ERR("called but we don't have FreeType\n");
6045 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6046 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6048 ERR("called but we don't have FreeType\n");
6052 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6053 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6055 ERR("called but we don't have FreeType\n");
6059 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6062 ERR("called but we don't have FreeType\n");
6066 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6068 ERR("called but we don't have FreeType\n");
6072 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6078 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6084 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6090 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6093 return DEFAULT_CHARSET;
6096 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6101 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6103 FIXME("(%p, %p): stub\n", font, glyphset);
6107 BOOL WineEngFontIsLinked(GdiFont *font)
6112 /*************************************************************************
6113 * GetRasterizerCaps (GDI32.@)
6115 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6117 lprs->nSize = sizeof(RASTERIZER_STATUS);
6119 lprs->nLanguageID = 0;
6123 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6125 ERR("called but we don't have FreeType\n");
6129 #endif /* HAVE_FREETYPE */