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 double. It fails if the absolute
807 value of the float number is greater than 32768.
809 static inline FT_Fixed FT_FixedFromFloat(double f)
815 This function builds an FT_Fixed from a FIXED. It simply put f.value
816 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
818 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
820 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
824 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
829 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
830 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
832 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
833 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
835 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
837 if(face_name && strcmpiW(face_name, family->FamilyName))
839 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
843 file = strrchr(face->file, '/');
848 if(!strcasecmp(file, file_nameA))
850 HeapFree(GetProcessHeap(), 0, file_nameA);
855 HeapFree(GetProcessHeap(), 0, file_nameA);
859 static Family *find_family_from_name(const WCHAR *name)
863 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
865 if(!strcmpiW(family->FamilyName, name))
872 static void DumpSubstList(void)
876 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
878 if(psub->from.charset != -1 || psub->to.charset != -1)
879 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
880 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
882 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
883 debugstr_w(psub->to.name));
888 static LPWSTR strdupW(LPCWSTR p)
891 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
892 ret = HeapAlloc(GetProcessHeap(), 0, len);
897 static LPSTR strdupA(LPCSTR p)
900 DWORD len = (strlen(p) + 1);
901 ret = HeapAlloc(GetProcessHeap(), 0, len);
906 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
911 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
913 if(!strcmpiW(element->from.name, from_name) &&
914 (element->from.charset == from_charset ||
915 element->from.charset == -1))
922 #define ADD_FONT_SUBST_FORCE 1
924 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
926 FontSubst *from_exist, *to_exist;
928 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
930 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
932 list_remove(&from_exist->entry);
933 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
934 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
935 HeapFree(GetProcessHeap(), 0, from_exist);
941 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
945 HeapFree(GetProcessHeap(), 0, subst->to.name);
946 subst->to.name = strdupW(to_exist->to.name);
949 list_add_tail(subst_list, &subst->entry);
954 HeapFree(GetProcessHeap(), 0, subst->from.name);
955 HeapFree(GetProcessHeap(), 0, subst->to.name);
956 HeapFree(GetProcessHeap(), 0, subst);
960 static void split_subst_info(NameCs *nc, LPSTR str)
962 CHAR *p = strrchr(str, ',');
967 nc->charset = strtol(p+1, NULL, 10);
970 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
971 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
972 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
975 static void LoadSubstList(void)
979 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
983 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
984 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
985 &hkey) == ERROR_SUCCESS) {
987 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
988 &valuelen, &datalen, NULL, NULL);
990 valuelen++; /* returned value doesn't include room for '\0' */
991 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
992 data = HeapAlloc(GetProcessHeap(), 0, datalen);
996 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
997 &dlen) == ERROR_SUCCESS) {
998 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1000 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1001 split_subst_info(&psub->from, value);
1002 split_subst_info(&psub->to, data);
1004 /* Win 2000 doesn't allow mapping between different charsets
1005 or mapping of DEFAULT_CHARSET */
1006 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1007 psub->to.charset == DEFAULT_CHARSET) {
1008 HeapFree(GetProcessHeap(), 0, psub->to.name);
1009 HeapFree(GetProcessHeap(), 0, psub->from.name);
1010 HeapFree(GetProcessHeap(), 0, psub);
1012 add_font_subst(&font_subst_list, psub, 0);
1014 /* reset dlen and vlen */
1018 HeapFree(GetProcessHeap(), 0, data);
1019 HeapFree(GetProcessHeap(), 0, value);
1024 static WCHAR *get_familyname(FT_Face ft_face)
1026 WCHAR *family = NULL;
1028 FT_UInt num_names, name_index, i;
1030 if(FT_IS_SFNT(ft_face))
1032 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1034 for(name_index = 0; name_index < num_names; name_index++)
1036 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1038 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
1039 (name.language_id == GetUserDefaultLCID()) &&
1040 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
1041 (name.encoding_id == TT_MS_ID_UNICODE_CS))
1043 /* String is not nul terminated and string_len is a byte length. */
1044 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1045 for(i = 0; i < name.string_len / 2; i++)
1047 WORD *tmp = (WORD *)&name.string[i * 2];
1048 family[i] = GET_BE_WORD(*tmp);
1052 TRACE("Got localised name %s\n", debugstr_w(family));
1063 /*****************************************************************
1066 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1067 * of FreeType that don't export this function.
1070 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1075 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1076 if(pFT_Load_Sfnt_Table)
1078 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1080 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1081 else /* Do it the hard way */
1083 TT_Face tt_face = (TT_Face) ft_face;
1084 SFNT_Interface *sfnt;
1085 if (FT_Version.major==2 && FT_Version.minor==0)
1088 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1092 /* A field was added in the middle of the structure in 2.1.x */
1093 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1095 err = sfnt->load_any(tt_face, table, offset, buf, len);
1103 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1104 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1105 "Please upgrade your freetype library.\n");
1108 err = FT_Err_Unimplemented_Feature;
1114 static inline int TestStyles(DWORD flags, DWORD styles)
1116 return (flags & styles) == styles;
1119 static int StyleOrdering(Face *face)
1121 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1123 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1125 if (TestStyles(face->ntmFlags, NTM_BOLD))
1127 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1130 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1131 debugstr_w(face->family->FamilyName),
1132 debugstr_w(face->StyleName),
1138 /* Add a style of face to a font family using an ordering of the list such
1139 that regular fonts come before bold and italic, and single styles come
1140 before compound styles. */
1141 static void AddFaceToFamily(Face *face, Family *family)
1145 LIST_FOR_EACH( entry, &family->faces )
1147 Face *ent = LIST_ENTRY(entry, Face, entry);
1148 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1150 list_add_before( entry, &face->entry );
1153 #define ADDFONT_EXTERNAL_FONT 0x01
1154 #define ADDFONT_FORCE_BITMAP 0x02
1155 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1159 TT_Header *pHeader = NULL;
1160 WCHAR *english_family, *localised_family, *StyleW;
1164 struct list *family_elem_ptr, *face_elem_ptr;
1166 FT_Long face_index = 0, num_faces;
1167 #ifdef HAVE_FREETYPE_FTWINFNT_H
1168 FT_WinFNT_HeaderRec winfnt_header;
1170 int i, bitmap_num, internal_leading;
1173 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1174 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1176 #ifdef HAVE_CARBON_CARBON_H
1177 if(file && !fake_family)
1179 char **mac_list = expand_mac_font(file);
1182 BOOL had_one = FALSE;
1184 for(cursor = mac_list; *cursor; cursor++)
1187 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1188 HeapFree(GetProcessHeap(), 0, *cursor);
1190 HeapFree(GetProcessHeap(), 0, mac_list);
1195 #endif /* HAVE_CARBON_CARBON_H */
1198 char *family_name = fake_family;
1202 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1203 err = pFT_New_Face(library, file, face_index, &ft_face);
1206 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1207 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1211 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1215 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*/
1216 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1217 pFT_Done_Face(ft_face);
1221 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1222 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1223 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1224 pFT_Done_Face(ft_face);
1228 if(FT_IS_SFNT(ft_face))
1230 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1231 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1232 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1234 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1235 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1236 pFT_Done_Face(ft_face);
1240 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1241 we don't want to load these. */
1242 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1246 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1248 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1249 pFT_Done_Face(ft_face);
1255 if(!ft_face->family_name || !ft_face->style_name) {
1256 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1257 pFT_Done_Face(ft_face);
1261 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1263 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1264 pFT_Done_Face(ft_face);
1270 localised_family = get_familyname(ft_face);
1271 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1273 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1274 HeapFree(GetProcessHeap(), 0, localised_family);
1275 num_faces = ft_face->num_faces;
1276 pFT_Done_Face(ft_face);
1279 HeapFree(GetProcessHeap(), 0, localised_family);
1283 family_name = ft_face->family_name;
1287 My_FT_Bitmap_Size *size = NULL;
1290 if(!FT_IS_SCALABLE(ft_face))
1291 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1293 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1294 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1295 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1297 localised_family = NULL;
1299 localised_family = get_familyname(ft_face);
1300 if(localised_family && !strcmpW(localised_family, english_family)) {
1301 HeapFree(GetProcessHeap(), 0, localised_family);
1302 localised_family = NULL;
1307 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1308 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1309 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1314 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1315 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1316 list_init(&family->faces);
1317 list_add_tail(&font_list, &family->entry);
1319 if(localised_family) {
1320 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1321 subst->from.name = strdupW(english_family);
1322 subst->from.charset = -1;
1323 subst->to.name = strdupW(localised_family);
1324 subst->to.charset = -1;
1325 add_font_subst(&font_subst_list, subst, 0);
1328 HeapFree(GetProcessHeap(), 0, localised_family);
1329 HeapFree(GetProcessHeap(), 0, english_family);
1331 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1332 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1333 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1335 internal_leading = 0;
1336 memset(&fs, 0, sizeof(fs));
1338 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1340 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1341 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1342 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1343 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1344 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1345 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1346 if(pOS2->version == 0) {
1349 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1350 fs.fsCsb[0] |= FS_LATIN1;
1352 fs.fsCsb[0] |= FS_SYMBOL;
1355 #ifdef HAVE_FREETYPE_FTWINFNT_H
1356 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1358 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1359 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1360 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1362 internal_leading = winfnt_header.internal_leading;
1366 face_elem_ptr = list_head(&family->faces);
1367 while(face_elem_ptr) {
1368 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1369 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1370 if(!strcmpW(face->StyleName, StyleW) &&
1371 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1372 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1373 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1374 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1377 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1378 HeapFree(GetProcessHeap(), 0, StyleW);
1379 pFT_Done_Face(ft_face);
1382 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1383 TRACE("Original font is newer so skipping this one\n");
1384 HeapFree(GetProcessHeap(), 0, StyleW);
1385 pFT_Done_Face(ft_face);
1388 TRACE("Replacing original with this one\n");
1389 list_remove(&face->entry);
1390 HeapFree(GetProcessHeap(), 0, face->file);
1391 HeapFree(GetProcessHeap(), 0, face->StyleName);
1392 HeapFree(GetProcessHeap(), 0, face);
1397 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1398 face->cached_enum_data = NULL;
1399 face->StyleName = StyleW;
1402 face->file = strdupA(file);
1403 face->font_data_ptr = NULL;
1404 face->font_data_size = 0;
1409 face->font_data_ptr = font_data_ptr;
1410 face->font_data_size = font_data_size;
1412 face->face_index = face_index;
1414 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1415 face->ntmFlags |= NTM_ITALIC;
1416 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1417 face->ntmFlags |= NTM_BOLD;
1418 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1419 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1420 face->family = family;
1421 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1423 memset(&face->fs_links, 0, sizeof(face->fs_links));
1425 if(FT_IS_SCALABLE(ft_face)) {
1426 memset(&face->size, 0, sizeof(face->size));
1427 face->scalable = TRUE;
1429 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1430 size->height, size->width, size->size >> 6,
1431 size->x_ppem >> 6, size->y_ppem >> 6);
1432 face->size.height = size->height;
1433 face->size.width = size->width;
1434 face->size.size = size->size;
1435 face->size.x_ppem = size->x_ppem;
1436 face->size.y_ppem = size->y_ppem;
1437 face->size.internal_leading = internal_leading;
1438 face->scalable = FALSE;
1441 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1443 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1445 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1446 face->ntmFlags |= NTM_PS_OPENTYPE;
1449 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1450 face->fs.fsCsb[0], face->fs.fsCsb[1],
1451 face->fs.fsUsb[0], face->fs.fsUsb[1],
1452 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1455 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1456 for(i = 0; i < ft_face->num_charmaps; i++) {
1457 switch(ft_face->charmaps[i]->encoding) {
1458 case FT_ENCODING_UNICODE:
1459 case FT_ENCODING_APPLE_ROMAN:
1460 face->fs.fsCsb[0] |= FS_LATIN1;
1462 case FT_ENCODING_MS_SYMBOL:
1463 face->fs.fsCsb[0] |= FS_SYMBOL;
1471 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1472 have_installed_roman_font = TRUE;
1474 AddFaceToFamily(face, family);
1476 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1478 num_faces = ft_face->num_faces;
1479 pFT_Done_Face(ft_face);
1480 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1481 debugstr_w(StyleW));
1482 } while(num_faces > ++face_index);
1486 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1488 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1491 static void DumpFontList(void)
1495 struct list *family_elem_ptr, *face_elem_ptr;
1497 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1498 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1499 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1500 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1501 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1502 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1504 TRACE(" %d", face->size.height);
1511 /***********************************************************
1512 * The replacement list is a way to map an entire font
1513 * family onto another family. For example adding
1515 * [HKCU\Software\Wine\Fonts\Replacements]
1516 * "Wingdings"="Winedings"
1518 * would enumerate the Winedings font both as Winedings and
1519 * Wingdings. However if a real Wingdings font is present the
1520 * replacement does not take place.
1523 static void LoadReplaceList(void)
1526 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1531 struct list *family_elem_ptr, *face_elem_ptr;
1534 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1535 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1537 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1538 &valuelen, &datalen, NULL, NULL);
1540 valuelen++; /* returned value doesn't include room for '\0' */
1541 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1542 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1546 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1547 &dlen) == ERROR_SUCCESS) {
1548 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1549 /* "NewName"="Oldname" */
1550 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1552 /* Find the old family and hence all of the font files
1554 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1555 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1556 if(!strcmpiW(family->FamilyName, data)) {
1557 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1558 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1559 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1560 debugstr_w(face->StyleName), familyA);
1561 /* Now add a new entry with the new family name */
1562 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1567 /* reset dlen and vlen */
1571 HeapFree(GetProcessHeap(), 0, data);
1572 HeapFree(GetProcessHeap(), 0, value);
1577 /*************************************************************
1580 static BOOL init_system_links(void)
1582 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1583 'W','i','n','d','o','w','s',' ','N','T','\\',
1584 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1585 'S','y','s','t','e','m','L','i','n','k',0};
1588 DWORD type, max_val, max_data, val_len, data_len, index;
1589 WCHAR *value, *data;
1590 WCHAR *entry, *next;
1591 SYSTEM_LINKS *font_link, *system_font_link;
1592 CHILD_FONT *child_font;
1593 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1594 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1595 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1601 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1603 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1604 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1605 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1606 val_len = max_val + 1;
1607 data_len = max_data;
1609 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1611 TRACE("%s:\n", debugstr_w(value));
1613 memset(&fs, 0, sizeof(fs));
1614 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1615 psub = get_font_subst(&font_subst_list, value, -1);
1616 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1617 list_init(&font_link->links);
1618 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1621 CHILD_FONT *child_font;
1623 TRACE("\t%s\n", debugstr_w(entry));
1625 next = entry + strlenW(entry) + 1;
1627 face_name = strchrW(entry, ',');
1631 while(isspaceW(*face_name))
1634 psub = get_font_subst(&font_subst_list, face_name, -1);
1636 face_name = psub->to.name;
1638 face = find_face_from_filename(entry, face_name);
1641 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1645 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1646 child_font->face = face;
1647 child_font->font = NULL;
1648 fs.fsCsb[0] |= face->fs.fsCsb[0];
1649 fs.fsCsb[1] |= face->fs.fsCsb[1];
1650 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1651 list_add_tail(&font_link->links, &child_font->entry);
1653 family = find_family_from_name(font_link->font_name);
1656 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1658 face->fs_links = fs;
1661 list_add_tail(&system_links, &font_link->entry);
1662 val_len = max_val + 1;
1663 data_len = max_data;
1666 HeapFree(GetProcessHeap(), 0, value);
1667 HeapFree(GetProcessHeap(), 0, data);
1671 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1674 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1675 system_font_link->font_name = strdupW(System);
1676 list_init(&system_font_link->links);
1678 face = find_face_from_filename(tahoma_ttf, Tahoma);
1681 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1682 child_font->face = face;
1683 child_font->font = NULL;
1684 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1685 list_add_tail(&system_font_link->links, &child_font->entry);
1687 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1689 if(!strcmpiW(font_link->font_name, Tahoma))
1691 CHILD_FONT *font_link_entry;
1692 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1694 CHILD_FONT *new_child;
1695 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1696 new_child->face = font_link_entry->face;
1697 new_child->font = NULL;
1698 list_add_tail(&system_font_link->links, &new_child->entry);
1703 list_add_tail(&system_links, &system_font_link->entry);
1707 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1710 struct dirent *dent;
1711 char path[MAX_PATH];
1713 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1715 dir = opendir(dirname);
1717 WARN("Can't open directory %s\n", debugstr_a(dirname));
1720 while((dent = readdir(dir)) != NULL) {
1721 struct stat statbuf;
1723 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1726 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1728 sprintf(path, "%s/%s", dirname, dent->d_name);
1730 if(stat(path, &statbuf) == -1)
1732 WARN("Can't stat %s\n", debugstr_a(path));
1735 if(S_ISDIR(statbuf.st_mode))
1736 ReadFontDir(path, external_fonts);
1738 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1744 static void load_fontconfig_fonts(void)
1746 #ifdef SONAME_LIBFONTCONFIG
1747 void *fc_handle = NULL;
1756 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1758 TRACE("Wine cannot find the fontconfig library (%s).\n",
1759 SONAME_LIBFONTCONFIG);
1762 #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;}
1763 LOAD_FUNCPTR(FcConfigGetCurrent);
1764 LOAD_FUNCPTR(FcFontList);
1765 LOAD_FUNCPTR(FcFontSetDestroy);
1766 LOAD_FUNCPTR(FcInit);
1767 LOAD_FUNCPTR(FcObjectSetAdd);
1768 LOAD_FUNCPTR(FcObjectSetCreate);
1769 LOAD_FUNCPTR(FcObjectSetDestroy);
1770 LOAD_FUNCPTR(FcPatternCreate);
1771 LOAD_FUNCPTR(FcPatternDestroy);
1772 LOAD_FUNCPTR(FcPatternGetBool);
1773 LOAD_FUNCPTR(FcPatternGetString);
1776 if(!pFcInit()) return;
1778 config = pFcConfigGetCurrent();
1779 pat = pFcPatternCreate();
1780 os = pFcObjectSetCreate();
1781 pFcObjectSetAdd(os, FC_FILE);
1782 pFcObjectSetAdd(os, FC_SCALABLE);
1783 fontset = pFcFontList(config, pat, os);
1784 if(!fontset) return;
1785 for(i = 0; i < fontset->nfont; i++) {
1788 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1790 TRACE("fontconfig: %s\n", file);
1792 /* We're just interested in OT/TT fonts for now, so this hack just
1793 picks up the scalable fonts without extensions .pf[ab] to save time
1794 loading every other font */
1796 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1798 TRACE("not scalable\n");
1802 len = strlen( file );
1803 if(len < 4) continue;
1804 ext = &file[ len - 3 ];
1805 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1806 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1808 pFcFontSetDestroy(fontset);
1809 pFcObjectSetDestroy(os);
1810 pFcPatternDestroy(pat);
1816 static BOOL load_font_from_data_dir(LPCWSTR file)
1819 const char *data_dir = wine_get_data_dir();
1821 if (!data_dir) data_dir = wine_get_build_dir();
1828 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1830 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1832 strcpy(unix_name, data_dir);
1833 strcat(unix_name, "/fonts/");
1835 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1837 EnterCriticalSection( &freetype_cs );
1838 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1839 LeaveCriticalSection( &freetype_cs );
1840 HeapFree(GetProcessHeap(), 0, unix_name);
1845 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1847 static const WCHAR slashW[] = {'\\','\0'};
1849 WCHAR windowsdir[MAX_PATH];
1852 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1853 strcatW(windowsdir, fontsW);
1854 strcatW(windowsdir, slashW);
1855 strcatW(windowsdir, file);
1856 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1857 EnterCriticalSection( &freetype_cs );
1858 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1859 LeaveCriticalSection( &freetype_cs );
1860 HeapFree(GetProcessHeap(), 0, unixname);
1865 static void load_system_fonts(void)
1868 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1869 const WCHAR * const *value;
1871 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1874 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1875 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1876 strcatW(windowsdir, fontsW);
1877 for(value = SystemFontValues; *value; value++) {
1878 dlen = sizeof(data);
1879 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1883 sprintfW(pathW, fmtW, windowsdir, data);
1884 if((unixname = wine_get_unix_file_name(pathW))) {
1885 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1886 HeapFree(GetProcessHeap(), 0, unixname);
1889 load_font_from_data_dir(data);
1896 /*************************************************************
1898 * This adds registry entries for any externally loaded fonts
1899 * (fonts from fontconfig or FontDirs). It also deletes entries
1900 * of no longer existing fonts.
1903 static void update_reg_entries(void)
1905 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1910 struct list *family_elem_ptr, *face_elem_ptr;
1912 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1913 static const WCHAR spaceW[] = {' ', '\0'};
1916 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1917 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1918 ERR("Can't create Windows font reg key\n");
1922 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1923 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1924 ERR("Can't create Windows font reg key\n");
1928 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1929 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1930 ERR("Can't create external font reg key\n");
1934 /* enumerate the fonts and add external ones to the two keys */
1936 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1937 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1938 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1939 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1940 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1941 if(!face->external) continue;
1943 if (!(face->ntmFlags & NTM_REGULAR))
1944 len = len_fam + strlenW(face->StyleName) + 1;
1945 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1946 strcpyW(valueW, family->FamilyName);
1947 if(len != len_fam) {
1948 strcatW(valueW, spaceW);
1949 strcatW(valueW, face->StyleName);
1951 strcatW(valueW, TrueType);
1953 file = wine_get_dos_file_name(face->file);
1955 len = strlenW(file) + 1;
1958 if((path = strrchr(face->file, '/')) == NULL)
1962 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1964 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1965 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1967 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1968 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1969 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1971 HeapFree(GetProcessHeap(), 0, file);
1972 HeapFree(GetProcessHeap(), 0, valueW);
1976 if(external_key) RegCloseKey(external_key);
1977 if(win9x_key) RegCloseKey(win9x_key);
1978 if(winnt_key) RegCloseKey(winnt_key);
1982 static void delete_external_font_keys(void)
1984 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1985 DWORD dlen, vlen, datalen, valuelen, i, type;
1989 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1990 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1991 ERR("Can't create Windows font reg key\n");
1995 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1996 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1997 ERR("Can't create Windows font reg key\n");
2001 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2002 ERR("Can't create external font reg key\n");
2006 /* Delete all external fonts added last time */
2008 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2009 &valuelen, &datalen, NULL, NULL);
2010 valuelen++; /* returned value doesn't include room for '\0' */
2011 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2012 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2014 dlen = datalen * sizeof(WCHAR);
2017 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2018 &dlen) == ERROR_SUCCESS) {
2020 RegDeleteValueW(winnt_key, valueW);
2021 RegDeleteValueW(win9x_key, valueW);
2022 /* reset dlen and vlen */
2026 HeapFree(GetProcessHeap(), 0, data);
2027 HeapFree(GetProcessHeap(), 0, valueW);
2029 /* Delete the old external fonts key */
2030 RegCloseKey(external_key);
2031 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2034 if(win9x_key) RegCloseKey(win9x_key);
2035 if(winnt_key) RegCloseKey(winnt_key);
2038 /*************************************************************
2039 * WineEngAddFontResourceEx
2042 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2045 if (ft_handle) /* do it only if we have freetype up and running */
2050 FIXME("Ignoring flags %x\n", flags);
2052 if((unixname = wine_get_unix_file_name(file)))
2054 EnterCriticalSection( &freetype_cs );
2055 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2056 LeaveCriticalSection( &freetype_cs );
2057 HeapFree(GetProcessHeap(), 0, unixname);
2059 if (!ret && !strchrW(file, '\\')) {
2060 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2061 ret = load_font_from_winfonts_dir(file);
2063 /* Try in datadir/fonts (or builddir/fonts),
2064 * needed for Magic the Gathering Online
2066 ret = load_font_from_data_dir(file);
2073 /*************************************************************
2074 * WineEngAddFontMemResourceEx
2077 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2079 if (ft_handle) /* do it only if we have freetype up and running */
2081 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2083 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2084 memcpy(pFontCopy, pbFont, cbFont);
2086 EnterCriticalSection( &freetype_cs );
2087 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2088 LeaveCriticalSection( &freetype_cs );
2092 TRACE("AddFontToList failed\n");
2093 HeapFree(GetProcessHeap(), 0, pFontCopy);
2096 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2097 * For now return something unique but quite random
2099 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2100 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2107 /*************************************************************
2108 * WineEngRemoveFontResourceEx
2111 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2117 static const struct nls_update_font_list
2119 UINT ansi_cp, oem_cp;
2120 const char *oem, *fixed, *system;
2121 const char *courier, *serif, *small, *sserif;
2122 /* these are for font substitutes */
2123 const char *shelldlg, *tmsrmn;
2124 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2128 const char *from, *to;
2129 } arial_0, courier_new_0, times_new_roman_0;
2130 } nls_update_font_list[] =
2132 /* Latin 1 (United States) */
2133 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2134 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2135 "Tahoma","Times New Roman",
2136 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2139 /* Latin 1 (Multilingual) */
2140 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2141 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2142 "Tahoma","Times New Roman", /* FIXME unverified */
2143 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2146 /* Eastern Europe */
2147 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2148 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2149 "Tahoma","Times New Roman", /* FIXME unverified */
2150 "Fixedsys,238", "System,238",
2151 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2152 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2153 { "Arial CE,0", "Arial,238" },
2154 { "Courier New CE,0", "Courier New,238" },
2155 { "Times New Roman CE,0", "Times New Roman,238" }
2158 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2159 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2160 "Tahoma","Times New Roman", /* FIXME unverified */
2161 "Fixedsys,204", "System,204",
2162 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2163 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2164 { "Arial Cyr,0", "Arial,204" },
2165 { "Courier New Cyr,0", "Courier New,204" },
2166 { "Times New Roman Cyr,0", "Times New Roman,204" }
2169 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2170 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2171 "Tahoma","Times New Roman", /* FIXME unverified */
2172 "Fixedsys,161", "System,161",
2173 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2174 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2175 { "Arial Greek,0", "Arial,161" },
2176 { "Courier New Greek,0", "Courier New,161" },
2177 { "Times New Roman Greek,0", "Times New Roman,161" }
2180 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2181 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2182 "Tahoma","Times New Roman", /* FIXME unverified */
2183 "Fixedsys,162", "System,162",
2184 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2185 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2186 { "Arial Tur,0", "Arial,162" },
2187 { "Courier New Tur,0", "Courier New,162" },
2188 { "Times New Roman Tur,0", "Times New Roman,162" }
2191 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2192 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2193 "Tahoma","Times New Roman", /* FIXME unverified */
2194 "Fixedsys,177", "System,177",
2195 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2196 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2200 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2201 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2202 "Tahoma","Times New Roman", /* FIXME unverified */
2203 "Fixedsys,178", "System,178",
2204 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2205 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2209 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2210 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2211 "Tahoma","Times New Roman", /* FIXME unverified */
2212 "Fixedsys,186", "System,186",
2213 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2214 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2215 { "Arial Baltic,0", "Arial,186" },
2216 { "Courier New Baltic,0", "Courier New,186" },
2217 { "Times New Roman Baltic,0", "Times New Roman,186" }
2220 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2221 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2222 "Tahoma","Times New Roman", /* FIXME unverified */
2223 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2227 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2228 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2229 "Tahoma","Times New Roman", /* FIXME unverified */
2230 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2234 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2235 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2236 "MS UI Gothic","MS Serif",
2237 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2240 /* Chinese Simplified */
2241 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2242 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2243 "Tahoma", "Times New Roman", /* FIXME unverified */
2244 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2248 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2249 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2251 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2254 /* Chinese Traditional */
2255 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2256 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2257 "PMingLiU", "MingLiU",
2258 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2263 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2265 return ( ansi_cp == 932 /* CP932 for Japanese */
2266 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2267 || ansi_cp == 949 /* CP949 for Korean */
2268 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2271 static inline HKEY create_fonts_NT_registry_key(void)
2275 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2276 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2280 static inline HKEY create_fonts_9x_registry_key(void)
2284 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2285 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2289 static inline HKEY create_config_fonts_registry_key(void)
2293 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2294 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2298 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2300 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2301 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2302 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2303 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2306 static void set_value_key(HKEY hkey, const char *name, const char *value)
2309 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2311 RegDeleteValueA(hkey, name);
2314 static void update_font_info(void)
2316 char buf[40], cpbuf[40];
2319 UINT i, ansi_cp = 0, oem_cp = 0;
2322 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2325 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2326 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2327 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2328 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2329 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2331 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2332 if (is_dbcs_ansi_cp(ansi_cp))
2333 use_default_fallback = TRUE;
2336 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2338 if (!strcmp( buf, cpbuf )) /* already set correctly */
2343 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2345 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2347 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2350 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2354 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2355 nls_update_font_list[i].oem_cp == oem_cp)
2357 hkey = create_config_fonts_registry_key();
2358 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2359 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2360 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2363 hkey = create_fonts_NT_registry_key();
2364 add_font_list(hkey, &nls_update_font_list[i]);
2367 hkey = create_fonts_9x_registry_key();
2368 add_font_list(hkey, &nls_update_font_list[i]);
2371 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2373 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2374 strlen(nls_update_font_list[i].shelldlg)+1);
2375 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2376 strlen(nls_update_font_list[i].tmsrmn)+1);
2378 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2379 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2380 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2381 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2382 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2383 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2384 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2385 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2387 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2388 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2389 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2397 /* Delete the FontSubstitutes from other locales */
2398 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2400 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2401 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2402 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2408 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2412 static BOOL init_freetype(void)
2414 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2417 "Wine cannot find the FreeType font library. To enable Wine to\n"
2418 "use TrueType fonts please install a version of FreeType greater than\n"
2419 "or equal to 2.0.5.\n"
2420 "http://www.freetype.org\n");
2424 #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;}
2426 LOAD_FUNCPTR(FT_Vector_Unit)
2427 LOAD_FUNCPTR(FT_Done_Face)
2428 LOAD_FUNCPTR(FT_Get_Char_Index)
2429 LOAD_FUNCPTR(FT_Get_Module)
2430 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2431 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2432 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2433 LOAD_FUNCPTR(FT_Init_FreeType)
2434 LOAD_FUNCPTR(FT_Load_Glyph)
2435 LOAD_FUNCPTR(FT_Matrix_Multiply)
2436 LOAD_FUNCPTR(FT_MulFix)
2437 LOAD_FUNCPTR(FT_New_Face)
2438 LOAD_FUNCPTR(FT_New_Memory_Face)
2439 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2440 LOAD_FUNCPTR(FT_Outline_Transform)
2441 LOAD_FUNCPTR(FT_Outline_Translate)
2442 LOAD_FUNCPTR(FT_Select_Charmap)
2443 LOAD_FUNCPTR(FT_Set_Charmap)
2444 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2445 LOAD_FUNCPTR(FT_Vector_Transform)
2448 /* Don't warn if these ones are missing */
2449 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2450 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2451 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2452 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2453 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2454 #ifdef HAVE_FREETYPE_FTWINFNT_H
2455 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2457 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2458 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2459 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2460 <= 2.0.3 has FT_Sqrt64 */
2464 if(pFT_Init_FreeType(&library) != 0) {
2465 ERR("Can't init FreeType library\n");
2466 wine_dlclose(ft_handle, NULL, 0);
2470 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2471 if (pFT_Library_Version)
2472 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2474 if (FT_Version.major<=0)
2480 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2481 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2482 ((FT_Version.minor << 8) & 0x00ff00) |
2483 ((FT_Version.patch ) & 0x0000ff);
2489 "Wine cannot find certain functions that it needs inside the FreeType\n"
2490 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2491 "FreeType to at least version 2.0.5.\n"
2492 "http://www.freetype.org\n");
2493 wine_dlclose(ft_handle, NULL, 0);
2498 /*************************************************************
2501 * Initialize FreeType library and create a list of available faces
2503 BOOL WineEngInit(void)
2505 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2506 static const WCHAR pathW[] = {'P','a','t','h',0};
2508 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2510 WCHAR windowsdir[MAX_PATH];
2513 const char *data_dir;
2517 /* update locale dependent font info in registry */
2520 if(!init_freetype()) return FALSE;
2522 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2523 ERR("Failed to create font mutex\n");
2526 WaitForSingleObject(font_mutex, INFINITE);
2528 delete_external_font_keys();
2530 /* load the system bitmap fonts */
2531 load_system_fonts();
2533 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2534 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2535 strcatW(windowsdir, fontsW);
2536 if((unixname = wine_get_unix_file_name(windowsdir)))
2538 ReadFontDir(unixname, FALSE);
2539 HeapFree(GetProcessHeap(), 0, unixname);
2542 /* load the system truetype fonts */
2543 data_dir = wine_get_data_dir();
2544 if (!data_dir) data_dir = wine_get_build_dir();
2545 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2546 strcpy(unixname, data_dir);
2547 strcat(unixname, "/fonts/");
2548 ReadFontDir(unixname, TRUE);
2549 HeapFree(GetProcessHeap(), 0, unixname);
2552 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2553 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2554 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2556 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2557 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2558 &hkey) == ERROR_SUCCESS) {
2560 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2561 &valuelen, &datalen, NULL, NULL);
2563 valuelen++; /* returned value doesn't include room for '\0' */
2564 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2565 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2568 dlen = datalen * sizeof(WCHAR);
2570 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2571 &dlen) == ERROR_SUCCESS) {
2572 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2574 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2576 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2577 HeapFree(GetProcessHeap(), 0, unixname);
2580 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2582 WCHAR pathW[MAX_PATH];
2583 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2586 sprintfW(pathW, fmtW, windowsdir, data);
2587 if((unixname = wine_get_unix_file_name(pathW)))
2589 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2590 HeapFree(GetProcessHeap(), 0, unixname);
2593 load_font_from_data_dir(data);
2595 /* reset dlen and vlen */
2600 HeapFree(GetProcessHeap(), 0, data);
2601 HeapFree(GetProcessHeap(), 0, valueW);
2605 load_fontconfig_fonts();
2607 /* then look in any directories that we've specified in the config file */
2608 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2609 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2615 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2617 len += sizeof(WCHAR);
2618 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2619 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2621 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2622 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2623 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2624 TRACE( "got font path %s\n", debugstr_a(valueA) );
2628 LPSTR next = strchr( ptr, ':' );
2629 if (next) *next++ = 0;
2630 ReadFontDir( ptr, TRUE );
2633 HeapFree( GetProcessHeap(), 0, valueA );
2635 HeapFree( GetProcessHeap(), 0, valueW );
2644 update_reg_entries();
2646 init_system_links();
2648 ReleaseMutex(font_mutex);
2653 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2656 TT_HoriHeader *pHori;
2660 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2661 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2663 if(height == 0) height = 16;
2665 /* Calc. height of EM square:
2667 * For +ve lfHeight we have
2668 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2669 * Re-arranging gives:
2670 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2672 * For -ve lfHeight we have
2674 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2675 * with il = winAscent + winDescent - units_per_em]
2680 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2681 ppem = MulDiv(ft_face->units_per_EM, height,
2682 pHori->Ascender - pHori->Descender);
2684 ppem = MulDiv(ft_face->units_per_EM, height,
2685 pOS2->usWinAscent + pOS2->usWinDescent);
2693 static struct font_mapping *map_font_file( const char *name )
2695 struct font_mapping *mapping;
2699 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2700 if (fstat( fd, &st ) == -1) goto error;
2702 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2704 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2706 mapping->refcount++;
2711 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2714 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2717 if (mapping->data == MAP_FAILED)
2719 HeapFree( GetProcessHeap(), 0, mapping );
2722 mapping->refcount = 1;
2723 mapping->dev = st.st_dev;
2724 mapping->ino = st.st_ino;
2725 mapping->size = st.st_size;
2726 list_add_tail( &mappings_list, &mapping->entry );
2734 static void unmap_font_file( struct font_mapping *mapping )
2736 if (!--mapping->refcount)
2738 list_remove( &mapping->entry );
2739 munmap( mapping->data, mapping->size );
2740 HeapFree( GetProcessHeap(), 0, mapping );
2744 static LONG load_VDMX(GdiFont*, LONG);
2746 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2753 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2757 if (!(font->mapping = map_font_file( face->file )))
2759 WARN("failed to map %s\n", debugstr_a(face->file));
2762 data_ptr = font->mapping->data;
2763 data_size = font->mapping->size;
2767 data_ptr = face->font_data_ptr;
2768 data_size = face->font_data_size;
2771 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2773 ERR("FT_New_Face rets %d\n", err);
2777 /* set it here, as load_VDMX needs it */
2778 font->ft_face = ft_face;
2780 if(FT_IS_SCALABLE(ft_face)) {
2781 /* load the VDMX table if we have one */
2782 font->ppem = load_VDMX(font, height);
2784 font->ppem = calc_ppem_for_height(ft_face, height);
2785 TRACE("height %d => ppem %d\n", height, font->ppem);
2787 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2788 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2790 font->ppem = height;
2791 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2792 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2798 static int get_nearest_charset(Face *face, int *cp)
2800 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2801 a single face with the requested charset. The idea is to check if
2802 the selected font supports the current ANSI codepage, if it does
2803 return the corresponding charset, else return the first charset */
2806 int acp = GetACP(), i;
2810 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2811 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2812 return csi.ciCharset;
2814 for(i = 0; i < 32; i++) {
2816 if(face->fs.fsCsb[0] & fs0) {
2817 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2819 return csi.ciCharset;
2822 FIXME("TCI failing on %x\n", fs0);
2826 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2827 face->fs.fsCsb[0], face->file);
2829 return DEFAULT_CHARSET;
2832 static GdiFont *alloc_font(void)
2834 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2836 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2837 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2839 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2840 ret->total_kern_pairs = (DWORD)-1;
2841 ret->kern_pairs = NULL;
2842 list_init(&ret->hfontlist);
2843 list_init(&ret->child_fonts);
2847 static void free_font(GdiFont *font)
2849 struct list *cursor, *cursor2;
2852 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2854 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2855 struct list *first_hfont;
2856 HFONTLIST *hfontlist;
2857 list_remove(cursor);
2860 first_hfont = list_head(&child->font->hfontlist);
2861 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2862 DeleteObject(hfontlist->hfont);
2863 HeapFree(GetProcessHeap(), 0, hfontlist);
2864 free_font(child->font);
2866 HeapFree(GetProcessHeap(), 0, child);
2869 if (font->ft_face) pFT_Done_Face(font->ft_face);
2870 if (font->mapping) unmap_font_file( font->mapping );
2871 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2872 HeapFree(GetProcessHeap(), 0, font->potm);
2873 HeapFree(GetProcessHeap(), 0, font->name);
2874 for (i = 0; i < font->gmsize; i++)
2875 HeapFree(GetProcessHeap(),0,font->gm[i]);
2876 HeapFree(GetProcessHeap(), 0, font->gm);
2877 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2878 HeapFree(GetProcessHeap(), 0, font);
2882 /*************************************************************
2885 * load the vdmx entry for the specified height
2888 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2889 ( ( (FT_ULong)_x4 << 24 ) | \
2890 ( (FT_ULong)_x3 << 16 ) | \
2891 ( (FT_ULong)_x2 << 8 ) | \
2894 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2909 static LONG load_VDMX(GdiFont *font, LONG height)
2913 BYTE devXRatio, devYRatio;
2914 USHORT numRecs, numRatios;
2915 DWORD result, offset = -1;
2919 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2921 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2924 /* FIXME: need the real device aspect ratio */
2928 numRecs = GET_BE_WORD(hdr[1]);
2929 numRatios = GET_BE_WORD(hdr[2]);
2931 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2932 for(i = 0; i < numRatios; i++) {
2935 offset = (3 * 2) + (i * sizeof(Ratios));
2936 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2939 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2941 if((ratio.xRatio == 0 &&
2942 ratio.yStartRatio == 0 &&
2943 ratio.yEndRatio == 0) ||
2944 (devXRatio == ratio.xRatio &&
2945 devYRatio >= ratio.yStartRatio &&
2946 devYRatio <= ratio.yEndRatio))
2948 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2949 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2950 offset = GET_BE_WORD(tmp);
2956 FIXME("No suitable ratio found\n");
2960 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2962 BYTE startsz, endsz;
2965 recs = GET_BE_WORD(group.recs);
2966 startsz = group.startsz;
2967 endsz = group.endsz;
2969 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2971 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2972 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2973 if(result == GDI_ERROR) {
2974 FIXME("Failed to retrieve vTable\n");
2979 for(i = 0; i < recs; i++) {
2980 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2981 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2982 ppem = GET_BE_WORD(vTable[i * 3]);
2984 if(yMax + -yMin == height) {
2987 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2990 if(yMax + -yMin > height) {
2993 goto end; /* failed */
2995 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2996 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2997 ppem = GET_BE_WORD(vTable[i * 3]);
2998 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3004 TRACE("ppem not found for height %d\n", height);
3008 if(ppem < startsz || ppem > endsz)
3011 for(i = 0; i < recs; i++) {
3013 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3015 if(yPelHeight > ppem)
3018 if(yPelHeight == ppem) {
3019 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3020 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3021 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
3027 HeapFree(GetProcessHeap(), 0, vTable);
3033 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3035 if(font->font_desc.hash != fd->hash) return TRUE;
3036 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3037 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3038 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3039 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3042 static void calc_hash(FONT_DESC *pfd)
3044 DWORD hash = 0, *ptr, two_chars;
3048 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3050 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3052 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3054 pwc = (WCHAR *)&two_chars;
3056 *pwc = toupperW(*pwc);
3058 *pwc = toupperW(*pwc);
3062 hash ^= !pfd->can_use_bitmap;
3067 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const XFORM *pxf, BOOL can_use_bitmap)
3072 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3075 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
3076 fd.can_use_bitmap = can_use_bitmap;
3079 /* try the in-use list */
3080 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3081 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3082 if(!fontcmp(ret, &fd)) {
3083 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3084 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3085 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3086 if(hflist->hfont == hfont)
3089 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3090 hflist->hfont = hfont;
3091 list_add_head(&ret->hfontlist, &hflist->entry);
3096 /* then the unused list */
3097 font_elem_ptr = list_head(&unused_gdi_font_list);
3098 while(font_elem_ptr) {
3099 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3100 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3101 if(!fontcmp(ret, &fd)) {
3102 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3103 assert(list_empty(&ret->hfontlist));
3104 TRACE("Found %p in unused list\n", ret);
3105 list_remove(&ret->entry);
3106 list_add_head(&gdi_font_list, &ret->entry);
3107 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3108 hflist->hfont = hfont;
3109 list_add_head(&ret->hfontlist, &hflist->entry);
3117 /*************************************************************
3118 * create_child_font_list
3120 static BOOL create_child_font_list(GdiFont *font)
3123 SYSTEM_LINKS *font_link;
3124 CHILD_FONT *font_link_entry, *new_child;
3126 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3128 if(!strcmpW(font_link->font_name, font->name))
3130 TRACE("found entry in system list\n");
3131 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3133 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3134 new_child->face = font_link_entry->face;
3135 new_child->font = NULL;
3136 list_add_tail(&font->child_fonts, &new_child->entry);
3137 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3144 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3145 * Sans Serif. This is how asian windows get default fallbacks for fonts
3147 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3148 font->charset != OEM_CHARSET &&
3149 strcmpW(font->name,szDefaultFallbackLink) != 0)
3150 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3152 if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3154 TRACE("found entry in default fallback list\n");
3155 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3157 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3158 new_child->face = font_link_entry->face;
3159 new_child->font = NULL;
3160 list_add_tail(&font->child_fonts, &new_child->entry);
3161 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3171 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3173 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3175 if (pFT_Set_Charmap)
3178 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3180 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3182 for (i = 0; i < ft_face->num_charmaps; i++)
3184 if (ft_face->charmaps[i]->encoding == encoding)
3186 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3187 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3189 switch (ft_face->charmaps[i]->platform_id)
3192 cmap_def = ft_face->charmaps[i];
3194 case 0: /* Apple Unicode */
3195 cmap0 = ft_face->charmaps[i];
3197 case 1: /* Macintosh */
3198 cmap1 = ft_face->charmaps[i];
3201 cmap2 = ft_face->charmaps[i];
3203 case 3: /* Microsoft */
3204 cmap3 = ft_face->charmaps[i];
3209 if (cmap3) /* prefer Microsoft cmap table */
3210 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3212 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3214 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3216 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3218 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3220 return ft_err == FT_Err_Ok;
3223 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3226 /*************************************************************
3227 * WineEngCreateFontInstance
3230 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3233 Face *face, *best, *best_bitmap;
3234 Family *family, *last_resort_family;
3235 struct list *family_elem_ptr, *face_elem_ptr;
3236 INT height, width = 0;
3237 unsigned int score = 0, new_score;
3238 signed int diff = 0, newdiff;
3239 BOOL bd, it, can_use_bitmap;
3243 FontSubst *psub = NULL;
3245 EnterCriticalSection( &freetype_cs );
3247 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
3249 struct list *first_hfont = list_head(&ret->hfontlist);
3250 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3251 if(hflist->hfont == hfont)
3253 LeaveCriticalSection( &freetype_cs );
3258 if (!GetObjectW( hfont, sizeof(lf), &lf ))
3260 LeaveCriticalSection( &freetype_cs );
3263 lf.lfWidth = abs(lf.lfWidth);
3265 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3267 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3268 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3269 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3272 TRACE("DC transform %f %f %f %f %f %f\n",
3273 dc->xformWorld2Vport.eM11, dc->xformWorld2Vport.eM12,
3274 dc->xformWorld2Vport.eM21, dc->xformWorld2Vport.eM22,
3275 dc->xformWorld2Vport.eDx, dc->xformWorld2Vport.eDy);
3277 /* check the cache first */
3278 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
3279 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3280 LeaveCriticalSection( &freetype_cs );
3284 TRACE("not in cache\n");
3285 if(list_empty(&font_list)) /* No fonts installed */
3287 TRACE("No fonts installed\n");
3288 LeaveCriticalSection( &freetype_cs );
3291 if(!have_installed_roman_font)
3293 TRACE("No roman font installed\n");
3294 LeaveCriticalSection( &freetype_cs );
3300 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
3301 ret->font_desc.lf = lf;
3302 ret->font_desc.can_use_bitmap = can_use_bitmap;
3303 calc_hash(&ret->font_desc);
3304 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3305 hflist->hfont = hfont;
3306 list_add_head(&ret->hfontlist, &hflist->entry);
3308 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3309 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3310 original value lfCharSet. Note this is a special case for
3311 Symbol and doesn't happen at least for "Wingdings*" */
3313 if(!strcmpiW(lf.lfFaceName, SymbolW))
3314 lf.lfCharSet = SYMBOL_CHARSET;
3316 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3317 switch(lf.lfCharSet) {
3318 case DEFAULT_CHARSET:
3319 csi.fs.fsCsb[0] = 0;
3322 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3323 csi.fs.fsCsb[0] = 0;
3329 if(lf.lfFaceName[0] != '\0') {
3330 SYSTEM_LINKS *font_link;
3331 CHILD_FONT *font_link_entry;
3332 LPWSTR FaceName = lf.lfFaceName;
3335 * Check for a leading '@' this signals that the font is being
3336 * requested in tategaki mode (vertical writing substitution) but
3337 * does not affect the fontface that is to be selected.
3339 if (lf.lfFaceName[0]=='@')
3340 FaceName = &lf.lfFaceName[1];
3342 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3345 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3346 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3347 if (psub->to.charset != -1)
3348 lf.lfCharSet = psub->to.charset;
3351 /* We want a match on name and charset or just name if
3352 charset was DEFAULT_CHARSET. If the latter then
3353 we fixup the returned charset later in get_nearest_charset
3354 where we'll either use the charset of the current ansi codepage
3355 or if that's unavailable the first charset that the font supports.
3357 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3358 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3359 if (!strcmpiW(family->FamilyName, FaceName) ||
3360 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3362 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3363 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3364 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3365 if(face->scalable || can_use_bitmap)
3372 * Try check the SystemLink list first for a replacement font.
3373 * We may find good replacements there.
3375 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3377 if(!strcmpiW(font_link->font_name, FaceName))
3379 TRACE("found entry in system list\n");
3380 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3382 face = font_link_entry->face;
3383 family = face->family;
3384 if(csi.fs.fsCsb[0] &
3385 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3387 if(face->scalable || can_use_bitmap)
3395 psub = NULL; /* substitution is no more relevant */
3397 /* If requested charset was DEFAULT_CHARSET then try using charset
3398 corresponding to the current ansi codepage */
3399 if (!csi.fs.fsCsb[0] || lf.lfWeight == FW_DONTCARE)
3402 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3403 FIXME("TCI failed on codepage %d\n", acp);
3404 csi.fs.fsCsb[0] = 0;
3406 lf.lfCharSet = csi.ciCharset;
3409 /* Face families are in the top 4 bits of lfPitchAndFamily,
3410 so mask with 0xF0 before testing */
3412 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3413 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3414 strcpyW(lf.lfFaceName, defFixed);
3415 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3416 strcpyW(lf.lfFaceName, defSerif);
3417 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3418 strcpyW(lf.lfFaceName, defSans);
3420 strcpyW(lf.lfFaceName, defSans);
3421 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3422 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3423 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3424 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3425 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3426 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3427 if(face->scalable || can_use_bitmap)
3433 last_resort_family = NULL;
3434 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3435 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3436 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3437 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3438 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3441 if(can_use_bitmap && !last_resort_family)
3442 last_resort_family = family;
3447 if(last_resort_family) {
3448 family = last_resort_family;
3449 csi.fs.fsCsb[0] = 0;
3453 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3454 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3455 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3456 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3457 if(face->scalable) {
3458 csi.fs.fsCsb[0] = 0;
3459 WARN("just using first face for now\n");
3462 if(can_use_bitmap && !last_resort_family)
3463 last_resort_family = family;
3466 if(!last_resort_family) {
3467 FIXME("can't find a single appropriate font - bailing\n");
3469 LeaveCriticalSection( &freetype_cs );
3473 WARN("could only find a bitmap font - this will probably look awful!\n");
3474 family = last_resort_family;
3475 csi.fs.fsCsb[0] = 0;
3478 it = lf.lfItalic ? 1 : 0;
3479 bd = lf.lfWeight > 550 ? 1 : 0;
3481 height = lf.lfHeight;
3483 face = best = best_bitmap = NULL;
3484 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3486 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3490 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3491 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3492 new_score = (italic ^ it) + (bold ^ bd);
3493 if(!best || new_score <= score)
3495 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3496 italic, bold, it, bd);
3499 if(best->scalable && score == 0) break;
3503 newdiff = height - (signed int)(best->size.height);
3505 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3506 if(!best_bitmap || new_score < score ||
3507 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3509 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3512 if(score == 0 && diff == 0) break;
3519 face = best->scalable ? best : best_bitmap;
3520 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3521 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3525 if(csi.fs.fsCsb[0]) {
3526 ret->charset = lf.lfCharSet;
3527 ret->codepage = csi.ciACP;
3530 ret->charset = get_nearest_charset(face, &ret->codepage);
3532 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3533 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3535 ret->aveWidth = height ? lf.lfWidth : 0;
3537 if(!face->scalable) {
3538 /* Windows uses integer scaling factors for bitmap fonts */
3539 INT scale, scaled_height;
3541 if (height != 0) height = diff;
3542 height += face->size.height;
3544 scale = (height + face->size.height - 1) / face->size.height;
3545 scaled_height = scale * face->size.height;
3546 /* XP allows not more than 10% deviation */
3547 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3548 ret->scale_y = scale;
3550 width = face->size.x_ppem >> 6;
3551 height = face->size.y_ppem >> 6;
3555 TRACE("font scale y: %f\n", ret->scale_y);
3557 ret->ft_face = OpenFontFace(ret, face, width, height);
3562 LeaveCriticalSection( &freetype_cs );
3566 ret->ntmFlags = face->ntmFlags;
3568 if (ret->charset == SYMBOL_CHARSET &&
3569 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3572 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3576 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3579 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3580 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3581 ret->underline = lf.lfUnderline ? 0xff : 0;
3582 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3583 create_child_font_list(ret);
3585 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3587 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3588 if (length != GDI_ERROR)
3590 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3591 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3592 TRACE("Loaded GSUB table of %i bytes\n",length);
3596 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3598 list_add_head(&gdi_font_list, &ret->entry);
3599 LeaveCriticalSection( &freetype_cs );
3603 static void dump_gdi_font_list(void)
3606 struct list *elem_ptr;
3608 TRACE("---------- gdiFont Cache ----------\n");
3609 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3610 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3611 TRACE("gdiFont=%p %s %d\n",
3612 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3615 TRACE("---------- Unused gdiFont Cache ----------\n");
3616 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3617 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3618 TRACE("gdiFont=%p %s %d\n",
3619 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3623 /*************************************************************
3624 * WineEngDestroyFontInstance
3626 * free the gdiFont associated with this handle
3629 BOOL WineEngDestroyFontInstance(HFONT handle)
3634 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3637 EnterCriticalSection( &freetype_cs );
3639 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3641 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3642 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3643 if(hflist->hfont == handle)
3645 TRACE("removing child font %p from child list\n", gdiFont);
3646 list_remove(&gdiFont->entry);
3647 LeaveCriticalSection( &freetype_cs );
3652 TRACE("destroying hfont=%p\n", handle);
3654 dump_gdi_font_list();
3656 font_elem_ptr = list_head(&gdi_font_list);
3657 while(font_elem_ptr) {
3658 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3659 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3661 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3662 while(hfontlist_elem_ptr) {
3663 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3664 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3665 if(hflist->hfont == handle) {
3666 list_remove(&hflist->entry);
3667 HeapFree(GetProcessHeap(), 0, hflist);
3671 if(list_empty(&gdiFont->hfontlist)) {
3672 TRACE("Moving to Unused list\n");
3673 list_remove(&gdiFont->entry);
3674 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3679 font_elem_ptr = list_head(&unused_gdi_font_list);
3680 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3681 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3682 while(font_elem_ptr) {
3683 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3684 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3685 TRACE("freeing %p\n", gdiFont);
3686 list_remove(&gdiFont->entry);
3689 LeaveCriticalSection( &freetype_cs );
3693 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3694 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3699 if (face->cached_enum_data)
3702 *pelf = face->cached_enum_data->elf;
3703 *pntm = face->cached_enum_data->ntm;
3704 *ptype = face->cached_enum_data->type;
3708 font = alloc_font();
3710 if(face->scalable) {
3711 height = -2048; /* 2048 is the most common em size */
3714 height = face->size.y_ppem >> 6;
3715 width = face->size.x_ppem >> 6;
3717 font->scale_y = 1.0;
3719 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3725 font->name = strdupW(face->family->FamilyName);
3726 font->ntmFlags = face->ntmFlags;
3728 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3730 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3732 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3734 lstrcpynW(pelf->elfLogFont.lfFaceName,
3735 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3737 lstrcpynW(pelf->elfFullName,
3738 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3740 lstrcpynW(pelf->elfStyle,
3741 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3746 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3748 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3750 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3751 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3752 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3755 pntm->ntmTm.ntmFlags = face->ntmFlags;
3756 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3757 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3758 pntm->ntmFontSig = face->fs;
3760 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3762 pelf->elfLogFont.lfEscapement = 0;
3763 pelf->elfLogFont.lfOrientation = 0;
3764 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3765 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3766 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3767 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3768 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3769 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3770 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3771 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3772 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3773 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3774 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3777 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3778 *ptype |= TRUETYPE_FONTTYPE;
3779 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3780 *ptype |= DEVICE_FONTTYPE;
3781 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3782 *ptype |= RASTER_FONTTYPE;
3784 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3785 if (face->cached_enum_data)
3787 face->cached_enum_data->elf = *pelf;
3788 face->cached_enum_data->ntm = *pntm;
3789 face->cached_enum_data->type = *ptype;
3795 /*************************************************************
3799 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3803 struct list *family_elem_ptr, *face_elem_ptr;
3805 NEWTEXTMETRICEXW ntm;
3814 lf.lfCharSet = DEFAULT_CHARSET;
3815 lf.lfPitchAndFamily = 0;
3816 lf.lfFaceName[0] = 0;
3820 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3822 EnterCriticalSection( &freetype_cs );
3823 if(plf->lfFaceName[0]) {
3825 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3828 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3829 debugstr_w(psub->to.name));
3831 strcpyW(lf.lfFaceName, psub->to.name);
3835 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3836 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3837 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3838 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3839 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3840 GetEnumStructs(face, &elf, &ntm, &type);
3841 for(i = 0; i < 32; i++) {
3842 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3843 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3844 strcpyW(elf.elfScript, OEM_DOSW);
3845 i = 32; /* break out of loop */
3846 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3849 fs.fsCsb[0] = 1L << i;
3851 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3853 csi.ciCharset = DEFAULT_CHARSET;
3854 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3855 if(csi.ciCharset != DEFAULT_CHARSET) {
3856 elf.elfLogFont.lfCharSet =
3857 ntm.ntmTm.tmCharSet = csi.ciCharset;
3859 strcpyW(elf.elfScript, ElfScriptsW[i]);
3861 FIXME("Unknown elfscript for bit %d\n", i);
3864 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3865 debugstr_w(elf.elfLogFont.lfFaceName),
3866 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3867 csi.ciCharset, type, debugstr_w(elf.elfScript),
3868 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3869 ntm.ntmTm.ntmFlags);
3870 /* release section before callback (FIXME) */
3871 LeaveCriticalSection( &freetype_cs );
3872 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3873 EnterCriticalSection( &freetype_cs );
3879 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3880 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3881 face_elem_ptr = list_head(&family->faces);
3882 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3883 GetEnumStructs(face, &elf, &ntm, &type);
3884 for(i = 0; i < 32; i++) {
3885 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3886 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3887 strcpyW(elf.elfScript, OEM_DOSW);
3888 i = 32; /* break out of loop */
3889 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3892 fs.fsCsb[0] = 1L << i;
3894 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3896 csi.ciCharset = DEFAULT_CHARSET;
3897 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3898 if(csi.ciCharset != DEFAULT_CHARSET) {
3899 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3902 strcpyW(elf.elfScript, ElfScriptsW[i]);
3904 FIXME("Unknown elfscript for bit %d\n", i);
3907 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3908 debugstr_w(elf.elfLogFont.lfFaceName),
3909 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3910 csi.ciCharset, type, debugstr_w(elf.elfScript),
3911 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3912 ntm.ntmTm.ntmFlags);
3913 /* release section before callback (FIXME) */
3914 LeaveCriticalSection( &freetype_cs );
3915 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3916 EnterCriticalSection( &freetype_cs );
3920 LeaveCriticalSection( &freetype_cs );
3924 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3926 pt->x.value = vec->x >> 6;
3927 pt->x.fract = (vec->x & 0x3f) << 10;
3928 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3929 pt->y.value = vec->y >> 6;
3930 pt->y.fract = (vec->y & 0x3f) << 10;
3931 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3935 /***************************************************
3936 * According to the MSDN documentation on WideCharToMultiByte,
3937 * certain codepages cannot set the default_used parameter.
3938 * This returns TRUE if the codepage can set that parameter, false else
3939 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3941 static BOOL codepage_sets_default_used(UINT codepage)
3955 * GSUB Table handling functions
3958 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
3960 const GSUB_CoverageFormat1* cf1;
3962 cf1 = (GSUB_CoverageFormat1*)table;
3964 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
3966 int count = GET_BE_WORD(cf1->GlyphCount);
3968 TRACE("Coverage Format 1, %i glyphs\n",count);
3969 for (i = 0; i < count; i++)
3970 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
3974 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
3976 const GSUB_CoverageFormat2* cf2;
3979 cf2 = (GSUB_CoverageFormat2*)cf1;
3981 count = GET_BE_WORD(cf2->RangeCount);
3982 TRACE("Coverage Format 2, %i ranges\n",count);
3983 for (i = 0; i < count; i++)
3985 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
3987 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
3988 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
3990 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
3991 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
3997 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4002 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4004 const GSUB_ScriptList *script;
4005 const GSUB_Script *deflt = NULL;
4007 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
4009 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4010 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4012 const GSUB_Script *scr;
4015 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4016 scr = (GSUB_Script*)((LPBYTE)script + offset);
4018 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4020 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4026 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4030 const GSUB_LangSys *Lang;
4032 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4034 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4036 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4037 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4039 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4042 offset = GET_BE_WORD(script->DefaultLangSys);
4045 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4051 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4054 const GSUB_FeatureList *feature;
4055 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
4057 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4058 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4060 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4061 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4063 const GSUB_Feature *feat;
4064 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4071 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4075 const GSUB_LookupList *lookup;
4076 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
4078 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4079 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4081 const GSUB_LookupTable *look;
4082 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4083 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
4084 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4085 if (GET_BE_WORD(look->LookupType) != 1)
4086 FIXME("We only handle SubType 1\n");
4091 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4093 const GSUB_SingleSubstFormat1 *ssf1;
4094 offset = GET_BE_WORD(look->SubTable[j]);
4095 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
4096 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4098 int offset = GET_BE_WORD(ssf1->Coverage);
4099 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4100 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
4102 TRACE(" Glyph 0x%x ->",glyph);
4103 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4104 TRACE(" 0x%x\n",glyph);
4109 const GSUB_SingleSubstFormat2 *ssf2;
4113 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
4114 offset = GET_BE_WORD(ssf1->Coverage);
4115 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4116 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
4117 TRACE(" Coverage index %i\n",index);
4120 TRACE(" Glyph is 0x%x ->",glyph);
4121 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4122 TRACE("0x%x\n",glyph);
4131 static const char* get_opentype_script(const GdiFont *font)
4134 * I am not sure if this is the correct way to generate our script tag
4137 switch (font->charset)
4139 case ANSI_CHARSET: return "latn";
4140 case BALTIC_CHARSET: return "latn"; /* ?? */
4141 case CHINESEBIG5_CHARSET: return "hani";
4142 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4143 case GB2312_CHARSET: return "hani";
4144 case GREEK_CHARSET: return "grek";
4145 case HANGUL_CHARSET: return "hang";
4146 case RUSSIAN_CHARSET: return "cyrl";
4147 case SHIFTJIS_CHARSET: return "kana";
4148 case TURKISH_CHARSET: return "latn"; /* ?? */
4149 case VIETNAMESE_CHARSET: return "latn";
4150 case JOHAB_CHARSET: return "latn"; /* ?? */
4151 case ARABIC_CHARSET: return "arab";
4152 case HEBREW_CHARSET: return "hebr";
4153 case THAI_CHARSET: return "thai";
4154 default: return "latn";
4158 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4160 const GSUB_Header *header;
4161 const GSUB_Script *script;
4162 const GSUB_LangSys *language;
4163 const GSUB_Feature *feature;
4165 if (!font->GSUB_Table)
4168 header = font->GSUB_Table;
4170 script = GSUB_get_script_table(header, get_opentype_script(font));
4173 TRACE("Script not found\n");
4176 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4179 TRACE("Language not found\n");
4182 feature = GSUB_get_feature(header, language, "vrt2");
4184 feature = GSUB_get_feature(header, language, "vert");
4187 TRACE("vrt2/vert feature not found\n");
4190 return GSUB_apply_feature(header, feature, glyph);
4193 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4197 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4198 WCHAR wc = (WCHAR)glyph;
4200 BOOL *default_used_pointer;
4203 default_used_pointer = NULL;
4204 default_used = FALSE;
4205 if (codepage_sets_default_used(font->codepage))
4206 default_used_pointer = &default_used;
4207 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4210 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4211 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4212 return get_GSUB_vert_glyph(font,ret);
4215 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4216 glyph = glyph + 0xf000;
4217 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4218 return get_GSUB_vert_glyph(font,glyphId);
4221 /*************************************************************
4222 * WineEngGetGlyphIndices
4225 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4226 LPWORD pgi, DWORD flags)
4229 int default_char = -1;
4231 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4233 for(i = 0; i < count; i++)
4235 pgi[i] = get_glyph_index(font, lpstr[i]);
4238 if (default_char == -1)
4240 if (FT_IS_SFNT(font->ft_face))
4242 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4243 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4248 WineEngGetTextMetrics(font, &textm);
4249 default_char = textm.tmDefaultChar;
4252 pgi[i] = default_char;
4258 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4260 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4261 return !memcmp(matrix, &identity, sizeof(FMAT2));
4264 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4266 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4267 return !memcmp(matrix, &identity, sizeof(MAT2));
4270 /*************************************************************
4271 * WineEngGetGlyphOutline
4273 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4274 * except that the first parameter is the HWINEENGFONT of the font in
4275 * question rather than an HDC.
4278 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4279 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4282 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4283 FT_Face ft_face = incoming_font->ft_face;
4284 GdiFont *font = incoming_font;
4285 FT_UInt glyph_index;
4286 DWORD width, height, pitch, needed = 0;
4287 FT_Bitmap ft_bitmap;
4289 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4291 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4292 double widthRatio = 1.0;
4293 FT_Matrix transMat = identityMat;
4294 BOOL needsTransform = FALSE;
4295 BOOL tategaki = (font->GSUB_Table != NULL);
4296 UINT original_index;
4298 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4299 buflen, buf, lpmat);
4301 TRACE("font transform %f %f %f %f\n",
4302 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4303 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4305 EnterCriticalSection( &freetype_cs );
4307 if(format & GGO_GLYPH_INDEX) {
4308 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4309 original_index = glyph;
4310 format &= ~GGO_GLYPH_INDEX;
4312 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4313 ft_face = font->ft_face;
4314 original_index = glyph_index;
4317 /* tategaki never appears to happen to lower glyph index */
4318 if (glyph_index < TATEGAKI_LOWER_BOUND )
4321 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4322 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4323 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4324 font->gmsize * sizeof(GM*));
4326 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4327 FONT_GM(font,original_index)->init && (!lpmat || is_identity_MAT2(lpmat)))
4329 *lpgm = FONT_GM(font,original_index)->gm;
4330 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4331 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4332 lpgm->gmCellIncX, lpgm->gmCellIncY);
4333 LeaveCriticalSection( &freetype_cs );
4334 return 1; /* FIXME */
4338 if (!font->gm[original_index / GM_BLOCK_SIZE])
4339 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4341 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || lpmat)
4342 load_flags |= FT_LOAD_NO_BITMAP;
4344 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4347 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4348 LeaveCriticalSection( &freetype_cs );
4352 /* Scaling factor */
4357 WineEngGetTextMetrics(font, &tm);
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)
5569 INT n = strlenW(font->name) + 1;
5571 lstrcpynW(str, font->name, count);
5572 return min(count, n);
5577 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5579 if (fs) *fs = font->fs;
5580 return font->charset;
5583 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5585 GdiFont *font = dc->gdiFont, *linked_font;
5586 struct list *first_hfont;
5589 EnterCriticalSection( &freetype_cs );
5590 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
5591 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
5592 if(font == linked_font)
5593 *new_hfont = dc->hFont;
5596 first_hfont = list_head(&linked_font->hfontlist);
5597 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
5599 LeaveCriticalSection( &freetype_cs );
5603 /* Retrieve a list of supported Unicode ranges for a given font.
5604 * Can be called with NULL gs to calculate the buffer size. Returns
5605 * the number of ranges found.
5607 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
5609 DWORD num_ranges = 0;
5611 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5614 FT_ULong char_code, char_code_prev;
5617 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
5619 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5620 face->num_glyphs, glyph_code, char_code);
5622 if (!glyph_code) return 0;
5626 gs->ranges[0].wcLow = (USHORT)char_code;
5627 gs->ranges[0].cGlyphs = 0;
5628 gs->cGlyphsSupported = 0;
5634 if (char_code < char_code_prev)
5636 ERR("expected increasing char code from FT_Get_Next_Char\n");
5639 if (char_code - char_code_prev > 1)
5644 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5645 gs->ranges[num_ranges - 1].cGlyphs = 1;
5646 gs->cGlyphsSupported++;
5651 gs->ranges[num_ranges - 1].cGlyphs++;
5652 gs->cGlyphsSupported++;
5654 char_code_prev = char_code;
5655 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5659 FIXME("encoding %u not supported\n", face->charmap->encoding);
5664 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5667 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
5669 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5672 glyphset->cbThis = size;
5673 glyphset->cRanges = num_ranges;
5678 /*************************************************************
5681 BOOL WineEngFontIsLinked(GdiFont *font)
5684 EnterCriticalSection( &freetype_cs );
5685 ret = !list_empty(&font->child_fonts);
5686 LeaveCriticalSection( &freetype_cs );
5690 static BOOL is_hinting_enabled(void)
5692 /* Use the >= 2.2.0 function if available */
5693 if(pFT_Get_TrueType_Engine_Type)
5695 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
5696 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
5698 #ifdef FT_DRIVER_HAS_HINTER
5703 /* otherwise if we've been compiled with < 2.2.0 headers
5704 use the internal macro */
5705 mod = pFT_Get_Module(library, "truetype");
5706 if(mod && FT_DRIVER_HAS_HINTER(mod))
5714 /*************************************************************************
5715 * GetRasterizerCaps (GDI32.@)
5717 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5719 static int hinting = -1;
5723 hinting = is_hinting_enabled();
5724 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
5727 lprs->nSize = sizeof(RASTERIZER_STATUS);
5728 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
5729 lprs->nLanguageID = 0;
5733 /*************************************************************************
5734 * Kerning support for TrueType fonts
5736 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5738 struct TT_kern_table
5744 struct TT_kern_subtable
5753 USHORT horizontal : 1;
5755 USHORT cross_stream: 1;
5756 USHORT override : 1;
5757 USHORT reserved1 : 4;
5763 struct TT_format0_kern_subtable
5767 USHORT entrySelector;
5778 static DWORD parse_format0_kern_subtable(GdiFont *font,
5779 const struct TT_format0_kern_subtable *tt_f0_ks,
5780 const USHORT *glyph_to_char,
5781 KERNINGPAIR *kern_pair, DWORD cPairs)
5784 const struct TT_kern_pair *tt_kern_pair;
5786 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
5788 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
5790 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5791 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
5792 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
5794 if (!kern_pair || !cPairs)
5797 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
5799 nPairs = min(nPairs, cPairs);
5801 for (i = 0; i < nPairs; i++)
5803 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
5804 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
5805 /* this algorithm appears to better match what Windows does */
5806 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
5807 if (kern_pair->iKernAmount < 0)
5809 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
5810 kern_pair->iKernAmount -= font->ppem;
5812 else if (kern_pair->iKernAmount > 0)
5814 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
5815 kern_pair->iKernAmount += font->ppem;
5817 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
5819 TRACE("left %u right %u value %d\n",
5820 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
5824 TRACE("copied %u entries\n", nPairs);
5828 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5832 const struct TT_kern_table *tt_kern_table;
5833 const struct TT_kern_subtable *tt_kern_subtable;
5835 USHORT *glyph_to_char;
5837 EnterCriticalSection( &freetype_cs );
5838 if (font->total_kern_pairs != (DWORD)-1)
5840 if (cPairs && kern_pair)
5842 cPairs = min(cPairs, font->total_kern_pairs);
5843 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5844 LeaveCriticalSection( &freetype_cs );
5847 LeaveCriticalSection( &freetype_cs );
5848 return font->total_kern_pairs;
5851 font->total_kern_pairs = 0;
5853 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5855 if (length == GDI_ERROR)
5857 TRACE("no kerning data in the font\n");
5858 LeaveCriticalSection( &freetype_cs );
5862 buf = HeapAlloc(GetProcessHeap(), 0, length);
5865 WARN("Out of memory\n");
5866 LeaveCriticalSection( &freetype_cs );
5870 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5872 /* build a glyph index to char code map */
5873 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5876 WARN("Out of memory allocating a glyph index to char code map\n");
5877 HeapFree(GetProcessHeap(), 0, buf);
5878 LeaveCriticalSection( &freetype_cs );
5882 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5888 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5890 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5891 font->ft_face->num_glyphs, glyph_code, char_code);
5895 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5897 /* FIXME: This doesn't match what Windows does: it does some fancy
5898 * things with duplicate glyph index to char code mappings, while
5899 * we just avoid overriding existing entries.
5901 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5902 glyph_to_char[glyph_code] = (USHORT)char_code;
5904 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5911 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5912 for (n = 0; n <= 65535; n++)
5913 glyph_to_char[n] = (USHORT)n;
5916 tt_kern_table = buf;
5917 nTables = GET_BE_WORD(tt_kern_table->nTables);
5918 TRACE("version %u, nTables %u\n",
5919 GET_BE_WORD(tt_kern_table->version), nTables);
5921 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5923 for (i = 0; i < nTables; i++)
5925 struct TT_kern_subtable tt_kern_subtable_copy;
5927 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5928 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5929 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5931 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5932 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
5933 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
5935 /* According to the TrueType specification this is the only format
5936 * that will be properly interpreted by Windows and OS/2
5938 if (tt_kern_subtable_copy.coverage.bits.format == 0)
5940 DWORD new_chunk, old_total = font->total_kern_pairs;
5942 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5943 glyph_to_char, NULL, 0);
5944 font->total_kern_pairs += new_chunk;
5946 if (!font->kern_pairs)
5947 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
5948 font->total_kern_pairs * sizeof(*font->kern_pairs));
5950 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
5951 font->total_kern_pairs * sizeof(*font->kern_pairs));
5953 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5954 glyph_to_char, font->kern_pairs + old_total, new_chunk);
5957 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
5959 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
5962 HeapFree(GetProcessHeap(), 0, glyph_to_char);
5963 HeapFree(GetProcessHeap(), 0, buf);
5965 if (cPairs && kern_pair)
5967 cPairs = min(cPairs, font->total_kern_pairs);
5968 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5969 LeaveCriticalSection( &freetype_cs );
5972 LeaveCriticalSection( &freetype_cs );
5973 return font->total_kern_pairs;
5976 #else /* HAVE_FREETYPE */
5978 /*************************************************************************/
5980 BOOL WineEngInit(void)
5984 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
5988 BOOL WineEngDestroyFontInstance(HFONT hfont)
5993 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
5998 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
5999 LPWORD pgi, DWORD flags)
6004 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6005 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6008 ERR("called but we don't have FreeType\n");
6012 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6014 ERR("called but we don't have FreeType\n");
6018 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6019 OUTLINETEXTMETRICW *potm)
6021 ERR("called but we don't have FreeType\n");
6025 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6028 ERR("called but we don't have FreeType\n");
6032 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6035 ERR("called but we don't have FreeType\n");
6039 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6042 ERR("called but we don't have FreeType\n");
6046 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6047 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6049 ERR("called but we don't have FreeType\n");
6053 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6054 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6056 ERR("called but we don't have FreeType\n");
6060 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6063 ERR("called but we don't have FreeType\n");
6067 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6069 ERR("called but we don't have FreeType\n");
6073 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6079 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6085 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6091 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6094 return DEFAULT_CHARSET;
6097 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6102 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6104 FIXME("(%p, %p): stub\n", font, glyphset);
6108 BOOL WineEngFontIsLinked(GdiFont *font)
6113 /*************************************************************************
6114 * GetRasterizerCaps (GDI32.@)
6116 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6118 lprs->nSize = sizeof(RASTERIZER_STATUS);
6120 lprs->nLanguageID = 0;
6124 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6126 ERR("called but we don't have FreeType\n");
6130 #endif /* HAVE_FREETYPE */