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;
343 const WCHAR *font_name;
347 #define GM_BLOCK_SIZE 128
348 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
350 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
351 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
352 #define UNUSED_CACHE_SIZE 10
353 static struct list child_font_list = LIST_INIT(child_font_list);
354 static struct list system_links = LIST_INIT(system_links);
356 static struct list font_subst_list = LIST_INIT(font_subst_list);
358 static struct list font_list = LIST_INIT(font_list);
360 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
361 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
362 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
364 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
365 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
366 'W','i','n','d','o','w','s','\\',
367 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
368 'F','o','n','t','s','\0'};
370 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
371 'W','i','n','d','o','w','s',' ','N','T','\\',
372 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
373 'F','o','n','t','s','\0'};
375 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
376 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
377 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
378 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
380 static const WCHAR * const SystemFontValues[4] = {
387 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
388 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
390 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
391 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
392 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
393 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
394 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
395 'E','u','r','o','p','e','a','n','\0'};
396 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
397 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
398 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
399 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
400 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
401 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
402 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
403 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
404 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
405 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
406 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
407 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
409 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
419 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
427 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
436 typedef struct tagFontSubst {
452 static struct list mappings_list = LIST_INIT( mappings_list );
454 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
456 static CRITICAL_SECTION freetype_cs;
457 static CRITICAL_SECTION_DEBUG critsect_debug =
460 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
461 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
463 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
465 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
467 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
468 static BOOL use_default_fallback = FALSE;
470 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
472 /****************************************
473 * Notes on .fon files
475 * The fonts System, FixedSys and Terminal are special. There are typically multiple
476 * versions installed for different resolutions and codepages. Windows stores which one to use
477 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
479 * FIXEDFON.FON FixedSys
481 * OEMFONT.FON Terminal
482 * LogPixels Current dpi set by the display control panel applet
483 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
484 * also has a LogPixels value that appears to mirror this)
486 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
487 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
488 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
489 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
490 * so that makes sense.
492 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
493 * to be mapped into the registry on Windows 2000 at least).
496 * ega80woa.fon=ega80850.fon
497 * ega40woa.fon=ega40850.fon
498 * cga80woa.fon=cga80850.fon
499 * cga40woa.fon=cga40850.fon
502 /* These are all structures needed for the GSUB table */
504 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
505 #define TATEGAKI_LOWER_BOUND 0x02F1
521 GSUB_ScriptRecord ScriptRecord[1];
527 } GSUB_LangSysRecord;
532 GSUB_LangSysRecord LangSysRecord[1];
536 WORD LookupOrder; /* Reserved */
537 WORD ReqFeatureIndex;
539 WORD FeatureIndex[1];
545 } GSUB_FeatureRecord;
549 GSUB_FeatureRecord FeatureRecord[1];
553 WORD FeatureParams; /* Reserved */
555 WORD LookupListIndex[1];
574 } GSUB_CoverageFormat1;
579 WORD StartCoverageIndex;
585 GSUB_RangeRecord RangeRecord[1];
586 } GSUB_CoverageFormat2;
589 WORD SubstFormat; /* = 1 */
592 } GSUB_SingleSubstFormat1;
595 WORD SubstFormat; /* = 2 */
599 }GSUB_SingleSubstFormat2;
601 #ifdef HAVE_CARBON_CARBON_H
602 static char *find_cache_dir(void)
606 static char cached_path[MAX_PATH];
607 static const char *wine = "/Wine", *fonts = "/Fonts";
609 if(*cached_path) return cached_path;
611 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
614 WARN("can't create cached data folder\n");
617 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
620 WARN("can't create cached data path\n");
624 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
626 ERR("Could not create full path\n");
630 strcat(cached_path, wine);
632 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
634 WARN("Couldn't mkdir %s\n", cached_path);
638 strcat(cached_path, fonts);
639 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
641 WARN("Couldn't mkdir %s\n", cached_path);
648 /******************************************************************
651 * Extracts individual TrueType font files from a Mac suitcase font
652 * and saves them into the user's caches directory (see
654 * Returns a NULL terminated array of filenames.
656 * We do this because they are apps that try to read ttf files
657 * themselves and they don't like Mac suitcase files.
659 static char **expand_mac_font(const char *path)
666 const char *filename;
670 unsigned int size, max_size;
673 TRACE("path %s\n", path);
675 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
678 WARN("failed to get ref\n");
682 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
685 TRACE("no data fork, so trying resource fork\n");
686 res_ref = FSOpenResFile(&ref, fsRdPerm);
689 TRACE("unable to open resource fork\n");
696 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
699 CloseResFile(res_ref);
703 out_dir = find_cache_dir();
705 filename = strrchr(path, '/');
706 if(!filename) filename = path;
709 /* output filename has the form out_dir/filename_%04x.ttf */
710 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
717 unsigned short *num_faces_ptr, num_faces, face;
720 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
722 fond = Get1IndResource(fond_res, idx);
724 TRACE("got fond resource %d\n", idx);
727 fam_rec = *(FamRec**)fond;
728 num_faces_ptr = (unsigned short *)(fam_rec + 1);
729 num_faces = GET_BE_WORD(*num_faces_ptr);
731 assoc = (AsscEntry*)(num_faces_ptr + 1);
732 TRACE("num faces %04x\n", num_faces);
733 for(face = 0; face < num_faces; face++, assoc++)
736 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
737 unsigned short size, font_id;
740 size = GET_BE_WORD(assoc->fontSize);
741 font_id = GET_BE_WORD(assoc->fontID);
744 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
748 TRACE("trying to load sfnt id %04x\n", font_id);
749 sfnt = GetResource(sfnt_res, font_id);
752 TRACE("can't get sfnt resource %04x\n", font_id);
756 output = HeapAlloc(GetProcessHeap(), 0, output_len);
761 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
763 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
764 if(fd != -1 || errno == EEXIST)
768 unsigned char *sfnt_data;
771 sfnt_data = *(unsigned char**)sfnt;
772 write(fd, sfnt_data, GetHandleSize(sfnt));
776 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
779 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
781 ret.array[ret.size++] = output;
785 WARN("unable to create %s\n", output);
786 HeapFree(GetProcessHeap(), 0, output);
789 ReleaseResource(sfnt);
792 ReleaseResource(fond);
795 CloseResFile(res_ref);
800 #endif /* HAVE_CARBON_CARBON_H */
802 static inline BOOL is_win9x(void)
804 return GetVersion() & 0x80000000;
807 This function builds an FT_Fixed from a double. It fails if the absolute
808 value of the float number is greater than 32768.
810 static inline FT_Fixed FT_FixedFromFloat(double f)
816 This function builds an FT_Fixed from a FIXED. It simply put f.value
817 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
819 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
821 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
825 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
830 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
831 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
833 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
834 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
836 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
838 if(face_name && strcmpiW(face_name, family->FamilyName))
840 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
844 file = strrchr(face->file, '/');
849 if(!strcasecmp(file, file_nameA))
851 HeapFree(GetProcessHeap(), 0, file_nameA);
856 HeapFree(GetProcessHeap(), 0, file_nameA);
860 static Family *find_family_from_name(const WCHAR *name)
864 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
866 if(!strcmpiW(family->FamilyName, name))
873 static void DumpSubstList(void)
877 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
879 if(psub->from.charset != -1 || psub->to.charset != -1)
880 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
881 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
883 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
884 debugstr_w(psub->to.name));
889 static LPWSTR strdupW(LPCWSTR p)
892 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
893 ret = HeapAlloc(GetProcessHeap(), 0, len);
898 static LPSTR strdupA(LPCSTR p)
901 DWORD len = (strlen(p) + 1);
902 ret = HeapAlloc(GetProcessHeap(), 0, len);
907 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
912 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
914 if(!strcmpiW(element->from.name, from_name) &&
915 (element->from.charset == from_charset ||
916 element->from.charset == -1))
923 #define ADD_FONT_SUBST_FORCE 1
925 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
927 FontSubst *from_exist, *to_exist;
929 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
931 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
933 list_remove(&from_exist->entry);
934 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
935 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
936 HeapFree(GetProcessHeap(), 0, from_exist);
942 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
946 HeapFree(GetProcessHeap(), 0, subst->to.name);
947 subst->to.name = strdupW(to_exist->to.name);
950 list_add_tail(subst_list, &subst->entry);
955 HeapFree(GetProcessHeap(), 0, subst->from.name);
956 HeapFree(GetProcessHeap(), 0, subst->to.name);
957 HeapFree(GetProcessHeap(), 0, subst);
961 static void split_subst_info(NameCs *nc, LPSTR str)
963 CHAR *p = strrchr(str, ',');
968 nc->charset = strtol(p+1, NULL, 10);
971 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
972 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
973 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
976 static void LoadSubstList(void)
980 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
984 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
985 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
986 &hkey) == ERROR_SUCCESS) {
988 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
989 &valuelen, &datalen, NULL, NULL);
991 valuelen++; /* returned value doesn't include room for '\0' */
992 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
993 data = HeapAlloc(GetProcessHeap(), 0, datalen);
997 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
998 &dlen) == ERROR_SUCCESS) {
999 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1001 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1002 split_subst_info(&psub->from, value);
1003 split_subst_info(&psub->to, data);
1005 /* Win 2000 doesn't allow mapping between different charsets
1006 or mapping of DEFAULT_CHARSET */
1007 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1008 psub->to.charset == DEFAULT_CHARSET) {
1009 HeapFree(GetProcessHeap(), 0, psub->to.name);
1010 HeapFree(GetProcessHeap(), 0, psub->from.name);
1011 HeapFree(GetProcessHeap(), 0, psub);
1013 add_font_subst(&font_subst_list, psub, 0);
1015 /* reset dlen and vlen */
1019 HeapFree(GetProcessHeap(), 0, data);
1020 HeapFree(GetProcessHeap(), 0, value);
1025 static WCHAR *get_familyname(FT_Face ft_face)
1027 WCHAR *family = NULL;
1029 FT_UInt num_names, name_index, i;
1031 if(FT_IS_SFNT(ft_face))
1033 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1035 for(name_index = 0; name_index < num_names; name_index++)
1037 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1039 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
1040 (name.language_id == GetUserDefaultLCID()) &&
1041 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
1042 (name.encoding_id == TT_MS_ID_UNICODE_CS))
1044 /* String is not nul terminated and string_len is a byte length. */
1045 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1046 for(i = 0; i < name.string_len / 2; i++)
1048 WORD *tmp = (WORD *)&name.string[i * 2];
1049 family[i] = GET_BE_WORD(*tmp);
1053 TRACE("Got localised name %s\n", debugstr_w(family));
1064 /*****************************************************************
1067 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1068 * of FreeType that don't export this function.
1071 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1076 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1077 if(pFT_Load_Sfnt_Table)
1079 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1081 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1082 else /* Do it the hard way */
1084 TT_Face tt_face = (TT_Face) ft_face;
1085 SFNT_Interface *sfnt;
1086 if (FT_Version.major==2 && FT_Version.minor==0)
1089 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1093 /* A field was added in the middle of the structure in 2.1.x */
1094 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1096 err = sfnt->load_any(tt_face, table, offset, buf, len);
1104 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1105 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1106 "Please upgrade your freetype library.\n");
1109 err = FT_Err_Unimplemented_Feature;
1115 static inline int TestStyles(DWORD flags, DWORD styles)
1117 return (flags & styles) == styles;
1120 static int StyleOrdering(Face *face)
1122 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1124 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1126 if (TestStyles(face->ntmFlags, NTM_BOLD))
1128 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1131 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1132 debugstr_w(face->family->FamilyName),
1133 debugstr_w(face->StyleName),
1139 /* Add a style of face to a font family using an ordering of the list such
1140 that regular fonts come before bold and italic, and single styles come
1141 before compound styles. */
1142 static void AddFaceToFamily(Face *face, Family *family)
1146 LIST_FOR_EACH( entry, &family->faces )
1148 Face *ent = LIST_ENTRY(entry, Face, entry);
1149 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1151 list_add_before( entry, &face->entry );
1154 #define ADDFONT_EXTERNAL_FONT 0x01
1155 #define ADDFONT_FORCE_BITMAP 0x02
1156 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1160 TT_Header *pHeader = NULL;
1161 WCHAR *english_family, *localised_family, *StyleW;
1165 struct list *family_elem_ptr, *face_elem_ptr;
1167 FT_Long face_index = 0, num_faces;
1168 #ifdef HAVE_FREETYPE_FTWINFNT_H
1169 FT_WinFNT_HeaderRec winfnt_header;
1171 int i, bitmap_num, internal_leading;
1174 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1175 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1177 #ifdef HAVE_CARBON_CARBON_H
1178 if(file && !fake_family)
1180 char **mac_list = expand_mac_font(file);
1183 BOOL had_one = FALSE;
1185 for(cursor = mac_list; *cursor; cursor++)
1188 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1189 HeapFree(GetProcessHeap(), 0, *cursor);
1191 HeapFree(GetProcessHeap(), 0, mac_list);
1196 #endif /* HAVE_CARBON_CARBON_H */
1199 char *family_name = fake_family;
1203 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1204 err = pFT_New_Face(library, file, face_index, &ft_face);
1207 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1208 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1212 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1216 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*/
1217 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1218 pFT_Done_Face(ft_face);
1222 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1223 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1224 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1225 pFT_Done_Face(ft_face);
1229 if(FT_IS_SFNT(ft_face))
1231 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1232 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1233 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1235 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1236 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1237 pFT_Done_Face(ft_face);
1241 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1242 we don't want to load these. */
1243 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1247 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1249 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1250 pFT_Done_Face(ft_face);
1256 if(!ft_face->family_name || !ft_face->style_name) {
1257 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1258 pFT_Done_Face(ft_face);
1262 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1264 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1265 pFT_Done_Face(ft_face);
1271 localised_family = get_familyname(ft_face);
1272 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1274 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1275 HeapFree(GetProcessHeap(), 0, localised_family);
1276 num_faces = ft_face->num_faces;
1277 pFT_Done_Face(ft_face);
1280 HeapFree(GetProcessHeap(), 0, localised_family);
1284 family_name = ft_face->family_name;
1288 My_FT_Bitmap_Size *size = NULL;
1291 if(!FT_IS_SCALABLE(ft_face))
1292 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1294 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1295 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1296 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1298 localised_family = NULL;
1300 localised_family = get_familyname(ft_face);
1301 if(localised_family && !strcmpW(localised_family, english_family)) {
1302 HeapFree(GetProcessHeap(), 0, localised_family);
1303 localised_family = NULL;
1308 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1309 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1310 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1315 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1316 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1317 list_init(&family->faces);
1318 list_add_tail(&font_list, &family->entry);
1320 if(localised_family) {
1321 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1322 subst->from.name = strdupW(english_family);
1323 subst->from.charset = -1;
1324 subst->to.name = strdupW(localised_family);
1325 subst->to.charset = -1;
1326 add_font_subst(&font_subst_list, subst, 0);
1329 HeapFree(GetProcessHeap(), 0, localised_family);
1330 HeapFree(GetProcessHeap(), 0, english_family);
1332 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1333 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1334 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1336 internal_leading = 0;
1337 memset(&fs, 0, sizeof(fs));
1339 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1341 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1342 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1343 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1344 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1345 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1346 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1347 if(pOS2->version == 0) {
1350 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1351 fs.fsCsb[0] |= FS_LATIN1;
1353 fs.fsCsb[0] |= FS_SYMBOL;
1356 #ifdef HAVE_FREETYPE_FTWINFNT_H
1357 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1359 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1360 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1361 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1363 internal_leading = winfnt_header.internal_leading;
1367 face_elem_ptr = list_head(&family->faces);
1368 while(face_elem_ptr) {
1369 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1370 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1371 if(!strcmpW(face->StyleName, StyleW) &&
1372 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1373 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1374 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1375 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1378 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1379 HeapFree(GetProcessHeap(), 0, StyleW);
1380 pFT_Done_Face(ft_face);
1383 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1384 TRACE("Original font is newer so skipping this one\n");
1385 HeapFree(GetProcessHeap(), 0, StyleW);
1386 pFT_Done_Face(ft_face);
1389 TRACE("Replacing original with this one\n");
1390 list_remove(&face->entry);
1391 HeapFree(GetProcessHeap(), 0, face->file);
1392 HeapFree(GetProcessHeap(), 0, face->StyleName);
1393 HeapFree(GetProcessHeap(), 0, face);
1398 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1399 face->cached_enum_data = NULL;
1400 face->StyleName = StyleW;
1403 face->file = strdupA(file);
1404 face->font_data_ptr = NULL;
1405 face->font_data_size = 0;
1410 face->font_data_ptr = font_data_ptr;
1411 face->font_data_size = font_data_size;
1413 face->face_index = face_index;
1415 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1416 face->ntmFlags |= NTM_ITALIC;
1417 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1418 face->ntmFlags |= NTM_BOLD;
1419 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1420 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1421 face->family = family;
1422 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1424 memset(&face->fs_links, 0, sizeof(face->fs_links));
1426 if(FT_IS_SCALABLE(ft_face)) {
1427 memset(&face->size, 0, sizeof(face->size));
1428 face->scalable = TRUE;
1430 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1431 size->height, size->width, size->size >> 6,
1432 size->x_ppem >> 6, size->y_ppem >> 6);
1433 face->size.height = size->height;
1434 face->size.width = size->width;
1435 face->size.size = size->size;
1436 face->size.x_ppem = size->x_ppem;
1437 face->size.y_ppem = size->y_ppem;
1438 face->size.internal_leading = internal_leading;
1439 face->scalable = FALSE;
1442 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1444 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1446 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1447 face->ntmFlags |= NTM_PS_OPENTYPE;
1450 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1451 face->fs.fsCsb[0], face->fs.fsCsb[1],
1452 face->fs.fsUsb[0], face->fs.fsUsb[1],
1453 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1456 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1457 for(i = 0; i < ft_face->num_charmaps; i++) {
1458 switch(ft_face->charmaps[i]->encoding) {
1459 case FT_ENCODING_UNICODE:
1460 case FT_ENCODING_APPLE_ROMAN:
1461 face->fs.fsCsb[0] |= FS_LATIN1;
1463 case FT_ENCODING_MS_SYMBOL:
1464 face->fs.fsCsb[0] |= FS_SYMBOL;
1472 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1473 have_installed_roman_font = TRUE;
1475 AddFaceToFamily(face, family);
1477 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1479 num_faces = ft_face->num_faces;
1480 pFT_Done_Face(ft_face);
1481 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1482 debugstr_w(StyleW));
1483 } while(num_faces > ++face_index);
1487 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1489 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1492 static void DumpFontList(void)
1496 struct list *family_elem_ptr, *face_elem_ptr;
1498 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1499 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1500 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1501 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1502 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1503 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1505 TRACE(" %d", face->size.height);
1512 /***********************************************************
1513 * The replacement list is a way to map an entire font
1514 * family onto another family. For example adding
1516 * [HKCU\Software\Wine\Fonts\Replacements]
1517 * "Wingdings"="Winedings"
1519 * would enumerate the Winedings font both as Winedings and
1520 * Wingdings. However if a real Wingdings font is present the
1521 * replacement does not take place.
1524 static void LoadReplaceList(void)
1527 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1532 struct list *family_elem_ptr, *face_elem_ptr;
1535 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1536 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1538 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1539 &valuelen, &datalen, NULL, NULL);
1541 valuelen++; /* returned value doesn't include room for '\0' */
1542 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1543 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1547 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1548 &dlen) == ERROR_SUCCESS) {
1549 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1550 /* "NewName"="Oldname" */
1551 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1553 /* Find the old family and hence all of the font files
1555 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1556 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1557 if(!strcmpiW(family->FamilyName, data)) {
1558 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1559 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1560 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1561 debugstr_w(face->StyleName), familyA);
1562 /* Now add a new entry with the new family name */
1563 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1568 /* reset dlen and vlen */
1572 HeapFree(GetProcessHeap(), 0, data);
1573 HeapFree(GetProcessHeap(), 0, value);
1578 /*************************************************************
1581 static BOOL init_system_links(void)
1583 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1584 'W','i','n','d','o','w','s',' ','N','T','\\',
1585 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1586 'S','y','s','t','e','m','L','i','n','k',0};
1589 DWORD type, max_val, max_data, val_len, data_len, index;
1590 WCHAR *value, *data;
1591 WCHAR *entry, *next;
1592 SYSTEM_LINKS *font_link, *system_font_link;
1593 CHILD_FONT *child_font;
1594 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1595 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1596 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1602 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1604 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1605 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1606 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1607 val_len = max_val + 1;
1608 data_len = max_data;
1610 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1612 TRACE("%s:\n", debugstr_w(value));
1614 memset(&fs, 0, sizeof(fs));
1615 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1616 psub = get_font_subst(&font_subst_list, value, -1);
1617 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1618 list_init(&font_link->links);
1619 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1622 CHILD_FONT *child_font;
1624 TRACE("\t%s\n", debugstr_w(entry));
1626 next = entry + strlenW(entry) + 1;
1628 face_name = strchrW(entry, ',');
1632 while(isspaceW(*face_name))
1635 psub = get_font_subst(&font_subst_list, face_name, -1);
1637 face_name = psub->to.name;
1639 face = find_face_from_filename(entry, face_name);
1642 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1646 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1647 child_font->face = face;
1648 child_font->font = NULL;
1649 fs.fsCsb[0] |= face->fs.fsCsb[0];
1650 fs.fsCsb[1] |= face->fs.fsCsb[1];
1651 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1652 list_add_tail(&font_link->links, &child_font->entry);
1654 family = find_family_from_name(font_link->font_name);
1657 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1659 face->fs_links = fs;
1662 list_add_tail(&system_links, &font_link->entry);
1663 val_len = max_val + 1;
1664 data_len = max_data;
1667 HeapFree(GetProcessHeap(), 0, value);
1668 HeapFree(GetProcessHeap(), 0, data);
1672 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1675 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1676 system_font_link->font_name = strdupW(System);
1677 list_init(&system_font_link->links);
1679 face = find_face_from_filename(tahoma_ttf, Tahoma);
1682 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1683 child_font->face = face;
1684 child_font->font = NULL;
1685 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1686 list_add_tail(&system_font_link->links, &child_font->entry);
1688 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1690 if(!strcmpiW(font_link->font_name, Tahoma))
1692 CHILD_FONT *font_link_entry;
1693 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1695 CHILD_FONT *new_child;
1696 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1697 new_child->face = font_link_entry->face;
1698 new_child->font = NULL;
1699 list_add_tail(&system_font_link->links, &new_child->entry);
1704 list_add_tail(&system_links, &system_font_link->entry);
1708 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1711 struct dirent *dent;
1712 char path[MAX_PATH];
1714 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1716 dir = opendir(dirname);
1718 WARN("Can't open directory %s\n", debugstr_a(dirname));
1721 while((dent = readdir(dir)) != NULL) {
1722 struct stat statbuf;
1724 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1727 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1729 sprintf(path, "%s/%s", dirname, dent->d_name);
1731 if(stat(path, &statbuf) == -1)
1733 WARN("Can't stat %s\n", debugstr_a(path));
1736 if(S_ISDIR(statbuf.st_mode))
1737 ReadFontDir(path, external_fonts);
1739 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1745 static void load_fontconfig_fonts(void)
1747 #ifdef SONAME_LIBFONTCONFIG
1748 void *fc_handle = NULL;
1757 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1759 TRACE("Wine cannot find the fontconfig library (%s).\n",
1760 SONAME_LIBFONTCONFIG);
1763 #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;}
1764 LOAD_FUNCPTR(FcConfigGetCurrent);
1765 LOAD_FUNCPTR(FcFontList);
1766 LOAD_FUNCPTR(FcFontSetDestroy);
1767 LOAD_FUNCPTR(FcInit);
1768 LOAD_FUNCPTR(FcObjectSetAdd);
1769 LOAD_FUNCPTR(FcObjectSetCreate);
1770 LOAD_FUNCPTR(FcObjectSetDestroy);
1771 LOAD_FUNCPTR(FcPatternCreate);
1772 LOAD_FUNCPTR(FcPatternDestroy);
1773 LOAD_FUNCPTR(FcPatternGetBool);
1774 LOAD_FUNCPTR(FcPatternGetString);
1777 if(!pFcInit()) return;
1779 config = pFcConfigGetCurrent();
1780 pat = pFcPatternCreate();
1781 os = pFcObjectSetCreate();
1782 pFcObjectSetAdd(os, FC_FILE);
1783 pFcObjectSetAdd(os, FC_SCALABLE);
1784 fontset = pFcFontList(config, pat, os);
1785 if(!fontset) return;
1786 for(i = 0; i < fontset->nfont; i++) {
1789 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1791 TRACE("fontconfig: %s\n", file);
1793 /* We're just interested in OT/TT fonts for now, so this hack just
1794 picks up the scalable fonts without extensions .pf[ab] to save time
1795 loading every other font */
1797 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1799 TRACE("not scalable\n");
1803 len = strlen( file );
1804 if(len < 4) continue;
1805 ext = &file[ len - 3 ];
1806 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1807 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1809 pFcFontSetDestroy(fontset);
1810 pFcObjectSetDestroy(os);
1811 pFcPatternDestroy(pat);
1817 static BOOL load_font_from_data_dir(LPCWSTR file)
1820 const char *data_dir = wine_get_data_dir();
1822 if (!data_dir) data_dir = wine_get_build_dir();
1829 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1831 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1833 strcpy(unix_name, data_dir);
1834 strcat(unix_name, "/fonts/");
1836 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1838 EnterCriticalSection( &freetype_cs );
1839 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1840 LeaveCriticalSection( &freetype_cs );
1841 HeapFree(GetProcessHeap(), 0, unix_name);
1846 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1848 static const WCHAR slashW[] = {'\\','\0'};
1850 WCHAR windowsdir[MAX_PATH];
1853 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1854 strcatW(windowsdir, fontsW);
1855 strcatW(windowsdir, slashW);
1856 strcatW(windowsdir, file);
1857 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1858 EnterCriticalSection( &freetype_cs );
1859 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1860 LeaveCriticalSection( &freetype_cs );
1861 HeapFree(GetProcessHeap(), 0, unixname);
1866 static void load_system_fonts(void)
1869 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1870 const WCHAR * const *value;
1872 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1875 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1876 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1877 strcatW(windowsdir, fontsW);
1878 for(value = SystemFontValues; *value; value++) {
1879 dlen = sizeof(data);
1880 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1884 sprintfW(pathW, fmtW, windowsdir, data);
1885 if((unixname = wine_get_unix_file_name(pathW))) {
1886 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1887 HeapFree(GetProcessHeap(), 0, unixname);
1890 load_font_from_data_dir(data);
1897 /*************************************************************
1899 * This adds registry entries for any externally loaded fonts
1900 * (fonts from fontconfig or FontDirs). It also deletes entries
1901 * of no longer existing fonts.
1904 static void update_reg_entries(void)
1906 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1911 struct list *family_elem_ptr, *face_elem_ptr;
1913 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1914 static const WCHAR spaceW[] = {' ', '\0'};
1917 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1918 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1919 ERR("Can't create Windows font reg key\n");
1923 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1924 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1925 ERR("Can't create Windows font reg key\n");
1929 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1930 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1931 ERR("Can't create external font reg key\n");
1935 /* enumerate the fonts and add external ones to the two keys */
1937 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1938 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1939 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1940 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1941 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1942 if(!face->external) continue;
1944 if (!(face->ntmFlags & NTM_REGULAR))
1945 len = len_fam + strlenW(face->StyleName) + 1;
1946 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1947 strcpyW(valueW, family->FamilyName);
1948 if(len != len_fam) {
1949 strcatW(valueW, spaceW);
1950 strcatW(valueW, face->StyleName);
1952 strcatW(valueW, TrueType);
1954 file = wine_get_dos_file_name(face->file);
1956 len = strlenW(file) + 1;
1959 if((path = strrchr(face->file, '/')) == NULL)
1963 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1965 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1966 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1968 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1969 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1970 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1972 HeapFree(GetProcessHeap(), 0, file);
1973 HeapFree(GetProcessHeap(), 0, valueW);
1977 if(external_key) RegCloseKey(external_key);
1978 if(win9x_key) RegCloseKey(win9x_key);
1979 if(winnt_key) RegCloseKey(winnt_key);
1983 static void delete_external_font_keys(void)
1985 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1986 DWORD dlen, vlen, datalen, valuelen, i, type;
1990 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1991 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1992 ERR("Can't create Windows font reg key\n");
1996 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1997 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1998 ERR("Can't create Windows font reg key\n");
2002 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2003 ERR("Can't create external font reg key\n");
2007 /* Delete all external fonts added last time */
2009 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2010 &valuelen, &datalen, NULL, NULL);
2011 valuelen++; /* returned value doesn't include room for '\0' */
2012 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2013 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2015 dlen = datalen * sizeof(WCHAR);
2018 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2019 &dlen) == ERROR_SUCCESS) {
2021 RegDeleteValueW(winnt_key, valueW);
2022 RegDeleteValueW(win9x_key, valueW);
2023 /* reset dlen and vlen */
2027 HeapFree(GetProcessHeap(), 0, data);
2028 HeapFree(GetProcessHeap(), 0, valueW);
2030 /* Delete the old external fonts key */
2031 RegCloseKey(external_key);
2032 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2035 if(win9x_key) RegCloseKey(win9x_key);
2036 if(winnt_key) RegCloseKey(winnt_key);
2039 /*************************************************************
2040 * WineEngAddFontResourceEx
2043 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2046 if (ft_handle) /* do it only if we have freetype up and running */
2051 FIXME("Ignoring flags %x\n", flags);
2053 if((unixname = wine_get_unix_file_name(file)))
2055 EnterCriticalSection( &freetype_cs );
2056 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2057 LeaveCriticalSection( &freetype_cs );
2058 HeapFree(GetProcessHeap(), 0, unixname);
2060 if (!ret && !strchrW(file, '\\')) {
2061 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2062 ret = load_font_from_winfonts_dir(file);
2064 /* Try in datadir/fonts (or builddir/fonts),
2065 * needed for Magic the Gathering Online
2067 ret = load_font_from_data_dir(file);
2074 /*************************************************************
2075 * WineEngAddFontMemResourceEx
2078 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2080 if (ft_handle) /* do it only if we have freetype up and running */
2082 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2084 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2085 memcpy(pFontCopy, pbFont, cbFont);
2087 EnterCriticalSection( &freetype_cs );
2088 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2089 LeaveCriticalSection( &freetype_cs );
2093 TRACE("AddFontToList failed\n");
2094 HeapFree(GetProcessHeap(), 0, pFontCopy);
2097 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2098 * For now return something unique but quite random
2100 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2101 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2108 /*************************************************************
2109 * WineEngRemoveFontResourceEx
2112 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2118 static const struct nls_update_font_list
2120 UINT ansi_cp, oem_cp;
2121 const char *oem, *fixed, *system;
2122 const char *courier, *serif, *small, *sserif;
2123 /* these are for font substitutes */
2124 const char *shelldlg, *tmsrmn;
2125 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2129 const char *from, *to;
2130 } arial_0, courier_new_0, times_new_roman_0;
2131 } nls_update_font_list[] =
2133 /* Latin 1 (United States) */
2134 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2135 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2136 "Tahoma","Times New Roman",
2137 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2140 /* Latin 1 (Multilingual) */
2141 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2142 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2143 "Tahoma","Times New Roman", /* FIXME unverified */
2144 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2147 /* Eastern Europe */
2148 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2149 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2150 "Tahoma","Times New Roman", /* FIXME unverified */
2151 "Fixedsys,238", "System,238",
2152 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2153 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2154 { "Arial CE,0", "Arial,238" },
2155 { "Courier New CE,0", "Courier New,238" },
2156 { "Times New Roman CE,0", "Times New Roman,238" }
2159 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2160 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2161 "Tahoma","Times New Roman", /* FIXME unverified */
2162 "Fixedsys,204", "System,204",
2163 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2164 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2165 { "Arial Cyr,0", "Arial,204" },
2166 { "Courier New Cyr,0", "Courier New,204" },
2167 { "Times New Roman Cyr,0", "Times New Roman,204" }
2170 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2171 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2172 "Tahoma","Times New Roman", /* FIXME unverified */
2173 "Fixedsys,161", "System,161",
2174 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2175 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2176 { "Arial Greek,0", "Arial,161" },
2177 { "Courier New Greek,0", "Courier New,161" },
2178 { "Times New Roman Greek,0", "Times New Roman,161" }
2181 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2182 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2183 "Tahoma","Times New Roman", /* FIXME unverified */
2184 "Fixedsys,162", "System,162",
2185 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2186 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2187 { "Arial Tur,0", "Arial,162" },
2188 { "Courier New Tur,0", "Courier New,162" },
2189 { "Times New Roman Tur,0", "Times New Roman,162" }
2192 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2193 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2194 "Tahoma","Times New Roman", /* FIXME unverified */
2195 "Fixedsys,177", "System,177",
2196 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2197 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2201 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2202 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2203 "Tahoma","Times New Roman", /* FIXME unverified */
2204 "Fixedsys,178", "System,178",
2205 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2206 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2210 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2211 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2212 "Tahoma","Times New Roman", /* FIXME unverified */
2213 "Fixedsys,186", "System,186",
2214 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2215 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2216 { "Arial Baltic,0", "Arial,186" },
2217 { "Courier New Baltic,0", "Courier New,186" },
2218 { "Times New Roman Baltic,0", "Times New Roman,186" }
2221 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2222 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2223 "Tahoma","Times New Roman", /* FIXME unverified */
2224 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2228 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2229 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2230 "Tahoma","Times New Roman", /* FIXME unverified */
2231 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2235 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2236 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2237 "MS UI Gothic","MS Serif",
2238 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2241 /* Chinese Simplified */
2242 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2243 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2244 "Tahoma", "Times New Roman", /* FIXME unverified */
2245 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2249 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2250 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2252 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2255 /* Chinese Traditional */
2256 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2257 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2258 "PMingLiU", "MingLiU",
2259 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2264 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2266 return ( ansi_cp == 932 /* CP932 for Japanese */
2267 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2268 || ansi_cp == 949 /* CP949 for Korean */
2269 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2272 static inline HKEY create_fonts_NT_registry_key(void)
2276 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2277 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2281 static inline HKEY create_fonts_9x_registry_key(void)
2285 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2286 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2290 static inline HKEY create_config_fonts_registry_key(void)
2294 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2295 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2299 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2301 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2302 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2303 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2304 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2307 static void set_value_key(HKEY hkey, const char *name, const char *value)
2310 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2312 RegDeleteValueA(hkey, name);
2315 static void update_font_info(void)
2317 char buf[40], cpbuf[40];
2320 UINT i, ansi_cp = 0, oem_cp = 0;
2323 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2326 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2327 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2328 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2329 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2330 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2332 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2333 if (is_dbcs_ansi_cp(ansi_cp))
2334 use_default_fallback = TRUE;
2337 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2339 if (!strcmp( buf, cpbuf )) /* already set correctly */
2344 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2346 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2348 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2351 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2355 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2356 nls_update_font_list[i].oem_cp == oem_cp)
2358 hkey = create_config_fonts_registry_key();
2359 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2360 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2361 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2364 hkey = create_fonts_NT_registry_key();
2365 add_font_list(hkey, &nls_update_font_list[i]);
2368 hkey = create_fonts_9x_registry_key();
2369 add_font_list(hkey, &nls_update_font_list[i]);
2372 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2374 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2375 strlen(nls_update_font_list[i].shelldlg)+1);
2376 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2377 strlen(nls_update_font_list[i].tmsrmn)+1);
2379 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2380 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2381 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2382 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2383 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2384 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2385 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2386 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2388 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2389 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2390 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2398 /* Delete the FontSubstitutes from other locales */
2399 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2401 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2402 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2403 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2409 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2413 static BOOL init_freetype(void)
2415 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2418 "Wine cannot find the FreeType font library. To enable Wine to\n"
2419 "use TrueType fonts please install a version of FreeType greater than\n"
2420 "or equal to 2.0.5.\n"
2421 "http://www.freetype.org\n");
2425 #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;}
2427 LOAD_FUNCPTR(FT_Vector_Unit)
2428 LOAD_FUNCPTR(FT_Done_Face)
2429 LOAD_FUNCPTR(FT_Get_Char_Index)
2430 LOAD_FUNCPTR(FT_Get_Module)
2431 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2432 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2433 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2434 LOAD_FUNCPTR(FT_Init_FreeType)
2435 LOAD_FUNCPTR(FT_Load_Glyph)
2436 LOAD_FUNCPTR(FT_Matrix_Multiply)
2437 LOAD_FUNCPTR(FT_MulFix)
2438 LOAD_FUNCPTR(FT_New_Face)
2439 LOAD_FUNCPTR(FT_New_Memory_Face)
2440 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2441 LOAD_FUNCPTR(FT_Outline_Transform)
2442 LOAD_FUNCPTR(FT_Outline_Translate)
2443 LOAD_FUNCPTR(FT_Select_Charmap)
2444 LOAD_FUNCPTR(FT_Set_Charmap)
2445 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2446 LOAD_FUNCPTR(FT_Vector_Transform)
2449 /* Don't warn if these ones are missing */
2450 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2451 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2452 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2453 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2454 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2455 #ifdef HAVE_FREETYPE_FTWINFNT_H
2456 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2458 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2459 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2460 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2461 <= 2.0.3 has FT_Sqrt64 */
2465 if(pFT_Init_FreeType(&library) != 0) {
2466 ERR("Can't init FreeType library\n");
2467 wine_dlclose(ft_handle, NULL, 0);
2471 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2472 if (pFT_Library_Version)
2473 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2475 if (FT_Version.major<=0)
2481 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2482 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2483 ((FT_Version.minor << 8) & 0x00ff00) |
2484 ((FT_Version.patch ) & 0x0000ff);
2490 "Wine cannot find certain functions that it needs inside the FreeType\n"
2491 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2492 "FreeType to at least version 2.0.5.\n"
2493 "http://www.freetype.org\n");
2494 wine_dlclose(ft_handle, NULL, 0);
2499 /*************************************************************
2502 * Initialize FreeType library and create a list of available faces
2504 BOOL WineEngInit(void)
2506 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2507 static const WCHAR pathW[] = {'P','a','t','h',0};
2509 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2511 WCHAR windowsdir[MAX_PATH];
2514 const char *data_dir;
2518 /* update locale dependent font info in registry */
2521 if(!init_freetype()) return FALSE;
2523 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2524 ERR("Failed to create font mutex\n");
2527 WaitForSingleObject(font_mutex, INFINITE);
2529 delete_external_font_keys();
2531 /* load the system bitmap fonts */
2532 load_system_fonts();
2534 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2535 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2536 strcatW(windowsdir, fontsW);
2537 if((unixname = wine_get_unix_file_name(windowsdir)))
2539 ReadFontDir(unixname, FALSE);
2540 HeapFree(GetProcessHeap(), 0, unixname);
2543 /* load the system truetype fonts */
2544 data_dir = wine_get_data_dir();
2545 if (!data_dir) data_dir = wine_get_build_dir();
2546 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2547 strcpy(unixname, data_dir);
2548 strcat(unixname, "/fonts/");
2549 ReadFontDir(unixname, TRUE);
2550 HeapFree(GetProcessHeap(), 0, unixname);
2553 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2554 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2555 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2557 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2558 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2559 &hkey) == ERROR_SUCCESS) {
2561 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2562 &valuelen, &datalen, NULL, NULL);
2564 valuelen++; /* returned value doesn't include room for '\0' */
2565 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2566 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2569 dlen = datalen * sizeof(WCHAR);
2571 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2572 &dlen) == ERROR_SUCCESS) {
2573 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2575 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2577 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2578 HeapFree(GetProcessHeap(), 0, unixname);
2581 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2583 WCHAR pathW[MAX_PATH];
2584 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2587 sprintfW(pathW, fmtW, windowsdir, data);
2588 if((unixname = wine_get_unix_file_name(pathW)))
2590 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2591 HeapFree(GetProcessHeap(), 0, unixname);
2594 load_font_from_data_dir(data);
2596 /* reset dlen and vlen */
2601 HeapFree(GetProcessHeap(), 0, data);
2602 HeapFree(GetProcessHeap(), 0, valueW);
2606 load_fontconfig_fonts();
2608 /* then look in any directories that we've specified in the config file */
2609 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2610 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2616 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2618 len += sizeof(WCHAR);
2619 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2620 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2622 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2623 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2624 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2625 TRACE( "got font path %s\n", debugstr_a(valueA) );
2629 LPSTR next = strchr( ptr, ':' );
2630 if (next) *next++ = 0;
2631 ReadFontDir( ptr, TRUE );
2634 HeapFree( GetProcessHeap(), 0, valueA );
2636 HeapFree( GetProcessHeap(), 0, valueW );
2645 update_reg_entries();
2647 init_system_links();
2649 ReleaseMutex(font_mutex);
2654 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2657 TT_HoriHeader *pHori;
2661 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2662 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2664 if(height == 0) height = 16;
2666 /* Calc. height of EM square:
2668 * For +ve lfHeight we have
2669 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2670 * Re-arranging gives:
2671 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2673 * For -ve lfHeight we have
2675 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2676 * with il = winAscent + winDescent - units_per_em]
2681 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2682 ppem = MulDiv(ft_face->units_per_EM, height,
2683 pHori->Ascender - pHori->Descender);
2685 ppem = MulDiv(ft_face->units_per_EM, height,
2686 pOS2->usWinAscent + pOS2->usWinDescent);
2694 static struct font_mapping *map_font_file( const char *name )
2696 struct font_mapping *mapping;
2700 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2701 if (fstat( fd, &st ) == -1) goto error;
2703 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2705 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2707 mapping->refcount++;
2712 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2715 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2718 if (mapping->data == MAP_FAILED)
2720 HeapFree( GetProcessHeap(), 0, mapping );
2723 mapping->refcount = 1;
2724 mapping->dev = st.st_dev;
2725 mapping->ino = st.st_ino;
2726 mapping->size = st.st_size;
2727 list_add_tail( &mappings_list, &mapping->entry );
2735 static void unmap_font_file( struct font_mapping *mapping )
2737 if (!--mapping->refcount)
2739 list_remove( &mapping->entry );
2740 munmap( mapping->data, mapping->size );
2741 HeapFree( GetProcessHeap(), 0, mapping );
2745 static LONG load_VDMX(GdiFont*, LONG);
2747 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2754 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2758 if (!(font->mapping = map_font_file( face->file )))
2760 WARN("failed to map %s\n", debugstr_a(face->file));
2763 data_ptr = font->mapping->data;
2764 data_size = font->mapping->size;
2768 data_ptr = face->font_data_ptr;
2769 data_size = face->font_data_size;
2772 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2774 ERR("FT_New_Face rets %d\n", err);
2778 /* set it here, as load_VDMX needs it */
2779 font->ft_face = ft_face;
2781 if(FT_IS_SCALABLE(ft_face)) {
2782 /* load the VDMX table if we have one */
2783 font->ppem = load_VDMX(font, height);
2785 font->ppem = calc_ppem_for_height(ft_face, height);
2786 TRACE("height %d => ppem %d\n", height, font->ppem);
2788 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2789 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2791 font->ppem = height;
2792 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2793 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2799 static int get_nearest_charset(Face *face, int *cp)
2801 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2802 a single face with the requested charset. The idea is to check if
2803 the selected font supports the current ANSI codepage, if it does
2804 return the corresponding charset, else return the first charset */
2807 int acp = GetACP(), i;
2811 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2812 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2813 return csi.ciCharset;
2815 for(i = 0; i < 32; i++) {
2817 if(face->fs.fsCsb[0] & fs0) {
2818 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2820 return csi.ciCharset;
2823 FIXME("TCI failing on %x\n", fs0);
2827 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2828 face->fs.fsCsb[0], face->file);
2830 return DEFAULT_CHARSET;
2833 static GdiFont *alloc_font(void)
2835 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2837 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2838 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2840 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2841 ret->total_kern_pairs = (DWORD)-1;
2842 ret->kern_pairs = NULL;
2843 list_init(&ret->hfontlist);
2844 list_init(&ret->child_fonts);
2848 static void free_font(GdiFont *font)
2850 struct list *cursor, *cursor2;
2853 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2855 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2856 struct list *first_hfont;
2857 HFONTLIST *hfontlist;
2858 list_remove(cursor);
2861 first_hfont = list_head(&child->font->hfontlist);
2862 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2863 DeleteObject(hfontlist->hfont);
2864 HeapFree(GetProcessHeap(), 0, hfontlist);
2865 free_font(child->font);
2867 HeapFree(GetProcessHeap(), 0, child);
2870 if (font->ft_face) pFT_Done_Face(font->ft_face);
2871 if (font->mapping) unmap_font_file( font->mapping );
2872 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2873 HeapFree(GetProcessHeap(), 0, font->potm);
2874 HeapFree(GetProcessHeap(), 0, font->name);
2875 for (i = 0; i < font->gmsize; i++)
2876 HeapFree(GetProcessHeap(),0,font->gm[i]);
2877 HeapFree(GetProcessHeap(), 0, font->gm);
2878 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2879 HeapFree(GetProcessHeap(), 0, font);
2883 /*************************************************************
2886 * load the vdmx entry for the specified height
2889 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2890 ( ( (FT_ULong)_x4 << 24 ) | \
2891 ( (FT_ULong)_x3 << 16 ) | \
2892 ( (FT_ULong)_x2 << 8 ) | \
2895 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2910 static LONG load_VDMX(GdiFont *font, LONG height)
2914 BYTE devXRatio, devYRatio;
2915 USHORT numRecs, numRatios;
2916 DWORD result, offset = -1;
2920 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2922 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2925 /* FIXME: need the real device aspect ratio */
2929 numRecs = GET_BE_WORD(hdr[1]);
2930 numRatios = GET_BE_WORD(hdr[2]);
2932 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2933 for(i = 0; i < numRatios; i++) {
2936 offset = (3 * 2) + (i * sizeof(Ratios));
2937 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2940 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2942 if((ratio.xRatio == 0 &&
2943 ratio.yStartRatio == 0 &&
2944 ratio.yEndRatio == 0) ||
2945 (devXRatio == ratio.xRatio &&
2946 devYRatio >= ratio.yStartRatio &&
2947 devYRatio <= ratio.yEndRatio))
2949 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2950 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2951 offset = GET_BE_WORD(tmp);
2957 FIXME("No suitable ratio found\n");
2961 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2963 BYTE startsz, endsz;
2966 recs = GET_BE_WORD(group.recs);
2967 startsz = group.startsz;
2968 endsz = group.endsz;
2970 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2972 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2973 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2974 if(result == GDI_ERROR) {
2975 FIXME("Failed to retrieve vTable\n");
2980 for(i = 0; i < recs; i++) {
2981 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2982 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2983 ppem = GET_BE_WORD(vTable[i * 3]);
2985 if(yMax + -yMin == height) {
2988 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2991 if(yMax + -yMin > height) {
2994 goto end; /* failed */
2996 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2997 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2998 ppem = GET_BE_WORD(vTable[i * 3]);
2999 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3005 TRACE("ppem not found for height %d\n", height);
3009 if(ppem < startsz || ppem > endsz)
3012 for(i = 0; i < recs; i++) {
3014 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3016 if(yPelHeight > ppem)
3019 if(yPelHeight == ppem) {
3020 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3021 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3022 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
3028 HeapFree(GetProcessHeap(), 0, vTable);
3034 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3036 if(font->font_desc.hash != fd->hash) return TRUE;
3037 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3038 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3039 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3040 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3043 static void calc_hash(FONT_DESC *pfd)
3045 DWORD hash = 0, *ptr, two_chars;
3049 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3051 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3053 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3055 pwc = (WCHAR *)&two_chars;
3057 *pwc = toupperW(*pwc);
3059 *pwc = toupperW(*pwc);
3063 hash ^= !pfd->can_use_bitmap;
3068 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3073 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3077 fd.can_use_bitmap = can_use_bitmap;
3080 /* try the in-use list */
3081 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3082 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3083 if(!fontcmp(ret, &fd)) {
3084 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3085 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3086 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3087 if(hflist->hfont == hfont)
3090 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3091 hflist->hfont = hfont;
3092 list_add_head(&ret->hfontlist, &hflist->entry);
3097 /* then the unused list */
3098 font_elem_ptr = list_head(&unused_gdi_font_list);
3099 while(font_elem_ptr) {
3100 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3101 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3102 if(!fontcmp(ret, &fd)) {
3103 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3104 assert(list_empty(&ret->hfontlist));
3105 TRACE("Found %p in unused list\n", ret);
3106 list_remove(&ret->entry);
3107 list_add_head(&gdi_font_list, &ret->entry);
3108 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3109 hflist->hfont = hfont;
3110 list_add_head(&ret->hfontlist, &hflist->entry);
3117 static void add_to_cache(GdiFont *font)
3119 static DWORD cache_num = 1;
3121 font->cache_num = cache_num++;
3122 list_add_head(&gdi_font_list, &font->entry);
3125 /*************************************************************
3126 * create_child_font_list
3128 static BOOL create_child_font_list(GdiFont *font)
3131 SYSTEM_LINKS *font_link;
3132 CHILD_FONT *font_link_entry, *new_child;
3134 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3136 if(!strcmpW(font_link->font_name, font->name))
3138 TRACE("found entry in system list\n");
3139 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3141 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3142 new_child->face = font_link_entry->face;
3143 new_child->font = NULL;
3144 list_add_tail(&font->child_fonts, &new_child->entry);
3145 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3152 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3153 * Sans Serif. This is how asian windows get default fallbacks for fonts
3155 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3156 font->charset != OEM_CHARSET &&
3157 strcmpW(font->name,szDefaultFallbackLink) != 0)
3158 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3160 if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3162 TRACE("found entry in default fallback list\n");
3163 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3165 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3166 new_child->face = font_link_entry->face;
3167 new_child->font = NULL;
3168 list_add_tail(&font->child_fonts, &new_child->entry);
3169 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3179 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3181 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3183 if (pFT_Set_Charmap)
3186 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3188 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3190 for (i = 0; i < ft_face->num_charmaps; i++)
3192 if (ft_face->charmaps[i]->encoding == encoding)
3194 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3195 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3197 switch (ft_face->charmaps[i]->platform_id)
3200 cmap_def = ft_face->charmaps[i];
3202 case 0: /* Apple Unicode */
3203 cmap0 = ft_face->charmaps[i];
3205 case 1: /* Macintosh */
3206 cmap1 = ft_face->charmaps[i];
3209 cmap2 = ft_face->charmaps[i];
3211 case 3: /* Microsoft */
3212 cmap3 = ft_face->charmaps[i];
3217 if (cmap3) /* prefer Microsoft cmap table */
3218 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3220 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3222 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3224 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3226 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3228 return ft_err == FT_Err_Ok;
3231 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3234 /*************************************************************
3235 * WineEngCreateFontInstance
3238 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3241 Face *face, *best, *best_bitmap;
3242 Family *family, *last_resort_family;
3243 struct list *family_elem_ptr, *face_elem_ptr;
3244 INT height, width = 0;
3245 unsigned int score = 0, new_score;
3246 signed int diff = 0, newdiff;
3247 BOOL bd, it, can_use_bitmap;
3252 FontSubst *psub = NULL;
3254 EnterCriticalSection( &freetype_cs );
3256 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
3258 struct list *first_hfont = list_head(&ret->hfontlist);
3259 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3260 if(hflist->hfont == hfont)
3262 LeaveCriticalSection( &freetype_cs );
3267 if (!GetObjectW( hfont, sizeof(lf), &lf ))
3269 LeaveCriticalSection( &freetype_cs );
3272 lf.lfWidth = abs(lf.lfWidth);
3274 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3276 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3277 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3278 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3281 if(dc->GraphicsMode == GM_ADVANCED)
3282 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3285 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3286 font scaling abilities. */
3287 dcmat.eM11 = dcmat.eM22 = fabs(dc->xformWorld2Vport.eM22);
3288 dcmat.eM21 = dcmat.eM12 = 0;
3291 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3292 dcmat.eM21, dcmat.eM22);
3294 /* check the cache first */
3295 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3296 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3297 LeaveCriticalSection( &freetype_cs );
3301 TRACE("not in cache\n");
3302 if(list_empty(&font_list)) /* No fonts installed */
3304 TRACE("No fonts installed\n");
3305 LeaveCriticalSection( &freetype_cs );
3308 if(!have_installed_roman_font)
3310 TRACE("No roman font installed\n");
3311 LeaveCriticalSection( &freetype_cs );
3317 ret->font_desc.matrix = dcmat;
3318 ret->font_desc.lf = lf;
3319 ret->font_desc.can_use_bitmap = can_use_bitmap;
3320 calc_hash(&ret->font_desc);
3321 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3322 hflist->hfont = hfont;
3323 list_add_head(&ret->hfontlist, &hflist->entry);
3325 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3326 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3327 original value lfCharSet. Note this is a special case for
3328 Symbol and doesn't happen at least for "Wingdings*" */
3330 if(!strcmpiW(lf.lfFaceName, SymbolW))
3331 lf.lfCharSet = SYMBOL_CHARSET;
3333 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3334 switch(lf.lfCharSet) {
3335 case DEFAULT_CHARSET:
3336 csi.fs.fsCsb[0] = 0;
3339 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3340 csi.fs.fsCsb[0] = 0;
3346 if(lf.lfFaceName[0] != '\0') {
3347 SYSTEM_LINKS *font_link;
3348 CHILD_FONT *font_link_entry;
3349 LPWSTR FaceName = lf.lfFaceName;
3352 * Check for a leading '@' this signals that the font is being
3353 * requested in tategaki mode (vertical writing substitution) but
3354 * does not affect the fontface that is to be selected.
3356 if (lf.lfFaceName[0]=='@')
3357 FaceName = &lf.lfFaceName[1];
3359 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3362 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3363 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3364 if (psub->to.charset != -1)
3365 lf.lfCharSet = psub->to.charset;
3368 /* We want a match on name and charset or just name if
3369 charset was DEFAULT_CHARSET. If the latter then
3370 we fixup the returned charset later in get_nearest_charset
3371 where we'll either use the charset of the current ansi codepage
3372 or if that's unavailable the first charset that the font supports.
3374 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3375 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3376 if (!strcmpiW(family->FamilyName, FaceName) ||
3377 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3379 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3380 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3381 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3382 if(face->scalable || can_use_bitmap)
3389 * Try check the SystemLink list first for a replacement font.
3390 * We may find good replacements there.
3392 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3394 if(!strcmpiW(font_link->font_name, FaceName))
3396 TRACE("found entry in system list\n");
3397 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3399 face = font_link_entry->face;
3400 family = face->family;
3401 if(csi.fs.fsCsb[0] &
3402 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3404 if(face->scalable || can_use_bitmap)
3412 psub = NULL; /* substitution is no more relevant */
3414 /* If requested charset was DEFAULT_CHARSET then try using charset
3415 corresponding to the current ansi codepage */
3416 if (!csi.fs.fsCsb[0] || lf.lfWeight == FW_DONTCARE)
3419 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3420 FIXME("TCI failed on codepage %d\n", acp);
3421 csi.fs.fsCsb[0] = 0;
3423 lf.lfCharSet = csi.ciCharset;
3426 /* Face families are in the top 4 bits of lfPitchAndFamily,
3427 so mask with 0xF0 before testing */
3429 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3430 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3431 strcpyW(lf.lfFaceName, defFixed);
3432 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3433 strcpyW(lf.lfFaceName, defSerif);
3434 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3435 strcpyW(lf.lfFaceName, defSans);
3437 strcpyW(lf.lfFaceName, defSans);
3438 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3439 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3440 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3441 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3442 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3443 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3444 if(face->scalable || can_use_bitmap)
3450 last_resort_family = NULL;
3451 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3452 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3453 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3454 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3455 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3458 if(can_use_bitmap && !last_resort_family)
3459 last_resort_family = family;
3464 if(last_resort_family) {
3465 family = last_resort_family;
3466 csi.fs.fsCsb[0] = 0;
3470 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3471 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3472 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3473 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3474 if(face->scalable) {
3475 csi.fs.fsCsb[0] = 0;
3476 WARN("just using first face for now\n");
3479 if(can_use_bitmap && !last_resort_family)
3480 last_resort_family = family;
3483 if(!last_resort_family) {
3484 FIXME("can't find a single appropriate font - bailing\n");
3486 LeaveCriticalSection( &freetype_cs );
3490 WARN("could only find a bitmap font - this will probably look awful!\n");
3491 family = last_resort_family;
3492 csi.fs.fsCsb[0] = 0;
3495 it = lf.lfItalic ? 1 : 0;
3496 bd = lf.lfWeight > 550 ? 1 : 0;
3498 height = lf.lfHeight;
3500 face = best = best_bitmap = NULL;
3501 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3503 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3507 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3508 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3509 new_score = (italic ^ it) + (bold ^ bd);
3510 if(!best || new_score <= score)
3512 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3513 italic, bold, it, bd);
3516 if(best->scalable && score == 0) break;
3520 newdiff = height - (signed int)(best->size.height);
3522 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3523 if(!best_bitmap || new_score < score ||
3524 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3526 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3529 if(score == 0 && diff == 0) break;
3536 face = best->scalable ? best : best_bitmap;
3537 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3538 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3542 if(csi.fs.fsCsb[0]) {
3543 ret->charset = lf.lfCharSet;
3544 ret->codepage = csi.ciACP;
3547 ret->charset = get_nearest_charset(face, &ret->codepage);
3549 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3550 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3552 ret->aveWidth = height ? lf.lfWidth : 0;
3554 if(!face->scalable) {
3555 /* Windows uses integer scaling factors for bitmap fonts */
3556 INT scale, scaled_height;
3558 if (height != 0) height = diff;
3559 height += face->size.height;
3561 scale = (height + face->size.height - 1) / face->size.height;
3562 scaled_height = scale * face->size.height;
3563 /* XP allows not more than 10% deviation */
3564 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3565 ret->scale_y = scale;
3567 width = face->size.x_ppem >> 6;
3568 height = face->size.y_ppem >> 6;
3572 TRACE("font scale y: %f\n", ret->scale_y);
3574 ret->ft_face = OpenFontFace(ret, face, width, height);
3579 LeaveCriticalSection( &freetype_cs );
3583 ret->ntmFlags = face->ntmFlags;
3585 if (ret->charset == SYMBOL_CHARSET &&
3586 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3589 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3593 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3596 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3597 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3598 ret->underline = lf.lfUnderline ? 0xff : 0;
3599 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3600 create_child_font_list(ret);
3602 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3604 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3605 if (length != GDI_ERROR)
3607 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3608 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3609 TRACE("Loaded GSUB table of %i bytes\n",length);
3613 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3616 LeaveCriticalSection( &freetype_cs );
3620 static void dump_gdi_font_list(void)
3623 struct list *elem_ptr;
3625 TRACE("---------- gdiFont Cache ----------\n");
3626 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3627 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3628 TRACE("gdiFont=%p %s %d\n",
3629 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3632 TRACE("---------- Unused gdiFont Cache ----------\n");
3633 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3634 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3635 TRACE("gdiFont=%p %s %d\n",
3636 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3640 /*************************************************************
3641 * WineEngDestroyFontInstance
3643 * free the gdiFont associated with this handle
3646 BOOL WineEngDestroyFontInstance(HFONT handle)
3651 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3654 EnterCriticalSection( &freetype_cs );
3656 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3658 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3659 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3660 if(hflist->hfont == handle)
3662 TRACE("removing child font %p from child list\n", gdiFont);
3663 list_remove(&gdiFont->entry);
3664 LeaveCriticalSection( &freetype_cs );
3669 TRACE("destroying hfont=%p\n", handle);
3671 dump_gdi_font_list();
3673 font_elem_ptr = list_head(&gdi_font_list);
3674 while(font_elem_ptr) {
3675 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3676 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3678 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3679 while(hfontlist_elem_ptr) {
3680 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3681 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3682 if(hflist->hfont == handle) {
3683 list_remove(&hflist->entry);
3684 HeapFree(GetProcessHeap(), 0, hflist);
3688 if(list_empty(&gdiFont->hfontlist)) {
3689 TRACE("Moving to Unused list\n");
3690 list_remove(&gdiFont->entry);
3691 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3696 font_elem_ptr = list_head(&unused_gdi_font_list);
3697 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3698 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3699 while(font_elem_ptr) {
3700 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3701 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3702 TRACE("freeing %p\n", gdiFont);
3703 list_remove(&gdiFont->entry);
3706 LeaveCriticalSection( &freetype_cs );
3710 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3711 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3716 if (face->cached_enum_data)
3719 *pelf = face->cached_enum_data->elf;
3720 *pntm = face->cached_enum_data->ntm;
3721 *ptype = face->cached_enum_data->type;
3725 font = alloc_font();
3727 if(face->scalable) {
3728 height = -2048; /* 2048 is the most common em size */
3731 height = face->size.y_ppem >> 6;
3732 width = face->size.x_ppem >> 6;
3734 font->scale_y = 1.0;
3736 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3742 font->name = strdupW(face->family->FamilyName);
3743 font->ntmFlags = face->ntmFlags;
3745 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3747 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3749 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3751 lstrcpynW(pelf->elfLogFont.lfFaceName,
3752 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3754 lstrcpynW(pelf->elfFullName,
3755 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3757 lstrcpynW(pelf->elfStyle,
3758 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3763 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3765 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3767 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3768 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3769 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3772 pntm->ntmTm.ntmFlags = face->ntmFlags;
3773 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3774 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3775 pntm->ntmFontSig = face->fs;
3777 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3779 pelf->elfLogFont.lfEscapement = 0;
3780 pelf->elfLogFont.lfOrientation = 0;
3781 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3782 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3783 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3784 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3785 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3786 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3787 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3788 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3789 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3790 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3791 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3794 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3795 *ptype |= TRUETYPE_FONTTYPE;
3796 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3797 *ptype |= DEVICE_FONTTYPE;
3798 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3799 *ptype |= RASTER_FONTTYPE;
3801 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3802 if (face->cached_enum_data)
3804 face->cached_enum_data->elf = *pelf;
3805 face->cached_enum_data->ntm = *pntm;
3806 face->cached_enum_data->type = *ptype;
3812 /*************************************************************
3816 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3820 struct list *family_elem_ptr, *face_elem_ptr;
3822 NEWTEXTMETRICEXW ntm;
3831 lf.lfCharSet = DEFAULT_CHARSET;
3832 lf.lfPitchAndFamily = 0;
3833 lf.lfFaceName[0] = 0;
3837 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3839 EnterCriticalSection( &freetype_cs );
3840 if(plf->lfFaceName[0]) {
3842 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3845 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3846 debugstr_w(psub->to.name));
3848 strcpyW(lf.lfFaceName, psub->to.name);
3852 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3853 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3854 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3855 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3856 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3857 GetEnumStructs(face, &elf, &ntm, &type);
3858 for(i = 0; i < 32; i++) {
3859 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3860 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3861 strcpyW(elf.elfScript, OEM_DOSW);
3862 i = 32; /* break out of loop */
3863 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3866 fs.fsCsb[0] = 1L << i;
3868 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3870 csi.ciCharset = DEFAULT_CHARSET;
3871 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3872 if(csi.ciCharset != DEFAULT_CHARSET) {
3873 elf.elfLogFont.lfCharSet =
3874 ntm.ntmTm.tmCharSet = csi.ciCharset;
3876 strcpyW(elf.elfScript, ElfScriptsW[i]);
3878 FIXME("Unknown elfscript for bit %d\n", i);
3881 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3882 debugstr_w(elf.elfLogFont.lfFaceName),
3883 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3884 csi.ciCharset, type, debugstr_w(elf.elfScript),
3885 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3886 ntm.ntmTm.ntmFlags);
3887 /* release section before callback (FIXME) */
3888 LeaveCriticalSection( &freetype_cs );
3889 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3890 EnterCriticalSection( &freetype_cs );
3896 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3897 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3898 face_elem_ptr = list_head(&family->faces);
3899 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3900 GetEnumStructs(face, &elf, &ntm, &type);
3901 for(i = 0; i < 32; i++) {
3902 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3903 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3904 strcpyW(elf.elfScript, OEM_DOSW);
3905 i = 32; /* break out of loop */
3906 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3909 fs.fsCsb[0] = 1L << i;
3911 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3913 csi.ciCharset = DEFAULT_CHARSET;
3914 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3915 if(csi.ciCharset != DEFAULT_CHARSET) {
3916 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3919 strcpyW(elf.elfScript, ElfScriptsW[i]);
3921 FIXME("Unknown elfscript for bit %d\n", i);
3924 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3925 debugstr_w(elf.elfLogFont.lfFaceName),
3926 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3927 csi.ciCharset, type, debugstr_w(elf.elfScript),
3928 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3929 ntm.ntmTm.ntmFlags);
3930 /* release section before callback (FIXME) */
3931 LeaveCriticalSection( &freetype_cs );
3932 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3933 EnterCriticalSection( &freetype_cs );
3937 LeaveCriticalSection( &freetype_cs );
3941 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3943 pt->x.value = vec->x >> 6;
3944 pt->x.fract = (vec->x & 0x3f) << 10;
3945 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3946 pt->y.value = vec->y >> 6;
3947 pt->y.fract = (vec->y & 0x3f) << 10;
3948 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3952 /***************************************************
3953 * According to the MSDN documentation on WideCharToMultiByte,
3954 * certain codepages cannot set the default_used parameter.
3955 * This returns TRUE if the codepage can set that parameter, false else
3956 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3958 static BOOL codepage_sets_default_used(UINT codepage)
3972 * GSUB Table handling functions
3975 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
3977 const GSUB_CoverageFormat1* cf1;
3979 cf1 = (GSUB_CoverageFormat1*)table;
3981 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
3983 int count = GET_BE_WORD(cf1->GlyphCount);
3985 TRACE("Coverage Format 1, %i glyphs\n",count);
3986 for (i = 0; i < count; i++)
3987 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
3991 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
3993 const GSUB_CoverageFormat2* cf2;
3996 cf2 = (GSUB_CoverageFormat2*)cf1;
3998 count = GET_BE_WORD(cf2->RangeCount);
3999 TRACE("Coverage Format 2, %i ranges\n",count);
4000 for (i = 0; i < count; i++)
4002 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4004 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4005 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4007 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4008 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4014 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4019 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4021 const GSUB_ScriptList *script;
4022 const GSUB_Script *deflt = NULL;
4024 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
4026 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4027 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4029 const GSUB_Script *scr;
4032 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4033 scr = (GSUB_Script*)((LPBYTE)script + offset);
4035 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4037 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4043 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4047 const GSUB_LangSys *Lang;
4049 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4051 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4053 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4054 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4056 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4059 offset = GET_BE_WORD(script->DefaultLangSys);
4062 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4068 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4071 const GSUB_FeatureList *feature;
4072 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
4074 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4075 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4077 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4078 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4080 const GSUB_Feature *feat;
4081 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4088 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4092 const GSUB_LookupList *lookup;
4093 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
4095 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4096 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4098 const GSUB_LookupTable *look;
4099 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4100 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
4101 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4102 if (GET_BE_WORD(look->LookupType) != 1)
4103 FIXME("We only handle SubType 1\n");
4108 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4110 const GSUB_SingleSubstFormat1 *ssf1;
4111 offset = GET_BE_WORD(look->SubTable[j]);
4112 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
4113 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4115 int offset = GET_BE_WORD(ssf1->Coverage);
4116 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4117 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
4119 TRACE(" Glyph 0x%x ->",glyph);
4120 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4121 TRACE(" 0x%x\n",glyph);
4126 const GSUB_SingleSubstFormat2 *ssf2;
4130 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
4131 offset = GET_BE_WORD(ssf1->Coverage);
4132 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4133 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
4134 TRACE(" Coverage index %i\n",index);
4137 TRACE(" Glyph is 0x%x ->",glyph);
4138 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4139 TRACE("0x%x\n",glyph);
4148 static const char* get_opentype_script(const GdiFont *font)
4151 * I am not sure if this is the correct way to generate our script tag
4154 switch (font->charset)
4156 case ANSI_CHARSET: return "latn";
4157 case BALTIC_CHARSET: return "latn"; /* ?? */
4158 case CHINESEBIG5_CHARSET: return "hani";
4159 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4160 case GB2312_CHARSET: return "hani";
4161 case GREEK_CHARSET: return "grek";
4162 case HANGUL_CHARSET: return "hang";
4163 case RUSSIAN_CHARSET: return "cyrl";
4164 case SHIFTJIS_CHARSET: return "kana";
4165 case TURKISH_CHARSET: return "latn"; /* ?? */
4166 case VIETNAMESE_CHARSET: return "latn";
4167 case JOHAB_CHARSET: return "latn"; /* ?? */
4168 case ARABIC_CHARSET: return "arab";
4169 case HEBREW_CHARSET: return "hebr";
4170 case THAI_CHARSET: return "thai";
4171 default: return "latn";
4175 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4177 const GSUB_Header *header;
4178 const GSUB_Script *script;
4179 const GSUB_LangSys *language;
4180 const GSUB_Feature *feature;
4182 if (!font->GSUB_Table)
4185 header = font->GSUB_Table;
4187 script = GSUB_get_script_table(header, get_opentype_script(font));
4190 TRACE("Script not found\n");
4193 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4196 TRACE("Language not found\n");
4199 feature = GSUB_get_feature(header, language, "vrt2");
4201 feature = GSUB_get_feature(header, language, "vert");
4204 TRACE("vrt2/vert feature not found\n");
4207 return GSUB_apply_feature(header, feature, glyph);
4210 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4214 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4215 WCHAR wc = (WCHAR)glyph;
4217 BOOL *default_used_pointer;
4220 default_used_pointer = NULL;
4221 default_used = FALSE;
4222 if (codepage_sets_default_used(font->codepage))
4223 default_used_pointer = &default_used;
4224 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4227 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4228 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4229 return get_GSUB_vert_glyph(font,ret);
4232 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4233 glyph = glyph + 0xf000;
4234 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4235 return get_GSUB_vert_glyph(font,glyphId);
4238 /*************************************************************
4239 * WineEngGetGlyphIndices
4242 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4243 LPWORD pgi, DWORD flags)
4246 int default_char = -1;
4248 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4250 for(i = 0; i < count; i++)
4252 pgi[i] = get_glyph_index(font, lpstr[i]);
4255 if (default_char == -1)
4257 if (FT_IS_SFNT(font->ft_face))
4259 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4260 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4265 WineEngGetTextMetrics(font, &textm);
4266 default_char = textm.tmDefaultChar;
4269 pgi[i] = default_char;
4275 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4277 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4278 return !memcmp(matrix, &identity, sizeof(FMAT2));
4281 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4283 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4284 return !memcmp(matrix, &identity, sizeof(MAT2));
4287 /*************************************************************
4288 * WineEngGetGlyphOutline
4290 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4291 * except that the first parameter is the HWINEENGFONT of the font in
4292 * question rather than an HDC.
4295 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4296 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4299 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4300 FT_Face ft_face = incoming_font->ft_face;
4301 GdiFont *font = incoming_font;
4302 FT_UInt glyph_index;
4303 DWORD width, height, pitch, needed = 0;
4304 FT_Bitmap ft_bitmap;
4306 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4308 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4309 double widthRatio = 1.0;
4310 FT_Matrix transMat = identityMat;
4311 FT_Matrix transMatUnrotated;
4312 BOOL needsTransform = FALSE;
4313 BOOL tategaki = (font->GSUB_Table != NULL);
4314 UINT original_index;
4316 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4317 buflen, buf, lpmat);
4319 TRACE("font transform %f %f %f %f\n",
4320 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4321 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4323 EnterCriticalSection( &freetype_cs );
4325 if(format & GGO_GLYPH_INDEX) {
4326 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4327 original_index = glyph;
4328 format &= ~GGO_GLYPH_INDEX;
4330 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4331 ft_face = font->ft_face;
4332 original_index = glyph_index;
4335 /* tategaki never appears to happen to lower glyph index */
4336 if (glyph_index < TATEGAKI_LOWER_BOUND )
4339 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4340 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4341 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4342 font->gmsize * sizeof(GM*));
4344 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4345 FONT_GM(font,original_index)->init && (!lpmat || is_identity_MAT2(lpmat)))
4347 *lpgm = FONT_GM(font,original_index)->gm;
4348 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4349 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4350 lpgm->gmCellIncX, lpgm->gmCellIncY);
4351 LeaveCriticalSection( &freetype_cs );
4352 return 1; /* FIXME */
4356 if (!font->gm[original_index / GM_BLOCK_SIZE])
4357 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4359 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || lpmat)
4360 load_flags |= FT_LOAD_NO_BITMAP;
4362 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4365 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4366 LeaveCriticalSection( &freetype_cs );
4370 /* Scaling factor */
4375 WineEngGetTextMetrics(font, &tm);
4377 widthRatio = (double)font->aveWidth;
4378 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4381 widthRatio = font->scale_y;
4383 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4384 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4386 adv = (INT)((ft_face->glyph->metrics.horiAdvance) + 63) >> 6;
4388 bbx = (right - left) >> 6;
4390 /* Scaling transform */
4391 if (widthRatio != 1.0 || font->scale_y != 1.0)
4394 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4397 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4399 pFT_Matrix_Multiply(&scaleMat, &transMat);
4400 needsTransform = TRUE;
4403 /* Slant transform */
4404 if (font->fake_italic) {
4407 slantMat.xx = (1 << 16);
4408 slantMat.xy = ((1 << 16) >> 2);
4410 slantMat.yy = (1 << 16);
4411 pFT_Matrix_Multiply(&slantMat, &transMat);
4412 needsTransform = TRUE;
4415 /* Rotation transform */
4416 transMatUnrotated = transMat;
4417 if(font->orientation && !tategaki) {
4418 FT_Matrix rotationMat;
4420 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4421 pFT_Vector_Unit(&vecAngle, angle);
4422 rotationMat.xx = vecAngle.x;
4423 rotationMat.xy = -vecAngle.y;
4424 rotationMat.yx = -rotationMat.xy;
4425 rotationMat.yy = rotationMat.xx;
4427 pFT_Matrix_Multiply(&rotationMat, &transMat);
4428 needsTransform = TRUE;
4431 /* World transform */
4432 if (!is_identity_FMAT2(&font->font_desc.matrix))
4435 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4436 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4437 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4438 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4439 pFT_Matrix_Multiply(&worldMat, &transMat);
4440 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4441 needsTransform = TRUE;
4444 /* Extra transformation specified by caller */
4445 if (lpmat && !is_identity_MAT2(lpmat))
4448 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4449 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
4450 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
4451 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4452 pFT_Matrix_Multiply(&extraMat, &transMat);
4453 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4454 needsTransform = TRUE;
4457 if(!needsTransform) {
4458 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4459 bottom = (ft_face->glyph->metrics.horiBearingY -
4460 ft_face->glyph->metrics.height) & -64;
4461 lpgm->gmCellIncX = adv;
4462 lpgm->gmCellIncY = 0;
4466 for(xc = 0; xc < 2; xc++) {
4467 for(yc = 0; yc < 2; yc++) {
4468 vec.x = (ft_face->glyph->metrics.horiBearingX +
4469 xc * ft_face->glyph->metrics.width);
4470 vec.y = ft_face->glyph->metrics.horiBearingY -
4471 yc * ft_face->glyph->metrics.height;
4472 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4473 pFT_Vector_Transform(&vec, &transMat);
4474 if(xc == 0 && yc == 0) {
4475 left = right = vec.x;
4476 top = bottom = vec.y;
4478 if(vec.x < left) left = vec.x;
4479 else if(vec.x > right) right = vec.x;
4480 if(vec.y < bottom) bottom = vec.y;
4481 else if(vec.y > top) top = vec.y;
4486 right = (right + 63) & -64;
4487 bottom = bottom & -64;
4488 top = (top + 63) & -64;
4490 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4491 vec.x = ft_face->glyph->metrics.horiAdvance;
4493 pFT_Vector_Transform(&vec, &transMat);
4494 lpgm->gmCellIncX = (vec.x+63) >> 6;
4495 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4497 vec.x = ft_face->glyph->metrics.horiAdvance;
4499 pFT_Vector_Transform(&vec, &transMatUnrotated);
4500 adv = (vec.x+63) >> 6;
4502 lpgm->gmBlackBoxX = (right - left) >> 6;
4503 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4504 lpgm->gmptGlyphOrigin.x = left >> 6;
4505 lpgm->gmptGlyphOrigin.y = top >> 6;
4507 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4508 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4509 lpgm->gmCellIncX, lpgm->gmCellIncY);
4511 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4512 (!lpmat || is_identity_MAT2(lpmat))) /* don't cache custom transforms */
4514 FONT_GM(font,original_index)->gm = *lpgm;
4515 FONT_GM(font,original_index)->adv = adv;
4516 FONT_GM(font,original_index)->lsb = lsb;
4517 FONT_GM(font,original_index)->bbx = bbx;
4518 FONT_GM(font,original_index)->init = TRUE;
4521 if(format == GGO_METRICS)
4523 LeaveCriticalSection( &freetype_cs );
4524 return 1; /* FIXME */
4527 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
4528 TRACE("loaded a bitmap\n");
4529 LeaveCriticalSection( &freetype_cs );
4535 width = lpgm->gmBlackBoxX;
4536 height = lpgm->gmBlackBoxY;
4537 pitch = ((width + 31) >> 5) << 2;
4538 needed = pitch * height;
4540 if(!buf || !buflen) break;
4542 switch(ft_face->glyph->format) {
4543 case ft_glyph_format_bitmap:
4545 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4546 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4547 INT h = ft_face->glyph->bitmap.rows;
4549 memcpy(dst, src, w);
4550 src += ft_face->glyph->bitmap.pitch;
4556 case ft_glyph_format_outline:
4557 ft_bitmap.width = width;
4558 ft_bitmap.rows = height;
4559 ft_bitmap.pitch = pitch;
4560 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4561 ft_bitmap.buffer = buf;
4563 if(needsTransform) {
4564 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4567 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4569 /* Note: FreeType will only set 'black' bits for us. */
4570 memset(buf, 0, needed);
4571 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4575 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4576 LeaveCriticalSection( &freetype_cs );
4581 case GGO_GRAY2_BITMAP:
4582 case GGO_GRAY4_BITMAP:
4583 case GGO_GRAY8_BITMAP:
4584 case WINE_GGO_GRAY16_BITMAP:
4586 unsigned int mult, row, col;
4589 width = lpgm->gmBlackBoxX;
4590 height = lpgm->gmBlackBoxY;
4591 pitch = (width + 3) / 4 * 4;
4592 needed = pitch * height;
4594 if(!buf || !buflen) break;
4596 switch(ft_face->glyph->format) {
4597 case ft_glyph_format_bitmap:
4599 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4600 INT h = ft_face->glyph->bitmap.rows;
4603 for(x = 0; x < pitch; x++)
4605 if(x < ft_face->glyph->bitmap.width)
4606 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4610 src += ft_face->glyph->bitmap.pitch;
4613 LeaveCriticalSection( &freetype_cs );
4616 case ft_glyph_format_outline:
4618 ft_bitmap.width = width;
4619 ft_bitmap.rows = height;
4620 ft_bitmap.pitch = pitch;
4621 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4622 ft_bitmap.buffer = buf;
4625 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4627 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4629 memset(ft_bitmap.buffer, 0, buflen);
4631 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4633 if(format == GGO_GRAY2_BITMAP)
4635 else if(format == GGO_GRAY4_BITMAP)
4637 else if(format == GGO_GRAY8_BITMAP)
4639 else /* format == WINE_GGO_GRAY16_BITMAP */
4641 LeaveCriticalSection( &freetype_cs );
4647 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4648 LeaveCriticalSection( &freetype_cs );
4653 for(row = 0; row < height; row++) {
4655 for(col = 0; col < width; col++, ptr++) {
4656 *ptr = (((int)*ptr) * mult + 128) / 256;
4665 int contour, point = 0, first_pt;
4666 FT_Outline *outline = &ft_face->glyph->outline;
4667 TTPOLYGONHEADER *pph;
4669 DWORD pph_start, cpfx, type;
4671 if(buflen == 0) buf = NULL;
4673 if (needsTransform && buf) {
4674 pFT_Outline_Transform(outline, &transMat);
4677 for(contour = 0; contour < outline->n_contours; contour++) {
4679 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4682 pph->dwType = TT_POLYGON_TYPE;
4683 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4685 needed += sizeof(*pph);
4687 while(point <= outline->contours[contour]) {
4688 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4689 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4690 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4694 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4697 } while(point <= outline->contours[contour] &&
4698 (outline->tags[point] & FT_Curve_Tag_On) ==
4699 (outline->tags[point-1] & FT_Curve_Tag_On));
4700 /* At the end of a contour Windows adds the start point, but
4702 if(point > outline->contours[contour] &&
4703 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4705 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4707 } else if(point <= outline->contours[contour] &&
4708 outline->tags[point] & FT_Curve_Tag_On) {
4709 /* add closing pt for bezier */
4711 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4719 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4722 pph->cb = needed - pph_start;
4728 /* Convert the quadratic Beziers to cubic Beziers.
4729 The parametric eqn for a cubic Bezier is, from PLRM:
4730 r(t) = at^3 + bt^2 + ct + r0
4731 with the control points:
4736 A quadratic Beizer has the form:
4737 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4739 So equating powers of t leads to:
4740 r1 = 2/3 p1 + 1/3 p0
4741 r2 = 2/3 p1 + 1/3 p2
4742 and of course r0 = p0, r3 = p2
4745 int contour, point = 0, first_pt;
4746 FT_Outline *outline = &ft_face->glyph->outline;
4747 TTPOLYGONHEADER *pph;
4749 DWORD pph_start, cpfx, type;
4750 FT_Vector cubic_control[4];
4751 if(buflen == 0) buf = NULL;
4753 if (needsTransform && buf) {
4754 pFT_Outline_Transform(outline, &transMat);
4757 for(contour = 0; contour < outline->n_contours; contour++) {
4759 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4762 pph->dwType = TT_POLYGON_TYPE;
4763 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4765 needed += sizeof(*pph);
4767 while(point <= outline->contours[contour]) {
4768 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4769 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4770 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4773 if(type == TT_PRIM_LINE) {
4775 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4779 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4782 /* FIXME: Possible optimization in endpoint calculation
4783 if there are two consecutive curves */
4784 cubic_control[0] = outline->points[point-1];
4785 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4786 cubic_control[0].x += outline->points[point].x + 1;
4787 cubic_control[0].y += outline->points[point].y + 1;
4788 cubic_control[0].x >>= 1;
4789 cubic_control[0].y >>= 1;
4791 if(point+1 > outline->contours[contour])
4792 cubic_control[3] = outline->points[first_pt];
4794 cubic_control[3] = outline->points[point+1];
4795 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4796 cubic_control[3].x += outline->points[point].x + 1;
4797 cubic_control[3].y += outline->points[point].y + 1;
4798 cubic_control[3].x >>= 1;
4799 cubic_control[3].y >>= 1;
4802 /* r1 = 1/3 p0 + 2/3 p1
4803 r2 = 1/3 p2 + 2/3 p1 */
4804 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4805 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4806 cubic_control[2] = cubic_control[1];
4807 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4808 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4809 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4810 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4812 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4813 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4814 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4819 } while(point <= outline->contours[contour] &&
4820 (outline->tags[point] & FT_Curve_Tag_On) ==
4821 (outline->tags[point-1] & FT_Curve_Tag_On));
4822 /* At the end of a contour Windows adds the start point,
4823 but only for Beziers and we've already done that.
4825 if(point <= outline->contours[contour] &&
4826 outline->tags[point] & FT_Curve_Tag_On) {
4827 /* This is the closing pt of a bezier, but we've already
4828 added it, so just inc point and carry on */
4835 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4838 pph->cb = needed - pph_start;
4844 FIXME("Unsupported format %d\n", format);
4845 LeaveCriticalSection( &freetype_cs );
4848 LeaveCriticalSection( &freetype_cs );
4852 static BOOL get_bitmap_text_metrics(GdiFont *font)
4854 FT_Face ft_face = font->ft_face;
4855 #ifdef HAVE_FREETYPE_FTWINFNT_H
4856 FT_WinFNT_HeaderRec winfnt_header;
4858 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4859 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4860 font->potm->otmSize = size;
4862 #define TM font->potm->otmTextMetrics
4863 #ifdef HAVE_FREETYPE_FTWINFNT_H
4864 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4866 TM.tmHeight = winfnt_header.pixel_height;
4867 TM.tmAscent = winfnt_header.ascent;
4868 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4869 TM.tmInternalLeading = winfnt_header.internal_leading;
4870 TM.tmExternalLeading = winfnt_header.external_leading;
4871 TM.tmAveCharWidth = winfnt_header.avg_width;
4872 TM.tmMaxCharWidth = winfnt_header.max_width;
4873 TM.tmWeight = winfnt_header.weight;
4875 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4876 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4877 TM.tmFirstChar = winfnt_header.first_char;
4878 TM.tmLastChar = winfnt_header.last_char;
4879 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4880 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4881 TM.tmItalic = winfnt_header.italic;
4882 TM.tmUnderlined = font->underline;
4883 TM.tmStruckOut = font->strikeout;
4884 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4885 TM.tmCharSet = winfnt_header.charset;
4890 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4891 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4892 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4893 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4894 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4895 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4896 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4897 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4899 TM.tmDigitizedAspectX = 96; /* FIXME */
4900 TM.tmDigitizedAspectY = 96; /* FIXME */
4902 TM.tmLastChar = 255;
4903 TM.tmDefaultChar = 32;
4904 TM.tmBreakChar = 32;
4905 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4906 TM.tmUnderlined = font->underline;
4907 TM.tmStruckOut = font->strikeout;
4908 /* NB inverted meaning of TMPF_FIXED_PITCH */
4909 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4910 TM.tmCharSet = font->charset;
4918 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
4920 double scale_x, scale_y;
4924 scale_x = (double)font->aveWidth;
4925 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4928 scale_x = font->scale_y;
4930 scale_x *= fabs(font->font_desc.matrix.eM11);
4931 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
4933 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
4934 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
4936 SCALE_Y(ptm->tmHeight);
4937 SCALE_Y(ptm->tmAscent);
4938 SCALE_Y(ptm->tmDescent);
4939 SCALE_Y(ptm->tmInternalLeading);
4940 SCALE_Y(ptm->tmExternalLeading);
4941 SCALE_Y(ptm->tmOverhang);
4943 SCALE_X(ptm->tmAveCharWidth);
4944 SCALE_X(ptm->tmMaxCharWidth);
4950 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
4952 double scale_x, scale_y;
4956 scale_x = (double)font->aveWidth;
4957 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4960 scale_x = font->scale_y;
4962 scale_x *= fabs(font->font_desc.matrix.eM11);
4963 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
4965 scale_font_metrics(font, &potm->otmTextMetrics);
4967 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
4968 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
4970 SCALE_Y(potm->otmAscent);
4971 SCALE_Y(potm->otmDescent);
4972 SCALE_Y(potm->otmLineGap);
4973 SCALE_Y(potm->otmsCapEmHeight);
4974 SCALE_Y(potm->otmsXHeight);
4975 SCALE_Y(potm->otmrcFontBox.top);
4976 SCALE_Y(potm->otmrcFontBox.bottom);
4977 SCALE_X(potm->otmrcFontBox.left);
4978 SCALE_X(potm->otmrcFontBox.right);
4979 SCALE_Y(potm->otmMacAscent);
4980 SCALE_Y(potm->otmMacDescent);
4981 SCALE_Y(potm->otmMacLineGap);
4982 SCALE_X(potm->otmptSubscriptSize.x);
4983 SCALE_Y(potm->otmptSubscriptSize.y);
4984 SCALE_X(potm->otmptSubscriptOffset.x);
4985 SCALE_Y(potm->otmptSubscriptOffset.y);
4986 SCALE_X(potm->otmptSuperscriptSize.x);
4987 SCALE_Y(potm->otmptSuperscriptSize.y);
4988 SCALE_X(potm->otmptSuperscriptOffset.x);
4989 SCALE_Y(potm->otmptSuperscriptOffset.y);
4990 SCALE_Y(potm->otmsStrikeoutSize);
4991 SCALE_Y(potm->otmsStrikeoutPosition);
4992 SCALE_Y(potm->otmsUnderscoreSize);
4993 SCALE_Y(potm->otmsUnderscorePosition);
4999 /*************************************************************
5000 * WineEngGetTextMetrics
5003 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5005 EnterCriticalSection( &freetype_cs );
5007 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5008 if(!get_bitmap_text_metrics(font))
5010 LeaveCriticalSection( &freetype_cs );
5016 LeaveCriticalSection( &freetype_cs );
5019 *ptm = font->potm->otmTextMetrics;
5020 scale_font_metrics(font, ptm);
5021 LeaveCriticalSection( &freetype_cs );
5026 /*************************************************************
5027 * WineEngGetOutlineTextMetrics
5030 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5031 OUTLINETEXTMETRICW *potm)
5033 FT_Face ft_face = font->ft_face;
5034 UINT needed, lenfam, lensty, ret;
5036 TT_HoriHeader *pHori;
5037 TT_Postscript *pPost;
5038 FT_Fixed x_scale, y_scale;
5039 WCHAR *family_nameW, *style_nameW;
5040 static const WCHAR spaceW[] = {' ', '\0'};
5042 INT ascent, descent;
5044 TRACE("font=%p\n", font);
5046 if(!FT_IS_SCALABLE(ft_face))
5049 EnterCriticalSection( &freetype_cs );
5052 if(cbSize >= font->potm->otmSize)
5054 memcpy(potm, font->potm, font->potm->otmSize);
5055 scale_outline_font_metrics(font, potm);
5057 LeaveCriticalSection( &freetype_cs );
5058 return font->potm->otmSize;
5062 needed = sizeof(*potm);
5064 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5065 family_nameW = strdupW(font->name);
5067 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5069 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5070 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5071 style_nameW, lensty/sizeof(WCHAR));
5073 /* These names should be read from the TT name table */
5075 /* length of otmpFamilyName */
5078 /* length of otmpFaceName */
5079 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5080 needed += lenfam; /* just the family name */
5082 needed += lenfam + lensty; /* family + " " + style */
5085 /* length of otmpStyleName */
5088 /* length of otmpFullName */
5089 needed += lenfam + lensty;
5092 x_scale = ft_face->size->metrics.x_scale;
5093 y_scale = ft_face->size->metrics.y_scale;
5095 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5097 FIXME("Can't find OS/2 table - not TT font?\n");
5102 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5104 FIXME("Can't find HHEA table - not TT font?\n");
5109 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5111 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",
5112 pOS2->usWinAscent, pOS2->usWinDescent,
5113 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5114 ft_face->ascender, ft_face->descender, ft_face->height,
5115 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5116 ft_face->bbox.yMax, ft_face->bbox.yMin);
5118 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5119 font->potm->otmSize = needed;
5121 #define TM font->potm->otmTextMetrics
5123 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5124 ascent = pHori->Ascender;
5125 descent = -pHori->Descender;
5127 ascent = pOS2->usWinAscent;
5128 descent = pOS2->usWinDescent;
5132 TM.tmAscent = font->yMax;
5133 TM.tmDescent = -font->yMin;
5134 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5136 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5137 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5138 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5139 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5142 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5145 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5147 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5148 ((ascent + descent) -
5149 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5151 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5152 if (TM.tmAveCharWidth == 0) {
5153 TM.tmAveCharWidth = 1;
5155 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5156 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
5158 TM.tmDigitizedAspectX = 300;
5159 TM.tmDigitizedAspectY = 300;
5160 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5161 * symbol range to 0 - f0ff
5163 if (font->charset == SYMBOL_CHARSET)
5166 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
5170 TM.tmFirstChar = pOS2->usFirstCharIndex;
5171 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0xffff;
5173 TM.tmLastChar = pOS2->usLastCharIndex;
5174 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
5175 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5176 TM.tmUnderlined = font->underline;
5177 TM.tmStruckOut = font->strikeout;
5179 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5180 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5181 (pOS2->version == 0xFFFFU ||
5182 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5183 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5185 TM.tmPitchAndFamily = 0;
5187 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
5188 case PAN_FAMILY_SCRIPT:
5189 TM.tmPitchAndFamily |= FF_SCRIPT;
5191 case PAN_FAMILY_DECORATIVE:
5192 case PAN_FAMILY_PICTORIAL:
5193 TM.tmPitchAndFamily |= FF_DECORATIVE;
5195 case PAN_FAMILY_TEXT_DISPLAY:
5196 if(TM.tmPitchAndFamily == 0) /* fixed */
5197 TM.tmPitchAndFamily = FF_MODERN;
5199 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
5200 case PAN_SERIF_NORMAL_SANS:
5201 case PAN_SERIF_OBTUSE_SANS:
5202 case PAN_SERIF_PERP_SANS:
5203 TM.tmPitchAndFamily |= FF_SWISS;
5206 TM.tmPitchAndFamily |= FF_ROMAN;
5211 TM.tmPitchAndFamily |= FF_DONTCARE;
5214 if(FT_IS_SCALABLE(ft_face))
5215 TM.tmPitchAndFamily |= TMPF_VECTOR;
5217 if(FT_IS_SFNT(ft_face))
5219 if (font->ntmFlags & NTM_PS_OPENTYPE)
5220 TM.tmPitchAndFamily |= TMPF_DEVICE;
5222 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5225 TM.tmCharSet = font->charset;
5227 font->potm->otmFiller = 0;
5228 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5229 font->potm->otmfsSelection = pOS2->fsSelection;
5230 font->potm->otmfsType = pOS2->fsType;
5231 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5232 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5233 font->potm->otmItalicAngle = 0; /* POST table */
5234 font->potm->otmEMSquare = ft_face->units_per_EM;
5235 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5236 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5237 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5238 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5239 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5240 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5241 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5242 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5243 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5244 font->potm->otmMacAscent = TM.tmAscent;
5245 font->potm->otmMacDescent = -TM.tmDescent;
5246 font->potm->otmMacLineGap = font->potm->otmLineGap;
5247 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5248 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5249 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5250 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5251 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5252 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5253 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5254 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5255 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5256 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5257 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5259 font->potm->otmsUnderscoreSize = 0;
5260 font->potm->otmsUnderscorePosition = 0;
5262 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5263 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5267 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5268 cp = (char*)font->potm + sizeof(*font->potm);
5269 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5270 strcpyW((WCHAR*)cp, family_nameW);
5272 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5273 strcpyW((WCHAR*)cp, style_nameW);
5275 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5276 strcpyW((WCHAR*)cp, family_nameW);
5277 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5278 strcatW((WCHAR*)cp, spaceW);
5279 strcatW((WCHAR*)cp, style_nameW);
5280 cp += lenfam + lensty;
5283 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5284 strcpyW((WCHAR*)cp, family_nameW);
5285 strcatW((WCHAR*)cp, spaceW);
5286 strcatW((WCHAR*)cp, style_nameW);
5289 if(potm && needed <= cbSize)
5291 memcpy(potm, font->potm, font->potm->otmSize);
5292 scale_outline_font_metrics(font, potm);
5296 HeapFree(GetProcessHeap(), 0, style_nameW);
5297 HeapFree(GetProcessHeap(), 0, family_nameW);
5299 LeaveCriticalSection( &freetype_cs );
5303 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5305 HFONTLIST *hfontlist;
5306 child->font = alloc_font();
5307 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5308 if(!child->font->ft_face)
5310 free_font(child->font);
5315 child->font->ntmFlags = child->face->ntmFlags;
5316 child->font->orientation = font->orientation;
5317 child->font->scale_y = font->scale_y;
5318 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5319 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5320 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5321 child->font->base_font = font;
5322 list_add_head(&child_font_list, &child->font->entry);
5323 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5327 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5330 CHILD_FONT *child_font;
5333 font = font->base_font;
5335 *linked_font = font;
5337 if((*glyph = get_glyph_index(font, c)))
5340 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5342 if(!child_font->font)
5343 if(!load_child_font(font, child_font))
5346 if(!child_font->font->ft_face)
5348 g = get_glyph_index(child_font->font, c);
5352 *linked_font = child_font->font;
5359 /*************************************************************
5360 * WineEngGetCharWidth
5363 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5368 FT_UInt glyph_index;
5369 GdiFont *linked_font;
5371 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5373 EnterCriticalSection( &freetype_cs );
5374 for(c = firstChar; c <= lastChar; c++) {
5375 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5376 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5377 &gm, 0, NULL, NULL);
5378 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5380 LeaveCriticalSection( &freetype_cs );
5384 /*************************************************************
5385 * WineEngGetCharABCWidths
5388 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5393 FT_UInt glyph_index;
5394 GdiFont *linked_font;
5396 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5398 if(!FT_IS_SCALABLE(font->ft_face))
5401 EnterCriticalSection( &freetype_cs );
5403 for(c = firstChar; c <= lastChar; c++) {
5404 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5405 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5406 &gm, 0, NULL, NULL);
5407 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5408 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5409 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5410 FONT_GM(linked_font,glyph_index)->bbx;
5412 LeaveCriticalSection( &freetype_cs );
5416 /*************************************************************
5417 * WineEngGetCharABCWidthsI
5420 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5425 FT_UInt glyph_index;
5426 GdiFont *linked_font;
5428 if(!FT_HAS_HORIZONTAL(font->ft_face))
5431 EnterCriticalSection( &freetype_cs );
5433 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5435 for(c = firstChar; c < firstChar+count; c++) {
5436 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5437 &gm, 0, NULL, NULL);
5438 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5439 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5440 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5441 - FONT_GM(linked_font,c)->bbx;
5444 for(c = 0; c < count; c++) {
5445 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5446 &gm, 0, NULL, NULL);
5447 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5448 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5449 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5450 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5453 LeaveCriticalSection( &freetype_cs );
5457 /*************************************************************
5458 * WineEngGetTextExtentExPoint
5461 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5462 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5468 FT_UInt glyph_index;
5469 GdiFont *linked_font;
5471 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5474 EnterCriticalSection( &freetype_cs );
5477 WineEngGetTextMetrics(font, &tm);
5478 size->cy = tm.tmHeight;
5480 for(idx = 0; idx < count; idx++) {
5481 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5482 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5483 &gm, 0, NULL, NULL);
5484 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5486 if (! pnfit || ext <= max_ext) {
5496 LeaveCriticalSection( &freetype_cs );
5497 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5501 /*************************************************************
5502 * WineEngGetTextExtentExPointI
5505 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5506 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5513 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5515 EnterCriticalSection( &freetype_cs );
5518 WineEngGetTextMetrics(font, &tm);
5519 size->cy = tm.tmHeight;
5521 for(idx = 0; idx < count; idx++) {
5522 WineEngGetGlyphOutline(font, indices[idx],
5523 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
5525 size->cx += FONT_GM(font,indices[idx])->adv;
5527 if (! pnfit || ext <= max_ext) {
5537 LeaveCriticalSection( &freetype_cs );
5538 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5542 /*************************************************************
5543 * WineEngGetFontData
5546 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5549 FT_Face ft_face = font->ft_face;
5553 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5554 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
5555 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
5557 if(!FT_IS_SFNT(ft_face))
5565 if(table) { /* MS tags differ in endianness from FT ones */
5566 table = table >> 24 | table << 24 |
5567 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
5570 /* make sure value of len is the value freetype says it needs */
5573 FT_ULong needed = 0;
5574 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
5575 if( !err && needed < len) len = needed;
5577 err = load_sfnt_table(ft_face, table, offset, buf, &len);
5580 TRACE("Can't find table %c%c%c%c\n",
5581 /* bytes were reversed */
5582 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
5583 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
5589 /*************************************************************
5590 * WineEngGetTextFace
5593 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5595 INT n = strlenW(font->name) + 1;
5597 lstrcpynW(str, font->name, count);
5598 return min(count, n);
5603 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5605 if (fs) *fs = font->fs;
5606 return font->charset;
5609 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5611 GdiFont *font = dc->gdiFont, *linked_font;
5612 struct list *first_hfont;
5615 EnterCriticalSection( &freetype_cs );
5616 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
5617 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
5618 if(font == linked_font)
5619 *new_hfont = dc->hFont;
5622 first_hfont = list_head(&linked_font->hfontlist);
5623 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
5625 LeaveCriticalSection( &freetype_cs );
5629 /* Retrieve a list of supported Unicode ranges for a given font.
5630 * Can be called with NULL gs to calculate the buffer size. Returns
5631 * the number of ranges found.
5633 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
5635 DWORD num_ranges = 0;
5637 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5640 FT_ULong char_code, char_code_prev;
5643 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
5645 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5646 face->num_glyphs, glyph_code, char_code);
5648 if (!glyph_code) return 0;
5652 gs->ranges[0].wcLow = (USHORT)char_code;
5653 gs->ranges[0].cGlyphs = 0;
5654 gs->cGlyphsSupported = 0;
5660 if (char_code < char_code_prev)
5662 ERR("expected increasing char code from FT_Get_Next_Char\n");
5665 if (char_code - char_code_prev > 1)
5670 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5671 gs->ranges[num_ranges - 1].cGlyphs = 1;
5672 gs->cGlyphsSupported++;
5677 gs->ranges[num_ranges - 1].cGlyphs++;
5678 gs->cGlyphsSupported++;
5680 char_code_prev = char_code;
5681 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5685 FIXME("encoding %u not supported\n", face->charmap->encoding);
5690 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5693 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
5695 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5698 glyphset->cbThis = size;
5699 glyphset->cRanges = num_ranges;
5704 /*************************************************************
5707 BOOL WineEngFontIsLinked(GdiFont *font)
5710 EnterCriticalSection( &freetype_cs );
5711 ret = !list_empty(&font->child_fonts);
5712 LeaveCriticalSection( &freetype_cs );
5716 static BOOL is_hinting_enabled(void)
5718 /* Use the >= 2.2.0 function if available */
5719 if(pFT_Get_TrueType_Engine_Type)
5721 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
5722 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
5724 #ifdef FT_DRIVER_HAS_HINTER
5729 /* otherwise if we've been compiled with < 2.2.0 headers
5730 use the internal macro */
5731 mod = pFT_Get_Module(library, "truetype");
5732 if(mod && FT_DRIVER_HAS_HINTER(mod))
5740 /*************************************************************************
5741 * GetRasterizerCaps (GDI32.@)
5743 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5745 static int hinting = -1;
5749 hinting = is_hinting_enabled();
5750 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
5753 lprs->nSize = sizeof(RASTERIZER_STATUS);
5754 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
5755 lprs->nLanguageID = 0;
5759 /*************************************************************
5760 * WineEngRealizationInfo
5762 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
5764 FIXME("(%p, %p): stub!\n", font, info);
5767 if(FT_IS_SCALABLE(font->ft_face))
5770 info->cache_num = font->cache_num;
5771 info->unknown2 = -1;
5775 /*************************************************************************
5776 * Kerning support for TrueType fonts
5778 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5780 struct TT_kern_table
5786 struct TT_kern_subtable
5795 USHORT horizontal : 1;
5797 USHORT cross_stream: 1;
5798 USHORT override : 1;
5799 USHORT reserved1 : 4;
5805 struct TT_format0_kern_subtable
5809 USHORT entrySelector;
5820 static DWORD parse_format0_kern_subtable(GdiFont *font,
5821 const struct TT_format0_kern_subtable *tt_f0_ks,
5822 const USHORT *glyph_to_char,
5823 KERNINGPAIR *kern_pair, DWORD cPairs)
5826 const struct TT_kern_pair *tt_kern_pair;
5828 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
5830 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
5832 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5833 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
5834 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
5836 if (!kern_pair || !cPairs)
5839 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
5841 nPairs = min(nPairs, cPairs);
5843 for (i = 0; i < nPairs; i++)
5845 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
5846 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
5847 /* this algorithm appears to better match what Windows does */
5848 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
5849 if (kern_pair->iKernAmount < 0)
5851 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
5852 kern_pair->iKernAmount -= font->ppem;
5854 else if (kern_pair->iKernAmount > 0)
5856 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
5857 kern_pair->iKernAmount += font->ppem;
5859 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
5861 TRACE("left %u right %u value %d\n",
5862 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
5866 TRACE("copied %u entries\n", nPairs);
5870 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5874 const struct TT_kern_table *tt_kern_table;
5875 const struct TT_kern_subtable *tt_kern_subtable;
5877 USHORT *glyph_to_char;
5879 EnterCriticalSection( &freetype_cs );
5880 if (font->total_kern_pairs != (DWORD)-1)
5882 if (cPairs && kern_pair)
5884 cPairs = min(cPairs, font->total_kern_pairs);
5885 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5886 LeaveCriticalSection( &freetype_cs );
5889 LeaveCriticalSection( &freetype_cs );
5890 return font->total_kern_pairs;
5893 font->total_kern_pairs = 0;
5895 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5897 if (length == GDI_ERROR)
5899 TRACE("no kerning data in the font\n");
5900 LeaveCriticalSection( &freetype_cs );
5904 buf = HeapAlloc(GetProcessHeap(), 0, length);
5907 WARN("Out of memory\n");
5908 LeaveCriticalSection( &freetype_cs );
5912 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5914 /* build a glyph index to char code map */
5915 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5918 WARN("Out of memory allocating a glyph index to char code map\n");
5919 HeapFree(GetProcessHeap(), 0, buf);
5920 LeaveCriticalSection( &freetype_cs );
5924 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5930 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5932 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5933 font->ft_face->num_glyphs, glyph_code, char_code);
5937 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5939 /* FIXME: This doesn't match what Windows does: it does some fancy
5940 * things with duplicate glyph index to char code mappings, while
5941 * we just avoid overriding existing entries.
5943 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5944 glyph_to_char[glyph_code] = (USHORT)char_code;
5946 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5953 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5954 for (n = 0; n <= 65535; n++)
5955 glyph_to_char[n] = (USHORT)n;
5958 tt_kern_table = buf;
5959 nTables = GET_BE_WORD(tt_kern_table->nTables);
5960 TRACE("version %u, nTables %u\n",
5961 GET_BE_WORD(tt_kern_table->version), nTables);
5963 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5965 for (i = 0; i < nTables; i++)
5967 struct TT_kern_subtable tt_kern_subtable_copy;
5969 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5970 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5971 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5973 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5974 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
5975 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
5977 /* According to the TrueType specification this is the only format
5978 * that will be properly interpreted by Windows and OS/2
5980 if (tt_kern_subtable_copy.coverage.bits.format == 0)
5982 DWORD new_chunk, old_total = font->total_kern_pairs;
5984 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5985 glyph_to_char, NULL, 0);
5986 font->total_kern_pairs += new_chunk;
5988 if (!font->kern_pairs)
5989 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
5990 font->total_kern_pairs * sizeof(*font->kern_pairs));
5992 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
5993 font->total_kern_pairs * sizeof(*font->kern_pairs));
5995 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5996 glyph_to_char, font->kern_pairs + old_total, new_chunk);
5999 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6001 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6004 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6005 HeapFree(GetProcessHeap(), 0, buf);
6007 if (cPairs && kern_pair)
6009 cPairs = min(cPairs, font->total_kern_pairs);
6010 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6011 LeaveCriticalSection( &freetype_cs );
6014 LeaveCriticalSection( &freetype_cs );
6015 return font->total_kern_pairs;
6018 #else /* HAVE_FREETYPE */
6020 /*************************************************************************/
6022 BOOL WineEngInit(void)
6026 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6030 BOOL WineEngDestroyFontInstance(HFONT hfont)
6035 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6040 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6041 LPWORD pgi, DWORD flags)
6046 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6047 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6050 ERR("called but we don't have FreeType\n");
6054 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6056 ERR("called but we don't have FreeType\n");
6060 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6061 OUTLINETEXTMETRICW *potm)
6063 ERR("called but we don't have FreeType\n");
6067 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6070 ERR("called but we don't have FreeType\n");
6074 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6077 ERR("called but we don't have FreeType\n");
6081 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6084 ERR("called but we don't have FreeType\n");
6088 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6089 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6091 ERR("called but we don't have FreeType\n");
6095 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6096 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6098 ERR("called but we don't have FreeType\n");
6102 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6105 ERR("called but we don't have FreeType\n");
6109 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6111 ERR("called but we don't have FreeType\n");
6115 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6121 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6127 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6133 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6136 return DEFAULT_CHARSET;
6139 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6144 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6146 FIXME("(%p, %p): stub\n", font, glyphset);
6150 BOOL WineEngFontIsLinked(GdiFont *font)
6155 /*************************************************************************
6156 * GetRasterizerCaps (GDI32.@)
6158 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6160 lprs->nSize = sizeof(RASTERIZER_STATUS);
6162 lprs->nLanguageID = 0;
6166 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6168 ERR("called but we don't have FreeType\n");
6172 #endif /* HAVE_FREETYPE */