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 #ifdef FT_MULFIX_INLINED
167 #define pFT_MulFix FT_MULFIX_INLINED
169 MAKE_FUNCPTR(FT_MulFix);
171 MAKE_FUNCPTR(FT_New_Face);
172 MAKE_FUNCPTR(FT_New_Memory_Face);
173 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
174 MAKE_FUNCPTR(FT_Outline_Transform);
175 MAKE_FUNCPTR(FT_Outline_Translate);
176 MAKE_FUNCPTR(FT_Select_Charmap);
177 MAKE_FUNCPTR(FT_Set_Charmap);
178 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
179 MAKE_FUNCPTR(FT_Vector_Transform);
180 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
181 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
182 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
183 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
184 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
185 #ifdef HAVE_FREETYPE_FTWINFNT_H
186 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
189 #ifdef SONAME_LIBFONTCONFIG
190 #include <fontconfig/fontconfig.h>
191 MAKE_FUNCPTR(FcConfigGetCurrent);
192 MAKE_FUNCPTR(FcFontList);
193 MAKE_FUNCPTR(FcFontSetDestroy);
194 MAKE_FUNCPTR(FcInit);
195 MAKE_FUNCPTR(FcObjectSetAdd);
196 MAKE_FUNCPTR(FcObjectSetCreate);
197 MAKE_FUNCPTR(FcObjectSetDestroy);
198 MAKE_FUNCPTR(FcPatternCreate);
199 MAKE_FUNCPTR(FcPatternDestroy);
200 MAKE_FUNCPTR(FcPatternGetBool);
201 MAKE_FUNCPTR(FcPatternGetString);
207 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
208 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
209 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
212 #ifndef ft_encoding_none
213 #define FT_ENCODING_NONE ft_encoding_none
215 #ifndef ft_encoding_ms_symbol
216 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
218 #ifndef ft_encoding_unicode
219 #define FT_ENCODING_UNICODE ft_encoding_unicode
221 #ifndef ft_encoding_apple_roman
222 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
225 #ifdef WORDS_BIGENDIAN
226 #define GET_BE_WORD(x) (x)
228 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
231 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
238 FT_Short internal_leading;
241 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
242 So to let this compile on older versions of FreeType we'll define the
243 new structure here. */
245 FT_Short height, width;
246 FT_Pos size, x_ppem, y_ppem;
252 NEWTEXTMETRICEXW ntm;
256 typedef struct tagFace {
261 DWORD font_data_size;
264 FONTSIGNATURE fs_links;
266 FT_Fixed font_version;
268 Bitmap_Size size; /* set if face is a bitmap */
269 BOOL external; /* TRUE if we should manually add this font to the registry */
270 struct tagFamily *family;
271 /* Cached data for Enum */
272 struct enum_data *cached_enum_data;
275 typedef struct tagFamily {
277 const WCHAR *FamilyName;
283 INT adv; /* These three hold to widths of the unrotated chars */
301 typedef struct tagHFONTLIST {
316 struct list hfontlist;
317 OUTLINETEXTMETRICW *potm;
318 DWORD total_kern_pairs;
319 KERNINGPAIR *kern_pairs;
320 struct list child_fonts;
322 /* the following members can be accessed without locking, they are never modified after creation */
324 struct font_mapping *mapping;
347 const WCHAR *font_name;
351 #define GM_BLOCK_SIZE 128
352 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
354 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
355 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
356 #define UNUSED_CACHE_SIZE 10
357 static struct list child_font_list = LIST_INIT(child_font_list);
358 static struct list system_links = LIST_INIT(system_links);
360 static struct list font_subst_list = LIST_INIT(font_subst_list);
362 static struct list font_list = LIST_INIT(font_list);
364 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
365 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
366 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
368 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
369 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
370 'W','i','n','d','o','w','s','\\',
371 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
372 'F','o','n','t','s','\0'};
374 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
375 'W','i','n','d','o','w','s',' ','N','T','\\',
376 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
377 'F','o','n','t','s','\0'};
379 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
380 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
381 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
382 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
384 static const WCHAR * const SystemFontValues[4] = {
391 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
392 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
394 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
395 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
396 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
397 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
398 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
399 'E','u','r','o','p','e','a','n','\0'};
400 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
401 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
402 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
403 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
404 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
405 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
406 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
407 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
408 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
409 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
410 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
411 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
413 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
423 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
431 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
440 typedef struct tagFontSubst {
456 static struct list mappings_list = LIST_INIT( mappings_list );
458 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
460 static CRITICAL_SECTION freetype_cs;
461 static CRITICAL_SECTION_DEBUG critsect_debug =
464 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
465 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
467 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
469 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
471 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
472 static BOOL use_default_fallback = FALSE;
474 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
476 /****************************************
477 * Notes on .fon files
479 * The fonts System, FixedSys and Terminal are special. There are typically multiple
480 * versions installed for different resolutions and codepages. Windows stores which one to use
481 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
483 * FIXEDFON.FON FixedSys
485 * OEMFONT.FON Terminal
486 * LogPixels Current dpi set by the display control panel applet
487 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
488 * also has a LogPixels value that appears to mirror this)
490 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
491 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
492 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
493 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
494 * so that makes sense.
496 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
497 * to be mapped into the registry on Windows 2000 at least).
500 * ega80woa.fon=ega80850.fon
501 * ega40woa.fon=ega40850.fon
502 * cga80woa.fon=cga80850.fon
503 * cga40woa.fon=cga40850.fon
506 /* These are all structures needed for the GSUB table */
508 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
509 #define TATEGAKI_LOWER_BOUND 0x02F1
525 GSUB_ScriptRecord ScriptRecord[1];
531 } GSUB_LangSysRecord;
536 GSUB_LangSysRecord LangSysRecord[1];
540 WORD LookupOrder; /* Reserved */
541 WORD ReqFeatureIndex;
543 WORD FeatureIndex[1];
549 } GSUB_FeatureRecord;
553 GSUB_FeatureRecord FeatureRecord[1];
557 WORD FeatureParams; /* Reserved */
559 WORD LookupListIndex[1];
578 } GSUB_CoverageFormat1;
583 WORD StartCoverageIndex;
589 GSUB_RangeRecord RangeRecord[1];
590 } GSUB_CoverageFormat2;
593 WORD SubstFormat; /* = 1 */
596 } GSUB_SingleSubstFormat1;
599 WORD SubstFormat; /* = 2 */
603 }GSUB_SingleSubstFormat2;
605 #ifdef HAVE_CARBON_CARBON_H
606 static char *find_cache_dir(void)
610 static char cached_path[MAX_PATH];
611 static const char *wine = "/Wine", *fonts = "/Fonts";
613 if(*cached_path) return cached_path;
615 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
618 WARN("can't create cached data folder\n");
621 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
624 WARN("can't create cached data path\n");
628 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
630 ERR("Could not create full path\n");
634 strcat(cached_path, wine);
636 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
638 WARN("Couldn't mkdir %s\n", cached_path);
642 strcat(cached_path, fonts);
643 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
645 WARN("Couldn't mkdir %s\n", cached_path);
652 /******************************************************************
655 * Extracts individual TrueType font files from a Mac suitcase font
656 * and saves them into the user's caches directory (see
658 * Returns a NULL terminated array of filenames.
660 * We do this because they are apps that try to read ttf files
661 * themselves and they don't like Mac suitcase files.
663 static char **expand_mac_font(const char *path)
670 const char *filename;
674 unsigned int size, max_size;
677 TRACE("path %s\n", path);
679 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
682 WARN("failed to get ref\n");
686 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
689 TRACE("no data fork, so trying resource fork\n");
690 res_ref = FSOpenResFile(&ref, fsRdPerm);
693 TRACE("unable to open resource fork\n");
700 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
703 CloseResFile(res_ref);
707 out_dir = find_cache_dir();
709 filename = strrchr(path, '/');
710 if(!filename) filename = path;
713 /* output filename has the form out_dir/filename_%04x.ttf */
714 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
721 unsigned short *num_faces_ptr, num_faces, face;
724 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
726 fond = Get1IndResource(fond_res, idx);
728 TRACE("got fond resource %d\n", idx);
731 fam_rec = *(FamRec**)fond;
732 num_faces_ptr = (unsigned short *)(fam_rec + 1);
733 num_faces = GET_BE_WORD(*num_faces_ptr);
735 assoc = (AsscEntry*)(num_faces_ptr + 1);
736 TRACE("num faces %04x\n", num_faces);
737 for(face = 0; face < num_faces; face++, assoc++)
740 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
741 unsigned short size, font_id;
744 size = GET_BE_WORD(assoc->fontSize);
745 font_id = GET_BE_WORD(assoc->fontID);
748 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
752 TRACE("trying to load sfnt id %04x\n", font_id);
753 sfnt = GetResource(sfnt_res, font_id);
756 TRACE("can't get sfnt resource %04x\n", font_id);
760 output = HeapAlloc(GetProcessHeap(), 0, output_len);
765 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
767 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
768 if(fd != -1 || errno == EEXIST)
772 unsigned char *sfnt_data;
775 sfnt_data = *(unsigned char**)sfnt;
776 write(fd, sfnt_data, GetHandleSize(sfnt));
780 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
783 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
785 ret.array[ret.size++] = output;
789 WARN("unable to create %s\n", output);
790 HeapFree(GetProcessHeap(), 0, output);
793 ReleaseResource(sfnt);
796 ReleaseResource(fond);
799 CloseResFile(res_ref);
804 #endif /* HAVE_CARBON_CARBON_H */
806 static inline BOOL is_win9x(void)
808 return GetVersion() & 0x80000000;
811 This function builds an FT_Fixed from a double. It fails if the absolute
812 value of the float number is greater than 32768.
814 static inline FT_Fixed FT_FixedFromFloat(double f)
820 This function builds an FT_Fixed from a FIXED. It simply put f.value
821 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
823 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
825 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
829 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
834 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
835 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
837 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
838 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
840 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
842 if(face_name && strcmpiW(face_name, family->FamilyName))
844 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
848 file = strrchr(face->file, '/');
853 if(!strcasecmp(file, file_nameA))
855 HeapFree(GetProcessHeap(), 0, file_nameA);
860 HeapFree(GetProcessHeap(), 0, file_nameA);
864 static Family *find_family_from_name(const WCHAR *name)
868 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
870 if(!strcmpiW(family->FamilyName, name))
877 static void DumpSubstList(void)
881 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
883 if(psub->from.charset != -1 || psub->to.charset != -1)
884 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
885 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
887 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
888 debugstr_w(psub->to.name));
893 static LPWSTR strdupW(LPCWSTR p)
896 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
897 ret = HeapAlloc(GetProcessHeap(), 0, len);
902 static LPSTR strdupA(LPCSTR p)
905 DWORD len = (strlen(p) + 1);
906 ret = HeapAlloc(GetProcessHeap(), 0, len);
911 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
916 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
918 if(!strcmpiW(element->from.name, from_name) &&
919 (element->from.charset == from_charset ||
920 element->from.charset == -1))
927 #define ADD_FONT_SUBST_FORCE 1
929 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
931 FontSubst *from_exist, *to_exist;
933 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
935 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
937 list_remove(&from_exist->entry);
938 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
939 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
940 HeapFree(GetProcessHeap(), 0, from_exist);
946 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
950 HeapFree(GetProcessHeap(), 0, subst->to.name);
951 subst->to.name = strdupW(to_exist->to.name);
954 list_add_tail(subst_list, &subst->entry);
959 HeapFree(GetProcessHeap(), 0, subst->from.name);
960 HeapFree(GetProcessHeap(), 0, subst->to.name);
961 HeapFree(GetProcessHeap(), 0, subst);
965 static void split_subst_info(NameCs *nc, LPSTR str)
967 CHAR *p = strrchr(str, ',');
972 nc->charset = strtol(p+1, NULL, 10);
975 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
976 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
977 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
980 static void LoadSubstList(void)
984 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
988 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
989 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
990 &hkey) == ERROR_SUCCESS) {
992 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
993 &valuelen, &datalen, NULL, NULL);
995 valuelen++; /* returned value doesn't include room for '\0' */
996 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
997 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1001 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1002 &dlen) == ERROR_SUCCESS) {
1003 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1005 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1006 split_subst_info(&psub->from, value);
1007 split_subst_info(&psub->to, data);
1009 /* Win 2000 doesn't allow mapping between different charsets
1010 or mapping of DEFAULT_CHARSET */
1011 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1012 psub->to.charset == DEFAULT_CHARSET) {
1013 HeapFree(GetProcessHeap(), 0, psub->to.name);
1014 HeapFree(GetProcessHeap(), 0, psub->from.name);
1015 HeapFree(GetProcessHeap(), 0, psub);
1017 add_font_subst(&font_subst_list, psub, 0);
1019 /* reset dlen and vlen */
1023 HeapFree(GetProcessHeap(), 0, data);
1024 HeapFree(GetProcessHeap(), 0, value);
1029 static WCHAR *get_familyname(FT_Face ft_face)
1031 WCHAR *family = NULL;
1033 FT_UInt num_names, name_index, i;
1035 if(FT_IS_SFNT(ft_face))
1037 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1039 for(name_index = 0; name_index < num_names; name_index++)
1041 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1043 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
1044 (name.language_id == GetUserDefaultLCID()) &&
1045 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
1046 (name.encoding_id == TT_MS_ID_UNICODE_CS))
1048 /* String is not nul terminated and string_len is a byte length. */
1049 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1050 for(i = 0; i < name.string_len / 2; i++)
1052 WORD *tmp = (WORD *)&name.string[i * 2];
1053 family[i] = GET_BE_WORD(*tmp);
1057 TRACE("Got localised name %s\n", debugstr_w(family));
1068 /*****************************************************************
1071 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1072 * of FreeType that don't export this function.
1075 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1080 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1081 if(pFT_Load_Sfnt_Table)
1083 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1085 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1086 else /* Do it the hard way */
1088 TT_Face tt_face = (TT_Face) ft_face;
1089 SFNT_Interface *sfnt;
1090 if (FT_Version.major==2 && FT_Version.minor==0)
1093 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1097 /* A field was added in the middle of the structure in 2.1.x */
1098 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1100 err = sfnt->load_any(tt_face, table, offset, buf, len);
1108 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1109 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1110 "Please upgrade your freetype library.\n");
1113 err = FT_Err_Unimplemented_Feature;
1119 static inline int TestStyles(DWORD flags, DWORD styles)
1121 return (flags & styles) == styles;
1124 static int StyleOrdering(Face *face)
1126 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1128 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1130 if (TestStyles(face->ntmFlags, NTM_BOLD))
1132 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1135 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1136 debugstr_w(face->family->FamilyName),
1137 debugstr_w(face->StyleName),
1143 /* Add a style of face to a font family using an ordering of the list such
1144 that regular fonts come before bold and italic, and single styles come
1145 before compound styles. */
1146 static void AddFaceToFamily(Face *face, Family *family)
1150 LIST_FOR_EACH( entry, &family->faces )
1152 Face *ent = LIST_ENTRY(entry, Face, entry);
1153 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1155 list_add_before( entry, &face->entry );
1158 #define ADDFONT_EXTERNAL_FONT 0x01
1159 #define ADDFONT_FORCE_BITMAP 0x02
1160 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1164 TT_Header *pHeader = NULL;
1165 WCHAR *english_family, *localised_family, *StyleW;
1169 struct list *family_elem_ptr, *face_elem_ptr;
1171 FT_Long face_index = 0, num_faces;
1172 #ifdef HAVE_FREETYPE_FTWINFNT_H
1173 FT_WinFNT_HeaderRec winfnt_header;
1175 int i, bitmap_num, internal_leading;
1178 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1179 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1181 #ifdef HAVE_CARBON_CARBON_H
1182 if(file && !fake_family)
1184 char **mac_list = expand_mac_font(file);
1187 BOOL had_one = FALSE;
1189 for(cursor = mac_list; *cursor; cursor++)
1192 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1193 HeapFree(GetProcessHeap(), 0, *cursor);
1195 HeapFree(GetProcessHeap(), 0, mac_list);
1200 #endif /* HAVE_CARBON_CARBON_H */
1203 char *family_name = fake_family;
1207 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1208 err = pFT_New_Face(library, file, face_index, &ft_face);
1211 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1212 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1216 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1220 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*/
1221 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1222 pFT_Done_Face(ft_face);
1226 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1227 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1228 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1229 pFT_Done_Face(ft_face);
1233 if(FT_IS_SFNT(ft_face))
1235 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1236 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1237 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1239 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1240 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1241 pFT_Done_Face(ft_face);
1245 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1246 we don't want to load these. */
1247 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1251 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1253 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1254 pFT_Done_Face(ft_face);
1260 if(!ft_face->family_name || !ft_face->style_name) {
1261 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1262 pFT_Done_Face(ft_face);
1266 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1268 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1269 pFT_Done_Face(ft_face);
1275 localised_family = get_familyname(ft_face);
1276 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1278 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1279 HeapFree(GetProcessHeap(), 0, localised_family);
1280 num_faces = ft_face->num_faces;
1281 pFT_Done_Face(ft_face);
1284 HeapFree(GetProcessHeap(), 0, localised_family);
1288 family_name = ft_face->family_name;
1292 My_FT_Bitmap_Size *size = NULL;
1295 if(!FT_IS_SCALABLE(ft_face))
1296 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1298 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1299 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1300 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1302 localised_family = NULL;
1304 localised_family = get_familyname(ft_face);
1305 if(localised_family && !strcmpW(localised_family, english_family)) {
1306 HeapFree(GetProcessHeap(), 0, localised_family);
1307 localised_family = NULL;
1312 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1313 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1314 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1319 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1320 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1321 list_init(&family->faces);
1322 list_add_tail(&font_list, &family->entry);
1324 if(localised_family) {
1325 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1326 subst->from.name = strdupW(english_family);
1327 subst->from.charset = -1;
1328 subst->to.name = strdupW(localised_family);
1329 subst->to.charset = -1;
1330 add_font_subst(&font_subst_list, subst, 0);
1333 HeapFree(GetProcessHeap(), 0, localised_family);
1334 HeapFree(GetProcessHeap(), 0, english_family);
1336 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1337 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1338 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1340 internal_leading = 0;
1341 memset(&fs, 0, sizeof(fs));
1343 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1345 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1346 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1347 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1348 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1349 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1350 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1351 if(pOS2->version == 0) {
1354 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1355 fs.fsCsb[0] |= FS_LATIN1;
1357 fs.fsCsb[0] |= FS_SYMBOL;
1360 #ifdef HAVE_FREETYPE_FTWINFNT_H
1361 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1363 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1364 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1365 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1367 internal_leading = winfnt_header.internal_leading;
1371 face_elem_ptr = list_head(&family->faces);
1372 while(face_elem_ptr) {
1373 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1374 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1375 if(!strcmpW(face->StyleName, StyleW) &&
1376 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1377 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1378 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1379 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1382 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1383 HeapFree(GetProcessHeap(), 0, StyleW);
1384 pFT_Done_Face(ft_face);
1387 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1388 TRACE("Original font is newer so skipping this one\n");
1389 HeapFree(GetProcessHeap(), 0, StyleW);
1390 pFT_Done_Face(ft_face);
1393 TRACE("Replacing original with this one\n");
1394 list_remove(&face->entry);
1395 HeapFree(GetProcessHeap(), 0, face->file);
1396 HeapFree(GetProcessHeap(), 0, face->StyleName);
1397 HeapFree(GetProcessHeap(), 0, face);
1402 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1403 face->cached_enum_data = NULL;
1404 face->StyleName = StyleW;
1407 face->file = strdupA(file);
1408 face->font_data_ptr = NULL;
1409 face->font_data_size = 0;
1414 face->font_data_ptr = font_data_ptr;
1415 face->font_data_size = font_data_size;
1417 face->face_index = face_index;
1419 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1420 face->ntmFlags |= NTM_ITALIC;
1421 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1422 face->ntmFlags |= NTM_BOLD;
1423 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1424 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1425 face->family = family;
1426 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1428 memset(&face->fs_links, 0, sizeof(face->fs_links));
1430 if(FT_IS_SCALABLE(ft_face)) {
1431 memset(&face->size, 0, sizeof(face->size));
1432 face->scalable = TRUE;
1434 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1435 size->height, size->width, size->size >> 6,
1436 size->x_ppem >> 6, size->y_ppem >> 6);
1437 face->size.height = size->height;
1438 face->size.width = size->width;
1439 face->size.size = size->size;
1440 face->size.x_ppem = size->x_ppem;
1441 face->size.y_ppem = size->y_ppem;
1442 face->size.internal_leading = internal_leading;
1443 face->scalable = FALSE;
1446 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1448 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1450 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1451 face->ntmFlags |= NTM_PS_OPENTYPE;
1454 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1455 face->fs.fsCsb[0], face->fs.fsCsb[1],
1456 face->fs.fsUsb[0], face->fs.fsUsb[1],
1457 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1460 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1461 for(i = 0; i < ft_face->num_charmaps; i++) {
1462 switch(ft_face->charmaps[i]->encoding) {
1463 case FT_ENCODING_UNICODE:
1464 case FT_ENCODING_APPLE_ROMAN:
1465 face->fs.fsCsb[0] |= FS_LATIN1;
1467 case FT_ENCODING_MS_SYMBOL:
1468 face->fs.fsCsb[0] |= FS_SYMBOL;
1476 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1477 have_installed_roman_font = TRUE;
1479 AddFaceToFamily(face, family);
1481 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1483 num_faces = ft_face->num_faces;
1484 pFT_Done_Face(ft_face);
1485 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1486 debugstr_w(StyleW));
1487 } while(num_faces > ++face_index);
1491 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1493 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1496 static void DumpFontList(void)
1500 struct list *family_elem_ptr, *face_elem_ptr;
1502 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1503 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1504 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1505 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1506 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1507 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1509 TRACE(" %d", face->size.height);
1516 /***********************************************************
1517 * The replacement list is a way to map an entire font
1518 * family onto another family. For example adding
1520 * [HKCU\Software\Wine\Fonts\Replacements]
1521 * "Wingdings"="Winedings"
1523 * would enumerate the Winedings font both as Winedings and
1524 * Wingdings. However if a real Wingdings font is present the
1525 * replacement does not take place.
1528 static void LoadReplaceList(void)
1531 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1536 struct list *family_elem_ptr, *face_elem_ptr;
1539 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1540 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1542 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1543 &valuelen, &datalen, NULL, NULL);
1545 valuelen++; /* returned value doesn't include room for '\0' */
1546 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1547 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1551 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1552 &dlen) == ERROR_SUCCESS) {
1553 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1554 /* "NewName"="Oldname" */
1555 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1557 /* Find the old family and hence all of the font files
1559 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1560 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1561 if(!strcmpiW(family->FamilyName, data)) {
1562 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1563 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1564 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1565 debugstr_w(face->StyleName), familyA);
1566 /* Now add a new entry with the new family name */
1567 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1572 /* reset dlen and vlen */
1576 HeapFree(GetProcessHeap(), 0, data);
1577 HeapFree(GetProcessHeap(), 0, value);
1582 /*************************************************************
1585 static BOOL init_system_links(void)
1587 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1588 'W','i','n','d','o','w','s',' ','N','T','\\',
1589 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1590 'S','y','s','t','e','m','L','i','n','k',0};
1593 DWORD type, max_val, max_data, val_len, data_len, index;
1594 WCHAR *value, *data;
1595 WCHAR *entry, *next;
1596 SYSTEM_LINKS *font_link, *system_font_link;
1597 CHILD_FONT *child_font;
1598 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1599 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1600 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1606 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1608 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1609 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1610 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1611 val_len = max_val + 1;
1612 data_len = max_data;
1614 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1616 TRACE("%s:\n", debugstr_w(value));
1618 memset(&fs, 0, sizeof(fs));
1619 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1620 psub = get_font_subst(&font_subst_list, value, -1);
1621 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1622 list_init(&font_link->links);
1623 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1626 CHILD_FONT *child_font;
1628 TRACE("\t%s\n", debugstr_w(entry));
1630 next = entry + strlenW(entry) + 1;
1632 face_name = strchrW(entry, ',');
1636 while(isspaceW(*face_name))
1639 psub = get_font_subst(&font_subst_list, face_name, -1);
1641 face_name = psub->to.name;
1643 face = find_face_from_filename(entry, face_name);
1646 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1650 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1651 child_font->face = face;
1652 child_font->font = NULL;
1653 fs.fsCsb[0] |= face->fs.fsCsb[0];
1654 fs.fsCsb[1] |= face->fs.fsCsb[1];
1655 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1656 list_add_tail(&font_link->links, &child_font->entry);
1658 family = find_family_from_name(font_link->font_name);
1661 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1663 face->fs_links = fs;
1666 list_add_tail(&system_links, &font_link->entry);
1667 val_len = max_val + 1;
1668 data_len = max_data;
1671 HeapFree(GetProcessHeap(), 0, value);
1672 HeapFree(GetProcessHeap(), 0, data);
1676 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1679 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1680 system_font_link->font_name = strdupW(System);
1681 list_init(&system_font_link->links);
1683 face = find_face_from_filename(tahoma_ttf, Tahoma);
1686 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1687 child_font->face = face;
1688 child_font->font = NULL;
1689 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1690 list_add_tail(&system_font_link->links, &child_font->entry);
1692 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1694 if(!strcmpiW(font_link->font_name, Tahoma))
1696 CHILD_FONT *font_link_entry;
1697 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1699 CHILD_FONT *new_child;
1700 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1701 new_child->face = font_link_entry->face;
1702 new_child->font = NULL;
1703 list_add_tail(&system_font_link->links, &new_child->entry);
1708 list_add_tail(&system_links, &system_font_link->entry);
1712 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1715 struct dirent *dent;
1716 char path[MAX_PATH];
1718 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1720 dir = opendir(dirname);
1722 WARN("Can't open directory %s\n", debugstr_a(dirname));
1725 while((dent = readdir(dir)) != NULL) {
1726 struct stat statbuf;
1728 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1731 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1733 sprintf(path, "%s/%s", dirname, dent->d_name);
1735 if(stat(path, &statbuf) == -1)
1737 WARN("Can't stat %s\n", debugstr_a(path));
1740 if(S_ISDIR(statbuf.st_mode))
1741 ReadFontDir(path, external_fonts);
1743 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1749 static void load_fontconfig_fonts(void)
1751 #ifdef SONAME_LIBFONTCONFIG
1752 void *fc_handle = NULL;
1761 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1763 TRACE("Wine cannot find the fontconfig library (%s).\n",
1764 SONAME_LIBFONTCONFIG);
1767 #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;}
1768 LOAD_FUNCPTR(FcConfigGetCurrent);
1769 LOAD_FUNCPTR(FcFontList);
1770 LOAD_FUNCPTR(FcFontSetDestroy);
1771 LOAD_FUNCPTR(FcInit);
1772 LOAD_FUNCPTR(FcObjectSetAdd);
1773 LOAD_FUNCPTR(FcObjectSetCreate);
1774 LOAD_FUNCPTR(FcObjectSetDestroy);
1775 LOAD_FUNCPTR(FcPatternCreate);
1776 LOAD_FUNCPTR(FcPatternDestroy);
1777 LOAD_FUNCPTR(FcPatternGetBool);
1778 LOAD_FUNCPTR(FcPatternGetString);
1781 if(!pFcInit()) return;
1783 config = pFcConfigGetCurrent();
1784 pat = pFcPatternCreate();
1785 os = pFcObjectSetCreate();
1786 pFcObjectSetAdd(os, FC_FILE);
1787 pFcObjectSetAdd(os, FC_SCALABLE);
1788 fontset = pFcFontList(config, pat, os);
1789 if(!fontset) return;
1790 for(i = 0; i < fontset->nfont; i++) {
1793 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1795 TRACE("fontconfig: %s\n", file);
1797 /* We're just interested in OT/TT fonts for now, so this hack just
1798 picks up the scalable fonts without extensions .pf[ab] to save time
1799 loading every other font */
1801 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1803 TRACE("not scalable\n");
1807 len = strlen( file );
1808 if(len < 4) continue;
1809 ext = &file[ len - 3 ];
1810 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1811 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1813 pFcFontSetDestroy(fontset);
1814 pFcObjectSetDestroy(os);
1815 pFcPatternDestroy(pat);
1821 static BOOL load_font_from_data_dir(LPCWSTR file)
1824 const char *data_dir = wine_get_data_dir();
1826 if (!data_dir) data_dir = wine_get_build_dir();
1833 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1835 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1837 strcpy(unix_name, data_dir);
1838 strcat(unix_name, "/fonts/");
1840 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1842 EnterCriticalSection( &freetype_cs );
1843 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1844 LeaveCriticalSection( &freetype_cs );
1845 HeapFree(GetProcessHeap(), 0, unix_name);
1850 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1852 static const WCHAR slashW[] = {'\\','\0'};
1854 WCHAR windowsdir[MAX_PATH];
1857 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1858 strcatW(windowsdir, fontsW);
1859 strcatW(windowsdir, slashW);
1860 strcatW(windowsdir, file);
1861 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1862 EnterCriticalSection( &freetype_cs );
1863 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1864 LeaveCriticalSection( &freetype_cs );
1865 HeapFree(GetProcessHeap(), 0, unixname);
1870 static void load_system_fonts(void)
1873 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1874 const WCHAR * const *value;
1876 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1879 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1880 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1881 strcatW(windowsdir, fontsW);
1882 for(value = SystemFontValues; *value; value++) {
1883 dlen = sizeof(data);
1884 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1888 sprintfW(pathW, fmtW, windowsdir, data);
1889 if((unixname = wine_get_unix_file_name(pathW))) {
1890 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1891 HeapFree(GetProcessHeap(), 0, unixname);
1894 load_font_from_data_dir(data);
1901 /*************************************************************
1903 * This adds registry entries for any externally loaded fonts
1904 * (fonts from fontconfig or FontDirs). It also deletes entries
1905 * of no longer existing fonts.
1908 static void update_reg_entries(void)
1910 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1915 struct list *family_elem_ptr, *face_elem_ptr;
1917 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1918 static const WCHAR spaceW[] = {' ', '\0'};
1921 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1922 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1923 ERR("Can't create Windows font reg key\n");
1927 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1928 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1929 ERR("Can't create Windows font reg key\n");
1933 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1934 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1935 ERR("Can't create external font reg key\n");
1939 /* enumerate the fonts and add external ones to the two keys */
1941 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1942 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1943 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1944 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1945 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1946 if(!face->external) continue;
1948 if (!(face->ntmFlags & NTM_REGULAR))
1949 len = len_fam + strlenW(face->StyleName) + 1;
1950 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1951 strcpyW(valueW, family->FamilyName);
1952 if(len != len_fam) {
1953 strcatW(valueW, spaceW);
1954 strcatW(valueW, face->StyleName);
1956 strcatW(valueW, TrueType);
1958 file = wine_get_dos_file_name(face->file);
1960 len = strlenW(file) + 1;
1963 if((path = strrchr(face->file, '/')) == NULL)
1967 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1969 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1970 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1972 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1973 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1974 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1976 HeapFree(GetProcessHeap(), 0, file);
1977 HeapFree(GetProcessHeap(), 0, valueW);
1981 if(external_key) RegCloseKey(external_key);
1982 if(win9x_key) RegCloseKey(win9x_key);
1983 if(winnt_key) RegCloseKey(winnt_key);
1987 static void delete_external_font_keys(void)
1989 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1990 DWORD dlen, vlen, datalen, valuelen, i, type;
1994 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1995 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1996 ERR("Can't create Windows font reg key\n");
2000 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2001 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2002 ERR("Can't create Windows font reg key\n");
2006 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2007 ERR("Can't create external font reg key\n");
2011 /* Delete all external fonts added last time */
2013 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2014 &valuelen, &datalen, NULL, NULL);
2015 valuelen++; /* returned value doesn't include room for '\0' */
2016 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2017 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2019 dlen = datalen * sizeof(WCHAR);
2022 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2023 &dlen) == ERROR_SUCCESS) {
2025 RegDeleteValueW(winnt_key, valueW);
2026 RegDeleteValueW(win9x_key, valueW);
2027 /* reset dlen and vlen */
2031 HeapFree(GetProcessHeap(), 0, data);
2032 HeapFree(GetProcessHeap(), 0, valueW);
2034 /* Delete the old external fonts key */
2035 RegCloseKey(external_key);
2036 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2039 if(win9x_key) RegCloseKey(win9x_key);
2040 if(winnt_key) RegCloseKey(winnt_key);
2043 /*************************************************************
2044 * WineEngAddFontResourceEx
2047 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2050 if (ft_handle) /* do it only if we have freetype up and running */
2055 FIXME("Ignoring flags %x\n", flags);
2057 if((unixname = wine_get_unix_file_name(file)))
2059 EnterCriticalSection( &freetype_cs );
2060 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2061 LeaveCriticalSection( &freetype_cs );
2062 HeapFree(GetProcessHeap(), 0, unixname);
2064 if (!ret && !strchrW(file, '\\')) {
2065 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2066 ret = load_font_from_winfonts_dir(file);
2068 /* Try in datadir/fonts (or builddir/fonts),
2069 * needed for Magic the Gathering Online
2071 ret = load_font_from_data_dir(file);
2078 /*************************************************************
2079 * WineEngAddFontMemResourceEx
2082 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2084 if (ft_handle) /* do it only if we have freetype up and running */
2086 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2088 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2089 memcpy(pFontCopy, pbFont, cbFont);
2091 EnterCriticalSection( &freetype_cs );
2092 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2093 LeaveCriticalSection( &freetype_cs );
2097 TRACE("AddFontToList failed\n");
2098 HeapFree(GetProcessHeap(), 0, pFontCopy);
2101 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2102 * For now return something unique but quite random
2104 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2105 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2112 /*************************************************************
2113 * WineEngRemoveFontResourceEx
2116 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2122 static const struct nls_update_font_list
2124 UINT ansi_cp, oem_cp;
2125 const char *oem, *fixed, *system;
2126 const char *courier, *serif, *small, *sserif;
2127 /* these are for font substitutes */
2128 const char *shelldlg, *tmsrmn;
2129 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2133 const char *from, *to;
2134 } arial_0, courier_new_0, times_new_roman_0;
2135 } nls_update_font_list[] =
2137 /* Latin 1 (United States) */
2138 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2139 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2140 "Tahoma","Times New Roman",
2141 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2144 /* Latin 1 (Multilingual) */
2145 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2146 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2147 "Tahoma","Times New Roman", /* FIXME unverified */
2148 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2151 /* Eastern Europe */
2152 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2153 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2154 "Tahoma","Times New Roman", /* FIXME unverified */
2155 "Fixedsys,238", "System,238",
2156 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2157 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2158 { "Arial CE,0", "Arial,238" },
2159 { "Courier New CE,0", "Courier New,238" },
2160 { "Times New Roman CE,0", "Times New Roman,238" }
2163 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2164 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2165 "Tahoma","Times New Roman", /* FIXME unverified */
2166 "Fixedsys,204", "System,204",
2167 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2168 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2169 { "Arial Cyr,0", "Arial,204" },
2170 { "Courier New Cyr,0", "Courier New,204" },
2171 { "Times New Roman Cyr,0", "Times New Roman,204" }
2174 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2175 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2176 "Tahoma","Times New Roman", /* FIXME unverified */
2177 "Fixedsys,161", "System,161",
2178 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2179 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2180 { "Arial Greek,0", "Arial,161" },
2181 { "Courier New Greek,0", "Courier New,161" },
2182 { "Times New Roman Greek,0", "Times New Roman,161" }
2185 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2186 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2187 "Tahoma","Times New Roman", /* FIXME unverified */
2188 "Fixedsys,162", "System,162",
2189 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2190 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2191 { "Arial Tur,0", "Arial,162" },
2192 { "Courier New Tur,0", "Courier New,162" },
2193 { "Times New Roman Tur,0", "Times New Roman,162" }
2196 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2197 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2198 "Tahoma","Times New Roman", /* FIXME unverified */
2199 "Fixedsys,177", "System,177",
2200 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2201 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2205 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2206 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2207 "Tahoma","Times New Roman", /* FIXME unverified */
2208 "Fixedsys,178", "System,178",
2209 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2210 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2214 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2215 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2216 "Tahoma","Times New Roman", /* FIXME unverified */
2217 "Fixedsys,186", "System,186",
2218 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2219 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2220 { "Arial Baltic,0", "Arial,186" },
2221 { "Courier New Baltic,0", "Courier New,186" },
2222 { "Times New Roman Baltic,0", "Times New Roman,186" }
2225 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2226 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2227 "Tahoma","Times New Roman", /* FIXME unverified */
2228 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2232 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2233 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2234 "Tahoma","Times New Roman", /* FIXME unverified */
2235 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2239 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2240 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2241 "MS UI Gothic","MS Serif",
2242 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2245 /* Chinese Simplified */
2246 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2247 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2248 "Tahoma", "Times New Roman", /* FIXME unverified */
2249 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2253 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2254 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2256 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2259 /* Chinese Traditional */
2260 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2261 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2262 "PMingLiU", "MingLiU",
2263 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2268 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2270 return ( ansi_cp == 932 /* CP932 for Japanese */
2271 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2272 || ansi_cp == 949 /* CP949 for Korean */
2273 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2276 static inline HKEY create_fonts_NT_registry_key(void)
2280 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2281 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2285 static inline HKEY create_fonts_9x_registry_key(void)
2289 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2290 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2294 static inline HKEY create_config_fonts_registry_key(void)
2298 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2299 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2303 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2305 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2306 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2307 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2308 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2311 static void set_value_key(HKEY hkey, const char *name, const char *value)
2314 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2316 RegDeleteValueA(hkey, name);
2319 static void update_font_info(void)
2321 char buf[40], cpbuf[40];
2324 UINT i, ansi_cp = 0, oem_cp = 0;
2327 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2330 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2331 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2332 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2333 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2334 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2336 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2337 if (is_dbcs_ansi_cp(ansi_cp))
2338 use_default_fallback = TRUE;
2341 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2343 if (!strcmp( buf, cpbuf )) /* already set correctly */
2348 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2350 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2352 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2355 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2359 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2360 nls_update_font_list[i].oem_cp == oem_cp)
2362 hkey = create_config_fonts_registry_key();
2363 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2364 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2365 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2368 hkey = create_fonts_NT_registry_key();
2369 add_font_list(hkey, &nls_update_font_list[i]);
2372 hkey = create_fonts_9x_registry_key();
2373 add_font_list(hkey, &nls_update_font_list[i]);
2376 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2378 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2379 strlen(nls_update_font_list[i].shelldlg)+1);
2380 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2381 strlen(nls_update_font_list[i].tmsrmn)+1);
2383 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2384 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2385 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2386 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2387 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2388 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2389 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2390 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2392 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2393 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2394 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2402 /* Delete the FontSubstitutes from other locales */
2403 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2405 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2406 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2407 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2413 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2417 static BOOL init_freetype(void)
2419 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2422 "Wine cannot find the FreeType font library. To enable Wine to\n"
2423 "use TrueType fonts please install a version of FreeType greater than\n"
2424 "or equal to 2.0.5.\n"
2425 "http://www.freetype.org\n");
2429 #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;}
2431 LOAD_FUNCPTR(FT_Vector_Unit)
2432 LOAD_FUNCPTR(FT_Done_Face)
2433 LOAD_FUNCPTR(FT_Get_Char_Index)
2434 LOAD_FUNCPTR(FT_Get_Module)
2435 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2436 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2437 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2438 LOAD_FUNCPTR(FT_Init_FreeType)
2439 LOAD_FUNCPTR(FT_Load_Glyph)
2440 LOAD_FUNCPTR(FT_Matrix_Multiply)
2441 #ifndef FT_MULFIX_INLINED
2442 LOAD_FUNCPTR(FT_MulFix)
2444 LOAD_FUNCPTR(FT_New_Face)
2445 LOAD_FUNCPTR(FT_New_Memory_Face)
2446 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2447 LOAD_FUNCPTR(FT_Outline_Transform)
2448 LOAD_FUNCPTR(FT_Outline_Translate)
2449 LOAD_FUNCPTR(FT_Select_Charmap)
2450 LOAD_FUNCPTR(FT_Set_Charmap)
2451 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2452 LOAD_FUNCPTR(FT_Vector_Transform)
2455 /* Don't warn if these ones are missing */
2456 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2457 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2458 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2459 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2460 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2461 #ifdef HAVE_FREETYPE_FTWINFNT_H
2462 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2464 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2465 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2466 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2467 <= 2.0.3 has FT_Sqrt64 */
2471 if(pFT_Init_FreeType(&library) != 0) {
2472 ERR("Can't init FreeType library\n");
2473 wine_dlclose(ft_handle, NULL, 0);
2477 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2478 if (pFT_Library_Version)
2479 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2481 if (FT_Version.major<=0)
2487 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2488 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2489 ((FT_Version.minor << 8) & 0x00ff00) |
2490 ((FT_Version.patch ) & 0x0000ff);
2496 "Wine cannot find certain functions that it needs inside the FreeType\n"
2497 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2498 "FreeType to at least version 2.0.5.\n"
2499 "http://www.freetype.org\n");
2500 wine_dlclose(ft_handle, NULL, 0);
2505 /*************************************************************
2508 * Initialize FreeType library and create a list of available faces
2510 BOOL WineEngInit(void)
2512 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2513 static const WCHAR pathW[] = {'P','a','t','h',0};
2515 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2517 WCHAR windowsdir[MAX_PATH];
2520 const char *data_dir;
2524 /* update locale dependent font info in registry */
2527 if(!init_freetype()) return FALSE;
2529 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2530 ERR("Failed to create font mutex\n");
2533 WaitForSingleObject(font_mutex, INFINITE);
2535 delete_external_font_keys();
2537 /* load the system bitmap fonts */
2538 load_system_fonts();
2540 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2541 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2542 strcatW(windowsdir, fontsW);
2543 if((unixname = wine_get_unix_file_name(windowsdir)))
2545 ReadFontDir(unixname, FALSE);
2546 HeapFree(GetProcessHeap(), 0, unixname);
2549 /* load the system truetype fonts */
2550 data_dir = wine_get_data_dir();
2551 if (!data_dir) data_dir = wine_get_build_dir();
2552 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2553 strcpy(unixname, data_dir);
2554 strcat(unixname, "/fonts/");
2555 ReadFontDir(unixname, TRUE);
2556 HeapFree(GetProcessHeap(), 0, unixname);
2559 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2560 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2561 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2563 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2564 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2565 &hkey) == ERROR_SUCCESS) {
2567 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2568 &valuelen, &datalen, NULL, NULL);
2570 valuelen++; /* returned value doesn't include room for '\0' */
2571 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2572 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2575 dlen = datalen * sizeof(WCHAR);
2577 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2578 &dlen) == ERROR_SUCCESS) {
2579 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2581 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2583 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2584 HeapFree(GetProcessHeap(), 0, unixname);
2587 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2589 WCHAR pathW[MAX_PATH];
2590 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2593 sprintfW(pathW, fmtW, windowsdir, data);
2594 if((unixname = wine_get_unix_file_name(pathW)))
2596 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2597 HeapFree(GetProcessHeap(), 0, unixname);
2600 load_font_from_data_dir(data);
2602 /* reset dlen and vlen */
2607 HeapFree(GetProcessHeap(), 0, data);
2608 HeapFree(GetProcessHeap(), 0, valueW);
2612 load_fontconfig_fonts();
2614 /* then look in any directories that we've specified in the config file */
2615 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2616 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2622 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2624 len += sizeof(WCHAR);
2625 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2626 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2628 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2629 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2630 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2631 TRACE( "got font path %s\n", debugstr_a(valueA) );
2635 LPSTR next = strchr( ptr, ':' );
2636 if (next) *next++ = 0;
2637 ReadFontDir( ptr, TRUE );
2640 HeapFree( GetProcessHeap(), 0, valueA );
2642 HeapFree( GetProcessHeap(), 0, valueW );
2651 update_reg_entries();
2653 init_system_links();
2655 ReleaseMutex(font_mutex);
2660 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2663 TT_HoriHeader *pHori;
2667 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2668 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2670 if(height == 0) height = 16;
2672 /* Calc. height of EM square:
2674 * For +ve lfHeight we have
2675 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2676 * Re-arranging gives:
2677 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2679 * For -ve lfHeight we have
2681 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2682 * with il = winAscent + winDescent - units_per_em]
2687 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2688 ppem = MulDiv(ft_face->units_per_EM, height,
2689 pHori->Ascender - pHori->Descender);
2691 ppem = MulDiv(ft_face->units_per_EM, height,
2692 pOS2->usWinAscent + pOS2->usWinDescent);
2700 static struct font_mapping *map_font_file( const char *name )
2702 struct font_mapping *mapping;
2706 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2707 if (fstat( fd, &st ) == -1) goto error;
2709 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2711 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2713 mapping->refcount++;
2718 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2721 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2724 if (mapping->data == MAP_FAILED)
2726 HeapFree( GetProcessHeap(), 0, mapping );
2729 mapping->refcount = 1;
2730 mapping->dev = st.st_dev;
2731 mapping->ino = st.st_ino;
2732 mapping->size = st.st_size;
2733 list_add_tail( &mappings_list, &mapping->entry );
2741 static void unmap_font_file( struct font_mapping *mapping )
2743 if (!--mapping->refcount)
2745 list_remove( &mapping->entry );
2746 munmap( mapping->data, mapping->size );
2747 HeapFree( GetProcessHeap(), 0, mapping );
2751 static LONG load_VDMX(GdiFont*, LONG);
2753 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2760 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2764 if (!(font->mapping = map_font_file( face->file )))
2766 WARN("failed to map %s\n", debugstr_a(face->file));
2769 data_ptr = font->mapping->data;
2770 data_size = font->mapping->size;
2774 data_ptr = face->font_data_ptr;
2775 data_size = face->font_data_size;
2778 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2780 ERR("FT_New_Face rets %d\n", err);
2784 /* set it here, as load_VDMX needs it */
2785 font->ft_face = ft_face;
2787 if(FT_IS_SCALABLE(ft_face)) {
2788 /* load the VDMX table if we have one */
2789 font->ppem = load_VDMX(font, height);
2791 font->ppem = calc_ppem_for_height(ft_face, height);
2792 TRACE("height %d => ppem %d\n", height, font->ppem);
2794 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2795 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2797 font->ppem = height;
2798 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2799 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2805 static int get_nearest_charset(Face *face, int *cp)
2807 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2808 a single face with the requested charset. The idea is to check if
2809 the selected font supports the current ANSI codepage, if it does
2810 return the corresponding charset, else return the first charset */
2813 int acp = GetACP(), i;
2817 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2818 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2819 return csi.ciCharset;
2821 for(i = 0; i < 32; i++) {
2823 if(face->fs.fsCsb[0] & fs0) {
2824 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2826 return csi.ciCharset;
2829 FIXME("TCI failing on %x\n", fs0);
2833 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2834 face->fs.fsCsb[0], face->file);
2836 return DEFAULT_CHARSET;
2839 static GdiFont *alloc_font(void)
2841 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2843 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2844 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2846 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2847 ret->total_kern_pairs = (DWORD)-1;
2848 ret->kern_pairs = NULL;
2849 list_init(&ret->hfontlist);
2850 list_init(&ret->child_fonts);
2854 static void free_font(GdiFont *font)
2856 struct list *cursor, *cursor2;
2859 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2861 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2862 struct list *first_hfont;
2863 HFONTLIST *hfontlist;
2864 list_remove(cursor);
2867 first_hfont = list_head(&child->font->hfontlist);
2868 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2869 DeleteObject(hfontlist->hfont);
2870 HeapFree(GetProcessHeap(), 0, hfontlist);
2871 free_font(child->font);
2873 HeapFree(GetProcessHeap(), 0, child);
2876 if (font->ft_face) pFT_Done_Face(font->ft_face);
2877 if (font->mapping) unmap_font_file( font->mapping );
2878 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2879 HeapFree(GetProcessHeap(), 0, font->potm);
2880 HeapFree(GetProcessHeap(), 0, font->name);
2881 for (i = 0; i < font->gmsize; i++)
2882 HeapFree(GetProcessHeap(),0,font->gm[i]);
2883 HeapFree(GetProcessHeap(), 0, font->gm);
2884 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2885 HeapFree(GetProcessHeap(), 0, font);
2889 /*************************************************************
2892 * load the vdmx entry for the specified height
2895 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2896 ( ( (FT_ULong)_x4 << 24 ) | \
2897 ( (FT_ULong)_x3 << 16 ) | \
2898 ( (FT_ULong)_x2 << 8 ) | \
2901 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2916 static LONG load_VDMX(GdiFont *font, LONG height)
2920 BYTE devXRatio, devYRatio;
2921 USHORT numRecs, numRatios;
2922 DWORD result, offset = -1;
2926 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2928 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2931 /* FIXME: need the real device aspect ratio */
2935 numRecs = GET_BE_WORD(hdr[1]);
2936 numRatios = GET_BE_WORD(hdr[2]);
2938 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2939 for(i = 0; i < numRatios; i++) {
2942 offset = (3 * 2) + (i * sizeof(Ratios));
2943 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2946 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2948 if((ratio.xRatio == 0 &&
2949 ratio.yStartRatio == 0 &&
2950 ratio.yEndRatio == 0) ||
2951 (devXRatio == ratio.xRatio &&
2952 devYRatio >= ratio.yStartRatio &&
2953 devYRatio <= ratio.yEndRatio))
2955 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2956 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2957 offset = GET_BE_WORD(tmp);
2963 FIXME("No suitable ratio found\n");
2967 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2969 BYTE startsz, endsz;
2972 recs = GET_BE_WORD(group.recs);
2973 startsz = group.startsz;
2974 endsz = group.endsz;
2976 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2978 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2979 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2980 if(result == GDI_ERROR) {
2981 FIXME("Failed to retrieve vTable\n");
2986 for(i = 0; i < recs; i++) {
2987 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2988 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2989 ppem = GET_BE_WORD(vTable[i * 3]);
2991 if(yMax + -yMin == height) {
2994 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2997 if(yMax + -yMin > height) {
3000 goto end; /* failed */
3002 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3003 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3004 ppem = GET_BE_WORD(vTable[i * 3]);
3005 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3011 TRACE("ppem not found for height %d\n", height);
3015 if(ppem < startsz || ppem > endsz)
3018 for(i = 0; i < recs; i++) {
3020 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3022 if(yPelHeight > ppem)
3025 if(yPelHeight == ppem) {
3026 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3027 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3028 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
3034 HeapFree(GetProcessHeap(), 0, vTable);
3040 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3042 if(font->font_desc.hash != fd->hash) return TRUE;
3043 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3044 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3045 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3046 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3049 static void calc_hash(FONT_DESC *pfd)
3051 DWORD hash = 0, *ptr, two_chars;
3055 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3057 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3059 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3061 pwc = (WCHAR *)&two_chars;
3063 *pwc = toupperW(*pwc);
3065 *pwc = toupperW(*pwc);
3069 hash ^= !pfd->can_use_bitmap;
3074 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3079 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3083 fd.can_use_bitmap = can_use_bitmap;
3086 /* try the in-use list */
3087 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3088 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3089 if(!fontcmp(ret, &fd)) {
3090 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3091 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3092 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3093 if(hflist->hfont == hfont)
3096 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3097 hflist->hfont = hfont;
3098 list_add_head(&ret->hfontlist, &hflist->entry);
3103 /* then the unused list */
3104 font_elem_ptr = list_head(&unused_gdi_font_list);
3105 while(font_elem_ptr) {
3106 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3107 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3108 if(!fontcmp(ret, &fd)) {
3109 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3110 assert(list_empty(&ret->hfontlist));
3111 TRACE("Found %p in unused list\n", ret);
3112 list_remove(&ret->entry);
3113 list_add_head(&gdi_font_list, &ret->entry);
3114 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3115 hflist->hfont = hfont;
3116 list_add_head(&ret->hfontlist, &hflist->entry);
3123 static void add_to_cache(GdiFont *font)
3125 static DWORD cache_num = 1;
3127 font->cache_num = cache_num++;
3128 list_add_head(&gdi_font_list, &font->entry);
3131 /*************************************************************
3132 * create_child_font_list
3134 static BOOL create_child_font_list(GdiFont *font)
3137 SYSTEM_LINKS *font_link;
3138 CHILD_FONT *font_link_entry, *new_child;
3140 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3142 if(!strcmpW(font_link->font_name, font->name))
3144 TRACE("found entry in system list\n");
3145 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3147 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3148 new_child->face = font_link_entry->face;
3149 new_child->font = NULL;
3150 list_add_tail(&font->child_fonts, &new_child->entry);
3151 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3158 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3159 * Sans Serif. This is how asian windows get default fallbacks for fonts
3161 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3162 font->charset != OEM_CHARSET &&
3163 strcmpW(font->name,szDefaultFallbackLink) != 0)
3164 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3166 if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3168 TRACE("found entry in default fallback list\n");
3169 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3171 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3172 new_child->face = font_link_entry->face;
3173 new_child->font = NULL;
3174 list_add_tail(&font->child_fonts, &new_child->entry);
3175 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3185 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3187 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3189 if (pFT_Set_Charmap)
3192 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3194 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3196 for (i = 0; i < ft_face->num_charmaps; i++)
3198 if (ft_face->charmaps[i]->encoding == encoding)
3200 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3201 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3203 switch (ft_face->charmaps[i]->platform_id)
3206 cmap_def = ft_face->charmaps[i];
3208 case 0: /* Apple Unicode */
3209 cmap0 = ft_face->charmaps[i];
3211 case 1: /* Macintosh */
3212 cmap1 = ft_face->charmaps[i];
3215 cmap2 = ft_face->charmaps[i];
3217 case 3: /* Microsoft */
3218 cmap3 = ft_face->charmaps[i];
3223 if (cmap3) /* prefer Microsoft cmap table */
3224 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3226 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3228 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3230 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3232 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3234 return ft_err == FT_Err_Ok;
3237 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3240 /*************************************************************
3241 * WineEngCreateFontInstance
3244 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3247 Face *face, *best, *best_bitmap;
3248 Family *family, *last_resort_family;
3249 struct list *family_elem_ptr, *face_elem_ptr;
3250 INT height, width = 0;
3251 unsigned int score = 0, new_score;
3252 signed int diff = 0, newdiff;
3253 BOOL bd, it, can_use_bitmap;
3258 FontSubst *psub = NULL;
3260 EnterCriticalSection( &freetype_cs );
3262 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
3264 struct list *first_hfont = list_head(&ret->hfontlist);
3265 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3266 if(hflist->hfont == hfont)
3268 LeaveCriticalSection( &freetype_cs );
3273 if (!GetObjectW( hfont, sizeof(lf), &lf ))
3275 LeaveCriticalSection( &freetype_cs );
3278 lf.lfWidth = abs(lf.lfWidth);
3280 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3282 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3283 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3284 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3287 if(dc->GraphicsMode == GM_ADVANCED)
3288 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3291 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3292 font scaling abilities. */
3293 dcmat.eM11 = dcmat.eM22 = fabs(dc->xformWorld2Vport.eM22);
3294 dcmat.eM21 = dcmat.eM12 = 0;
3297 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3298 dcmat.eM21, dcmat.eM22);
3300 /* check the cache first */
3301 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3302 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3303 LeaveCriticalSection( &freetype_cs );
3307 TRACE("not in cache\n");
3308 if(list_empty(&font_list)) /* No fonts installed */
3310 TRACE("No fonts installed\n");
3311 LeaveCriticalSection( &freetype_cs );
3314 if(!have_installed_roman_font)
3316 TRACE("No roman font installed\n");
3317 LeaveCriticalSection( &freetype_cs );
3323 ret->font_desc.matrix = dcmat;
3324 ret->font_desc.lf = lf;
3325 ret->font_desc.can_use_bitmap = can_use_bitmap;
3326 calc_hash(&ret->font_desc);
3327 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3328 hflist->hfont = hfont;
3329 list_add_head(&ret->hfontlist, &hflist->entry);
3331 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3332 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3333 original value lfCharSet. Note this is a special case for
3334 Symbol and doesn't happen at least for "Wingdings*" */
3336 if(!strcmpiW(lf.lfFaceName, SymbolW))
3337 lf.lfCharSet = SYMBOL_CHARSET;
3339 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3340 switch(lf.lfCharSet) {
3341 case DEFAULT_CHARSET:
3342 csi.fs.fsCsb[0] = 0;
3345 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3346 csi.fs.fsCsb[0] = 0;
3352 if(lf.lfFaceName[0] != '\0') {
3353 SYSTEM_LINKS *font_link;
3354 CHILD_FONT *font_link_entry;
3355 LPWSTR FaceName = lf.lfFaceName;
3358 * Check for a leading '@' this signals that the font is being
3359 * requested in tategaki mode (vertical writing substitution) but
3360 * does not affect the fontface that is to be selected.
3362 if (lf.lfFaceName[0]=='@')
3363 FaceName = &lf.lfFaceName[1];
3365 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3368 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3369 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3370 if (psub->to.charset != -1)
3371 lf.lfCharSet = psub->to.charset;
3374 /* We want a match on name and charset or just name if
3375 charset was DEFAULT_CHARSET. If the latter then
3376 we fixup the returned charset later in get_nearest_charset
3377 where we'll either use the charset of the current ansi codepage
3378 or if that's unavailable the first charset that the font supports.
3380 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3381 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3382 if (!strcmpiW(family->FamilyName, FaceName) ||
3383 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3385 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3386 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3387 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3388 if(face->scalable || can_use_bitmap)
3395 * Try check the SystemLink list first for a replacement font.
3396 * We may find good replacements there.
3398 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3400 if(!strcmpiW(font_link->font_name, FaceName))
3402 TRACE("found entry in system list\n");
3403 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3405 face = font_link_entry->face;
3406 family = face->family;
3407 if(csi.fs.fsCsb[0] &
3408 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3410 if(face->scalable || can_use_bitmap)
3418 psub = NULL; /* substitution is no more relevant */
3420 /* If requested charset was DEFAULT_CHARSET then try using charset
3421 corresponding to the current ansi codepage */
3422 if (!csi.fs.fsCsb[0] || lf.lfWeight == FW_DONTCARE)
3425 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3426 FIXME("TCI failed on codepage %d\n", acp);
3427 csi.fs.fsCsb[0] = 0;
3429 lf.lfCharSet = csi.ciCharset;
3432 /* Face families are in the top 4 bits of lfPitchAndFamily,
3433 so mask with 0xF0 before testing */
3435 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3436 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3437 strcpyW(lf.lfFaceName, defFixed);
3438 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3439 strcpyW(lf.lfFaceName, defSerif);
3440 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3441 strcpyW(lf.lfFaceName, defSans);
3443 strcpyW(lf.lfFaceName, defSans);
3444 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3445 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3446 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3447 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3448 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3449 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3450 if(face->scalable || can_use_bitmap)
3456 last_resort_family = NULL;
3457 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3458 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3459 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3460 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3461 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3464 if(can_use_bitmap && !last_resort_family)
3465 last_resort_family = family;
3470 if(last_resort_family) {
3471 family = last_resort_family;
3472 csi.fs.fsCsb[0] = 0;
3476 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3477 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3478 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3479 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3480 if(face->scalable) {
3481 csi.fs.fsCsb[0] = 0;
3482 WARN("just using first face for now\n");
3485 if(can_use_bitmap && !last_resort_family)
3486 last_resort_family = family;
3489 if(!last_resort_family) {
3490 FIXME("can't find a single appropriate font - bailing\n");
3492 LeaveCriticalSection( &freetype_cs );
3496 WARN("could only find a bitmap font - this will probably look awful!\n");
3497 family = last_resort_family;
3498 csi.fs.fsCsb[0] = 0;
3501 it = lf.lfItalic ? 1 : 0;
3502 bd = lf.lfWeight > 550 ? 1 : 0;
3504 height = lf.lfHeight;
3506 face = best = best_bitmap = NULL;
3507 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3509 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3513 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3514 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3515 new_score = (italic ^ it) + (bold ^ bd);
3516 if(!best || new_score <= score)
3518 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3519 italic, bold, it, bd);
3522 if(best->scalable && score == 0) break;
3526 newdiff = height - (signed int)(best->size.height);
3528 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3529 if(!best_bitmap || new_score < score ||
3530 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3532 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3535 if(score == 0 && diff == 0) break;
3542 face = best->scalable ? best : best_bitmap;
3543 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3544 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3548 if(csi.fs.fsCsb[0]) {
3549 ret->charset = lf.lfCharSet;
3550 ret->codepage = csi.ciACP;
3553 ret->charset = get_nearest_charset(face, &ret->codepage);
3555 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3556 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3558 ret->aveWidth = height ? lf.lfWidth : 0;
3560 if(!face->scalable) {
3561 /* Windows uses integer scaling factors for bitmap fonts */
3562 INT scale, scaled_height;
3564 /* FIXME: rotation of bitmap fonts is ignored */
3565 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3567 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3568 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3570 if (height != 0) height = diff;
3571 height += face->size.height;
3573 scale = (height + face->size.height - 1) / face->size.height;
3574 scaled_height = scale * face->size.height;
3575 /* XP allows not more than 10% deviation */
3576 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3577 ret->scale_y = scale;
3579 width = face->size.x_ppem >> 6;
3580 height = face->size.y_ppem >> 6;
3584 TRACE("font scale y: %f\n", ret->scale_y);
3586 ret->ft_face = OpenFontFace(ret, face, width, height);
3591 LeaveCriticalSection( &freetype_cs );
3595 ret->ntmFlags = face->ntmFlags;
3597 if (ret->charset == SYMBOL_CHARSET &&
3598 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3601 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3605 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3608 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3609 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3610 ret->underline = lf.lfUnderline ? 0xff : 0;
3611 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3612 create_child_font_list(ret);
3614 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3616 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3617 if (length != GDI_ERROR)
3619 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3620 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3621 TRACE("Loaded GSUB table of %i bytes\n",length);
3625 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3628 LeaveCriticalSection( &freetype_cs );
3632 static void dump_gdi_font_list(void)
3635 struct list *elem_ptr;
3637 TRACE("---------- gdiFont Cache ----------\n");
3638 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3639 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3640 TRACE("gdiFont=%p %s %d\n",
3641 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3644 TRACE("---------- Unused gdiFont Cache ----------\n");
3645 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3646 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3647 TRACE("gdiFont=%p %s %d\n",
3648 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3652 /*************************************************************
3653 * WineEngDestroyFontInstance
3655 * free the gdiFont associated with this handle
3658 BOOL WineEngDestroyFontInstance(HFONT handle)
3663 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3666 EnterCriticalSection( &freetype_cs );
3668 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3670 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3671 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3672 if(hflist->hfont == handle)
3674 TRACE("removing child font %p from child list\n", gdiFont);
3675 list_remove(&gdiFont->entry);
3676 LeaveCriticalSection( &freetype_cs );
3681 TRACE("destroying hfont=%p\n", handle);
3683 dump_gdi_font_list();
3685 font_elem_ptr = list_head(&gdi_font_list);
3686 while(font_elem_ptr) {
3687 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3688 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3690 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3691 while(hfontlist_elem_ptr) {
3692 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3693 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3694 if(hflist->hfont == handle) {
3695 list_remove(&hflist->entry);
3696 HeapFree(GetProcessHeap(), 0, hflist);
3700 if(list_empty(&gdiFont->hfontlist)) {
3701 TRACE("Moving to Unused list\n");
3702 list_remove(&gdiFont->entry);
3703 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3708 font_elem_ptr = list_head(&unused_gdi_font_list);
3709 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3710 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3711 while(font_elem_ptr) {
3712 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3713 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3714 TRACE("freeing %p\n", gdiFont);
3715 list_remove(&gdiFont->entry);
3718 LeaveCriticalSection( &freetype_cs );
3722 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3723 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3728 if (face->cached_enum_data)
3731 *pelf = face->cached_enum_data->elf;
3732 *pntm = face->cached_enum_data->ntm;
3733 *ptype = face->cached_enum_data->type;
3737 font = alloc_font();
3739 if(face->scalable) {
3740 height = -2048; /* 2048 is the most common em size */
3743 height = face->size.y_ppem >> 6;
3744 width = face->size.x_ppem >> 6;
3746 font->scale_y = 1.0;
3748 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3754 font->name = strdupW(face->family->FamilyName);
3755 font->ntmFlags = face->ntmFlags;
3757 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3759 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3761 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3763 lstrcpynW(pelf->elfLogFont.lfFaceName,
3764 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3766 lstrcpynW(pelf->elfFullName,
3767 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3769 lstrcpynW(pelf->elfStyle,
3770 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3775 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3777 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3779 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3780 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3781 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3784 pntm->ntmTm.ntmFlags = face->ntmFlags;
3785 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3786 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3787 pntm->ntmFontSig = face->fs;
3789 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3791 pelf->elfLogFont.lfEscapement = 0;
3792 pelf->elfLogFont.lfOrientation = 0;
3793 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3794 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3795 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3796 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3797 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3798 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3799 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3800 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3801 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3802 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3803 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3806 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3807 *ptype |= TRUETYPE_FONTTYPE;
3808 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3809 *ptype |= DEVICE_FONTTYPE;
3810 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3811 *ptype |= RASTER_FONTTYPE;
3813 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3814 if (face->cached_enum_data)
3816 face->cached_enum_data->elf = *pelf;
3817 face->cached_enum_data->ntm = *pntm;
3818 face->cached_enum_data->type = *ptype;
3824 /*************************************************************
3828 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3832 struct list *family_elem_ptr, *face_elem_ptr;
3834 NEWTEXTMETRICEXW ntm;
3843 lf.lfCharSet = DEFAULT_CHARSET;
3844 lf.lfPitchAndFamily = 0;
3845 lf.lfFaceName[0] = 0;
3849 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3851 EnterCriticalSection( &freetype_cs );
3852 if(plf->lfFaceName[0]) {
3854 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3857 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3858 debugstr_w(psub->to.name));
3860 strcpyW(lf.lfFaceName, psub->to.name);
3864 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3865 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3866 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3867 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3868 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3869 GetEnumStructs(face, &elf, &ntm, &type);
3870 for(i = 0; i < 32; i++) {
3871 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3872 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3873 strcpyW(elf.elfScript, OEM_DOSW);
3874 i = 32; /* break out of loop */
3875 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3878 fs.fsCsb[0] = 1L << i;
3880 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3882 csi.ciCharset = DEFAULT_CHARSET;
3883 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3884 if(csi.ciCharset != DEFAULT_CHARSET) {
3885 elf.elfLogFont.lfCharSet =
3886 ntm.ntmTm.tmCharSet = csi.ciCharset;
3888 strcpyW(elf.elfScript, ElfScriptsW[i]);
3890 FIXME("Unknown elfscript for bit %d\n", i);
3893 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3894 debugstr_w(elf.elfLogFont.lfFaceName),
3895 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3896 csi.ciCharset, type, debugstr_w(elf.elfScript),
3897 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3898 ntm.ntmTm.ntmFlags);
3899 /* release section before callback (FIXME) */
3900 LeaveCriticalSection( &freetype_cs );
3901 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3902 EnterCriticalSection( &freetype_cs );
3908 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3909 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3910 face_elem_ptr = list_head(&family->faces);
3911 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3912 GetEnumStructs(face, &elf, &ntm, &type);
3913 for(i = 0; i < 32; i++) {
3914 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3915 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3916 strcpyW(elf.elfScript, OEM_DOSW);
3917 i = 32; /* break out of loop */
3918 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3921 fs.fsCsb[0] = 1L << i;
3923 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3925 csi.ciCharset = DEFAULT_CHARSET;
3926 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3927 if(csi.ciCharset != DEFAULT_CHARSET) {
3928 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3931 strcpyW(elf.elfScript, ElfScriptsW[i]);
3933 FIXME("Unknown elfscript for bit %d\n", i);
3936 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3937 debugstr_w(elf.elfLogFont.lfFaceName),
3938 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3939 csi.ciCharset, type, debugstr_w(elf.elfScript),
3940 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3941 ntm.ntmTm.ntmFlags);
3942 /* release section before callback (FIXME) */
3943 LeaveCriticalSection( &freetype_cs );
3944 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3945 EnterCriticalSection( &freetype_cs );
3949 LeaveCriticalSection( &freetype_cs );
3953 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3955 pt->x.value = vec->x >> 6;
3956 pt->x.fract = (vec->x & 0x3f) << 10;
3957 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3958 pt->y.value = vec->y >> 6;
3959 pt->y.fract = (vec->y & 0x3f) << 10;
3960 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3964 /***************************************************
3965 * According to the MSDN documentation on WideCharToMultiByte,
3966 * certain codepages cannot set the default_used parameter.
3967 * This returns TRUE if the codepage can set that parameter, false else
3968 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3970 static BOOL codepage_sets_default_used(UINT codepage)
3984 * GSUB Table handling functions
3987 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
3989 const GSUB_CoverageFormat1* cf1;
3991 cf1 = (GSUB_CoverageFormat1*)table;
3993 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
3995 int count = GET_BE_WORD(cf1->GlyphCount);
3997 TRACE("Coverage Format 1, %i glyphs\n",count);
3998 for (i = 0; i < count; i++)
3999 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4003 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4005 const GSUB_CoverageFormat2* cf2;
4008 cf2 = (GSUB_CoverageFormat2*)cf1;
4010 count = GET_BE_WORD(cf2->RangeCount);
4011 TRACE("Coverage Format 2, %i ranges\n",count);
4012 for (i = 0; i < count; i++)
4014 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4016 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4017 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4019 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4020 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4026 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4031 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4033 const GSUB_ScriptList *script;
4034 const GSUB_Script *deflt = NULL;
4036 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
4038 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4039 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4041 const GSUB_Script *scr;
4044 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4045 scr = (GSUB_Script*)((LPBYTE)script + offset);
4047 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4049 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4055 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4059 const GSUB_LangSys *Lang;
4061 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4063 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4065 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4066 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4068 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4071 offset = GET_BE_WORD(script->DefaultLangSys);
4074 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4080 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4083 const GSUB_FeatureList *feature;
4084 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
4086 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4087 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4089 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4090 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4092 const GSUB_Feature *feat;
4093 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4100 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4104 const GSUB_LookupList *lookup;
4105 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
4107 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4108 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4110 const GSUB_LookupTable *look;
4111 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4112 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
4113 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4114 if (GET_BE_WORD(look->LookupType) != 1)
4115 FIXME("We only handle SubType 1\n");
4120 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4122 const GSUB_SingleSubstFormat1 *ssf1;
4123 offset = GET_BE_WORD(look->SubTable[j]);
4124 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
4125 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4127 int offset = GET_BE_WORD(ssf1->Coverage);
4128 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4129 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
4131 TRACE(" Glyph 0x%x ->",glyph);
4132 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4133 TRACE(" 0x%x\n",glyph);
4138 const GSUB_SingleSubstFormat2 *ssf2;
4142 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
4143 offset = GET_BE_WORD(ssf1->Coverage);
4144 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4145 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
4146 TRACE(" Coverage index %i\n",index);
4149 TRACE(" Glyph is 0x%x ->",glyph);
4150 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4151 TRACE("0x%x\n",glyph);
4160 static const char* get_opentype_script(const GdiFont *font)
4163 * I am not sure if this is the correct way to generate our script tag
4166 switch (font->charset)
4168 case ANSI_CHARSET: return "latn";
4169 case BALTIC_CHARSET: return "latn"; /* ?? */
4170 case CHINESEBIG5_CHARSET: return "hani";
4171 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4172 case GB2312_CHARSET: return "hani";
4173 case GREEK_CHARSET: return "grek";
4174 case HANGUL_CHARSET: return "hang";
4175 case RUSSIAN_CHARSET: return "cyrl";
4176 case SHIFTJIS_CHARSET: return "kana";
4177 case TURKISH_CHARSET: return "latn"; /* ?? */
4178 case VIETNAMESE_CHARSET: return "latn";
4179 case JOHAB_CHARSET: return "latn"; /* ?? */
4180 case ARABIC_CHARSET: return "arab";
4181 case HEBREW_CHARSET: return "hebr";
4182 case THAI_CHARSET: return "thai";
4183 default: return "latn";
4187 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4189 const GSUB_Header *header;
4190 const GSUB_Script *script;
4191 const GSUB_LangSys *language;
4192 const GSUB_Feature *feature;
4194 if (!font->GSUB_Table)
4197 header = font->GSUB_Table;
4199 script = GSUB_get_script_table(header, get_opentype_script(font));
4202 TRACE("Script not found\n");
4205 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4208 TRACE("Language not found\n");
4211 feature = GSUB_get_feature(header, language, "vrt2");
4213 feature = GSUB_get_feature(header, language, "vert");
4216 TRACE("vrt2/vert feature not found\n");
4219 return GSUB_apply_feature(header, feature, glyph);
4222 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4226 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4227 WCHAR wc = (WCHAR)glyph;
4229 BOOL *default_used_pointer;
4232 default_used_pointer = NULL;
4233 default_used = FALSE;
4234 if (codepage_sets_default_used(font->codepage))
4235 default_used_pointer = &default_used;
4236 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4239 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4240 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4241 return get_GSUB_vert_glyph(font,ret);
4244 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4245 glyph = glyph + 0xf000;
4246 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4247 return get_GSUB_vert_glyph(font,glyphId);
4250 /*************************************************************
4251 * WineEngGetGlyphIndices
4254 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4255 LPWORD pgi, DWORD flags)
4258 int default_char = -1;
4260 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4262 for(i = 0; i < count; i++)
4264 pgi[i] = get_glyph_index(font, lpstr[i]);
4267 if (default_char == -1)
4269 if (FT_IS_SFNT(font->ft_face))
4271 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4272 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4277 WineEngGetTextMetrics(font, &textm);
4278 default_char = textm.tmDefaultChar;
4281 pgi[i] = default_char;
4287 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4289 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4290 return !memcmp(matrix, &identity, sizeof(FMAT2));
4293 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4295 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4296 return !memcmp(matrix, &identity, sizeof(MAT2));
4299 /*************************************************************
4300 * WineEngGetGlyphOutline
4302 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4303 * except that the first parameter is the HWINEENGFONT of the font in
4304 * question rather than an HDC.
4307 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4308 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4311 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4312 FT_Face ft_face = incoming_font->ft_face;
4313 GdiFont *font = incoming_font;
4314 FT_UInt glyph_index;
4315 DWORD width, height, pitch, needed = 0;
4316 FT_Bitmap ft_bitmap;
4318 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4320 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4321 double widthRatio = 1.0;
4322 FT_Matrix transMat = identityMat;
4323 FT_Matrix transMatUnrotated;
4324 BOOL needsTransform = FALSE;
4325 BOOL tategaki = (font->GSUB_Table != NULL);
4326 UINT original_index;
4328 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4329 buflen, buf, lpmat);
4331 TRACE("font transform %f %f %f %f\n",
4332 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4333 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4335 EnterCriticalSection( &freetype_cs );
4337 if(format & GGO_GLYPH_INDEX) {
4338 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4339 original_index = glyph;
4340 format &= ~GGO_GLYPH_INDEX;
4342 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4343 ft_face = font->ft_face;
4344 original_index = glyph_index;
4347 /* tategaki never appears to happen to lower glyph index */
4348 if (glyph_index < TATEGAKI_LOWER_BOUND )
4351 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4352 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4353 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4354 font->gmsize * sizeof(GM*));
4356 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4357 FONT_GM(font,original_index)->init && (!lpmat || is_identity_MAT2(lpmat)))
4359 *lpgm = FONT_GM(font,original_index)->gm;
4360 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4361 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4362 lpgm->gmCellIncX, lpgm->gmCellIncY);
4363 LeaveCriticalSection( &freetype_cs );
4364 return 1; /* FIXME */
4368 if (!font->gm[original_index / GM_BLOCK_SIZE])
4369 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4371 /* Scaling factor */
4376 WineEngGetTextMetrics(font, &tm);
4378 widthRatio = (double)font->aveWidth;
4379 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4382 widthRatio = font->scale_y;
4384 /* Scaling transform */
4385 if (widthRatio != 1.0 || font->scale_y != 1.0)
4388 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4391 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4393 pFT_Matrix_Multiply(&scaleMat, &transMat);
4394 needsTransform = TRUE;
4397 /* Slant transform */
4398 if (font->fake_italic) {
4401 slantMat.xx = (1 << 16);
4402 slantMat.xy = ((1 << 16) >> 2);
4404 slantMat.yy = (1 << 16);
4405 pFT_Matrix_Multiply(&slantMat, &transMat);
4406 needsTransform = TRUE;
4409 /* Rotation transform */
4410 transMatUnrotated = transMat;
4411 if(font->orientation && !tategaki) {
4412 FT_Matrix rotationMat;
4414 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4415 pFT_Vector_Unit(&vecAngle, angle);
4416 rotationMat.xx = vecAngle.x;
4417 rotationMat.xy = -vecAngle.y;
4418 rotationMat.yx = -rotationMat.xy;
4419 rotationMat.yy = rotationMat.xx;
4421 pFT_Matrix_Multiply(&rotationMat, &transMat);
4422 needsTransform = TRUE;
4425 /* World transform */
4426 if (!is_identity_FMAT2(&font->font_desc.matrix))
4429 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4430 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4431 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4432 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4433 pFT_Matrix_Multiply(&worldMat, &transMat);
4434 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4435 needsTransform = TRUE;
4438 /* Extra transformation specified by caller */
4439 if (lpmat && !is_identity_MAT2(lpmat))
4442 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4443 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
4444 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
4445 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4446 pFT_Matrix_Multiply(&extraMat, &transMat);
4447 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4448 needsTransform = TRUE;
4451 if (needsTransform || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP))
4452 load_flags |= FT_LOAD_NO_BITMAP;
4454 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4457 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4458 LeaveCriticalSection( &freetype_cs );
4462 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4463 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4465 adv = (INT)((ft_face->glyph->metrics.horiAdvance) + 63) >> 6;
4467 bbx = (right - left) >> 6;
4469 if(!needsTransform) {
4470 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4471 bottom = (ft_face->glyph->metrics.horiBearingY -
4472 ft_face->glyph->metrics.height) & -64;
4473 lpgm->gmCellIncX = adv;
4474 lpgm->gmCellIncY = 0;
4478 for(xc = 0; xc < 2; xc++) {
4479 for(yc = 0; yc < 2; yc++) {
4480 vec.x = (ft_face->glyph->metrics.horiBearingX +
4481 xc * ft_face->glyph->metrics.width);
4482 vec.y = ft_face->glyph->metrics.horiBearingY -
4483 yc * ft_face->glyph->metrics.height;
4484 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4485 pFT_Vector_Transform(&vec, &transMat);
4486 if(xc == 0 && yc == 0) {
4487 left = right = vec.x;
4488 top = bottom = vec.y;
4490 if(vec.x < left) left = vec.x;
4491 else if(vec.x > right) right = vec.x;
4492 if(vec.y < bottom) bottom = vec.y;
4493 else if(vec.y > top) top = vec.y;
4498 right = (right + 63) & -64;
4499 bottom = bottom & -64;
4500 top = (top + 63) & -64;
4502 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4503 vec.x = ft_face->glyph->metrics.horiAdvance;
4505 pFT_Vector_Transform(&vec, &transMat);
4506 lpgm->gmCellIncX = (vec.x+63) >> 6;
4507 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4509 vec.x = ft_face->glyph->metrics.horiAdvance;
4511 pFT_Vector_Transform(&vec, &transMatUnrotated);
4512 adv = (vec.x+63) >> 6;
4514 lpgm->gmBlackBoxX = (right - left) >> 6;
4515 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4516 lpgm->gmptGlyphOrigin.x = left >> 6;
4517 lpgm->gmptGlyphOrigin.y = top >> 6;
4519 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4520 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4521 lpgm->gmCellIncX, lpgm->gmCellIncY);
4523 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4524 (!lpmat || is_identity_MAT2(lpmat))) /* don't cache custom transforms */
4526 FONT_GM(font,original_index)->gm = *lpgm;
4527 FONT_GM(font,original_index)->adv = adv;
4528 FONT_GM(font,original_index)->lsb = lsb;
4529 FONT_GM(font,original_index)->bbx = bbx;
4530 FONT_GM(font,original_index)->init = TRUE;
4533 if(format == GGO_METRICS)
4535 LeaveCriticalSection( &freetype_cs );
4536 return 1; /* FIXME */
4539 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
4540 TRACE("loaded a bitmap\n");
4541 LeaveCriticalSection( &freetype_cs );
4547 width = lpgm->gmBlackBoxX;
4548 height = lpgm->gmBlackBoxY;
4549 pitch = ((width + 31) >> 5) << 2;
4550 needed = pitch * height;
4552 if(!buf || !buflen) break;
4554 switch(ft_face->glyph->format) {
4555 case ft_glyph_format_bitmap:
4557 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4558 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4559 INT h = ft_face->glyph->bitmap.rows;
4561 memcpy(dst, src, w);
4562 src += ft_face->glyph->bitmap.pitch;
4568 case ft_glyph_format_outline:
4569 ft_bitmap.width = width;
4570 ft_bitmap.rows = height;
4571 ft_bitmap.pitch = pitch;
4572 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4573 ft_bitmap.buffer = buf;
4575 if(needsTransform) {
4576 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4579 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4581 /* Note: FreeType will only set 'black' bits for us. */
4582 memset(buf, 0, needed);
4583 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4587 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4588 LeaveCriticalSection( &freetype_cs );
4593 case GGO_GRAY2_BITMAP:
4594 case GGO_GRAY4_BITMAP:
4595 case GGO_GRAY8_BITMAP:
4596 case WINE_GGO_GRAY16_BITMAP:
4598 unsigned int mult, row, col;
4601 width = lpgm->gmBlackBoxX;
4602 height = lpgm->gmBlackBoxY;
4603 pitch = (width + 3) / 4 * 4;
4604 needed = pitch * height;
4606 if(!buf || !buflen) break;
4608 switch(ft_face->glyph->format) {
4609 case ft_glyph_format_bitmap:
4611 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4612 INT h = ft_face->glyph->bitmap.rows;
4615 for(x = 0; x < pitch; x++)
4617 if(x < ft_face->glyph->bitmap.width)
4618 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4622 src += ft_face->glyph->bitmap.pitch;
4625 LeaveCriticalSection( &freetype_cs );
4628 case ft_glyph_format_outline:
4630 ft_bitmap.width = width;
4631 ft_bitmap.rows = height;
4632 ft_bitmap.pitch = pitch;
4633 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4634 ft_bitmap.buffer = buf;
4637 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4639 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4641 memset(ft_bitmap.buffer, 0, buflen);
4643 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4645 if(format == GGO_GRAY2_BITMAP)
4647 else if(format == GGO_GRAY4_BITMAP)
4649 else if(format == GGO_GRAY8_BITMAP)
4651 else /* format == WINE_GGO_GRAY16_BITMAP */
4653 LeaveCriticalSection( &freetype_cs );
4659 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4660 LeaveCriticalSection( &freetype_cs );
4665 for(row = 0; row < height; row++) {
4667 for(col = 0; col < width; col++, ptr++) {
4668 *ptr = (((int)*ptr) * mult + 128) / 256;
4677 int contour, point = 0, first_pt;
4678 FT_Outline *outline = &ft_face->glyph->outline;
4679 TTPOLYGONHEADER *pph;
4681 DWORD pph_start, cpfx, type;
4683 if(buflen == 0) buf = NULL;
4685 if (needsTransform && buf) {
4686 pFT_Outline_Transform(outline, &transMat);
4689 for(contour = 0; contour < outline->n_contours; contour++) {
4691 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4694 pph->dwType = TT_POLYGON_TYPE;
4695 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4697 needed += sizeof(*pph);
4699 while(point <= outline->contours[contour]) {
4700 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4701 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4702 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4706 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4709 } while(point <= outline->contours[contour] &&
4710 (outline->tags[point] & FT_Curve_Tag_On) ==
4711 (outline->tags[point-1] & FT_Curve_Tag_On));
4712 /* At the end of a contour Windows adds the start point, but
4714 if(point > outline->contours[contour] &&
4715 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4717 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4719 } else if(point <= outline->contours[contour] &&
4720 outline->tags[point] & FT_Curve_Tag_On) {
4721 /* add closing pt for bezier */
4723 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4731 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4734 pph->cb = needed - pph_start;
4740 /* Convert the quadratic Beziers to cubic Beziers.
4741 The parametric eqn for a cubic Bezier is, from PLRM:
4742 r(t) = at^3 + bt^2 + ct + r0
4743 with the control points:
4748 A quadratic Beizer has the form:
4749 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4751 So equating powers of t leads to:
4752 r1 = 2/3 p1 + 1/3 p0
4753 r2 = 2/3 p1 + 1/3 p2
4754 and of course r0 = p0, r3 = p2
4757 int contour, point = 0, first_pt;
4758 FT_Outline *outline = &ft_face->glyph->outline;
4759 TTPOLYGONHEADER *pph;
4761 DWORD pph_start, cpfx, type;
4762 FT_Vector cubic_control[4];
4763 if(buflen == 0) buf = NULL;
4765 if (needsTransform && buf) {
4766 pFT_Outline_Transform(outline, &transMat);
4769 for(contour = 0; contour < outline->n_contours; contour++) {
4771 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4774 pph->dwType = TT_POLYGON_TYPE;
4775 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4777 needed += sizeof(*pph);
4779 while(point <= outline->contours[contour]) {
4780 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4781 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4782 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4785 if(type == TT_PRIM_LINE) {
4787 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4791 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4794 /* FIXME: Possible optimization in endpoint calculation
4795 if there are two consecutive curves */
4796 cubic_control[0] = outline->points[point-1];
4797 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4798 cubic_control[0].x += outline->points[point].x + 1;
4799 cubic_control[0].y += outline->points[point].y + 1;
4800 cubic_control[0].x >>= 1;
4801 cubic_control[0].y >>= 1;
4803 if(point+1 > outline->contours[contour])
4804 cubic_control[3] = outline->points[first_pt];
4806 cubic_control[3] = outline->points[point+1];
4807 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4808 cubic_control[3].x += outline->points[point].x + 1;
4809 cubic_control[3].y += outline->points[point].y + 1;
4810 cubic_control[3].x >>= 1;
4811 cubic_control[3].y >>= 1;
4814 /* r1 = 1/3 p0 + 2/3 p1
4815 r2 = 1/3 p2 + 2/3 p1 */
4816 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4817 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4818 cubic_control[2] = cubic_control[1];
4819 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4820 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4821 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4822 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4824 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4825 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4826 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4831 } while(point <= outline->contours[contour] &&
4832 (outline->tags[point] & FT_Curve_Tag_On) ==
4833 (outline->tags[point-1] & FT_Curve_Tag_On));
4834 /* At the end of a contour Windows adds the start point,
4835 but only for Beziers and we've already done that.
4837 if(point <= outline->contours[contour] &&
4838 outline->tags[point] & FT_Curve_Tag_On) {
4839 /* This is the closing pt of a bezier, but we've already
4840 added it, so just inc point and carry on */
4847 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4850 pph->cb = needed - pph_start;
4856 FIXME("Unsupported format %d\n", format);
4857 LeaveCriticalSection( &freetype_cs );
4860 LeaveCriticalSection( &freetype_cs );
4864 static BOOL get_bitmap_text_metrics(GdiFont *font)
4866 FT_Face ft_face = font->ft_face;
4867 #ifdef HAVE_FREETYPE_FTWINFNT_H
4868 FT_WinFNT_HeaderRec winfnt_header;
4870 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4871 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4872 font->potm->otmSize = size;
4874 #define TM font->potm->otmTextMetrics
4875 #ifdef HAVE_FREETYPE_FTWINFNT_H
4876 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4878 TM.tmHeight = winfnt_header.pixel_height;
4879 TM.tmAscent = winfnt_header.ascent;
4880 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4881 TM.tmInternalLeading = winfnt_header.internal_leading;
4882 TM.tmExternalLeading = winfnt_header.external_leading;
4883 TM.tmAveCharWidth = winfnt_header.avg_width;
4884 TM.tmMaxCharWidth = winfnt_header.max_width;
4885 TM.tmWeight = winfnt_header.weight;
4887 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4888 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4889 TM.tmFirstChar = winfnt_header.first_char;
4890 TM.tmLastChar = winfnt_header.last_char;
4891 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4892 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4893 TM.tmItalic = winfnt_header.italic;
4894 TM.tmUnderlined = font->underline;
4895 TM.tmStruckOut = font->strikeout;
4896 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4897 TM.tmCharSet = winfnt_header.charset;
4902 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4903 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4904 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4905 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4906 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4907 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4908 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4909 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4911 TM.tmDigitizedAspectX = 96; /* FIXME */
4912 TM.tmDigitizedAspectY = 96; /* FIXME */
4914 TM.tmLastChar = 255;
4915 TM.tmDefaultChar = 32;
4916 TM.tmBreakChar = 32;
4917 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4918 TM.tmUnderlined = font->underline;
4919 TM.tmStruckOut = font->strikeout;
4920 /* NB inverted meaning of TMPF_FIXED_PITCH */
4921 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4922 TM.tmCharSet = font->charset;
4930 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
4932 double scale_x, scale_y;
4936 scale_x = (double)font->aveWidth;
4937 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4940 scale_x = font->scale_y;
4942 scale_x *= fabs(font->font_desc.matrix.eM11);
4943 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
4945 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
4946 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
4948 SCALE_Y(ptm->tmHeight);
4949 SCALE_Y(ptm->tmAscent);
4950 SCALE_Y(ptm->tmDescent);
4951 SCALE_Y(ptm->tmInternalLeading);
4952 SCALE_Y(ptm->tmExternalLeading);
4953 SCALE_Y(ptm->tmOverhang);
4955 SCALE_X(ptm->tmAveCharWidth);
4956 SCALE_X(ptm->tmMaxCharWidth);
4962 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
4964 double scale_x, scale_y;
4968 scale_x = (double)font->aveWidth;
4969 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4972 scale_x = font->scale_y;
4974 scale_x *= fabs(font->font_desc.matrix.eM11);
4975 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
4977 scale_font_metrics(font, &potm->otmTextMetrics);
4979 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
4980 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
4982 SCALE_Y(potm->otmAscent);
4983 SCALE_Y(potm->otmDescent);
4984 SCALE_Y(potm->otmLineGap);
4985 SCALE_Y(potm->otmsCapEmHeight);
4986 SCALE_Y(potm->otmsXHeight);
4987 SCALE_Y(potm->otmrcFontBox.top);
4988 SCALE_Y(potm->otmrcFontBox.bottom);
4989 SCALE_X(potm->otmrcFontBox.left);
4990 SCALE_X(potm->otmrcFontBox.right);
4991 SCALE_Y(potm->otmMacAscent);
4992 SCALE_Y(potm->otmMacDescent);
4993 SCALE_Y(potm->otmMacLineGap);
4994 SCALE_X(potm->otmptSubscriptSize.x);
4995 SCALE_Y(potm->otmptSubscriptSize.y);
4996 SCALE_X(potm->otmptSubscriptOffset.x);
4997 SCALE_Y(potm->otmptSubscriptOffset.y);
4998 SCALE_X(potm->otmptSuperscriptSize.x);
4999 SCALE_Y(potm->otmptSuperscriptSize.y);
5000 SCALE_X(potm->otmptSuperscriptOffset.x);
5001 SCALE_Y(potm->otmptSuperscriptOffset.y);
5002 SCALE_Y(potm->otmsStrikeoutSize);
5003 SCALE_Y(potm->otmsStrikeoutPosition);
5004 SCALE_Y(potm->otmsUnderscoreSize);
5005 SCALE_Y(potm->otmsUnderscorePosition);
5011 /*************************************************************
5012 * WineEngGetTextMetrics
5015 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5017 EnterCriticalSection( &freetype_cs );
5019 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5020 if(!get_bitmap_text_metrics(font))
5022 LeaveCriticalSection( &freetype_cs );
5028 LeaveCriticalSection( &freetype_cs );
5031 *ptm = font->potm->otmTextMetrics;
5032 scale_font_metrics(font, ptm);
5033 LeaveCriticalSection( &freetype_cs );
5038 /*************************************************************
5039 * WineEngGetOutlineTextMetrics
5042 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5043 OUTLINETEXTMETRICW *potm)
5045 FT_Face ft_face = font->ft_face;
5046 UINT needed, lenfam, lensty, ret;
5048 TT_HoriHeader *pHori;
5049 TT_Postscript *pPost;
5050 FT_Fixed x_scale, y_scale;
5051 WCHAR *family_nameW, *style_nameW;
5052 static const WCHAR spaceW[] = {' ', '\0'};
5054 INT ascent, descent;
5056 TRACE("font=%p\n", font);
5058 if(!FT_IS_SCALABLE(ft_face))
5061 EnterCriticalSection( &freetype_cs );
5064 if(cbSize >= font->potm->otmSize)
5066 memcpy(potm, font->potm, font->potm->otmSize);
5067 scale_outline_font_metrics(font, potm);
5069 LeaveCriticalSection( &freetype_cs );
5070 return font->potm->otmSize;
5074 needed = sizeof(*potm);
5076 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5077 family_nameW = strdupW(font->name);
5079 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5081 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5082 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5083 style_nameW, lensty/sizeof(WCHAR));
5085 /* These names should be read from the TT name table */
5087 /* length of otmpFamilyName */
5090 /* length of otmpFaceName */
5091 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5092 needed += lenfam; /* just the family name */
5094 needed += lenfam + lensty; /* family + " " + style */
5097 /* length of otmpStyleName */
5100 /* length of otmpFullName */
5101 needed += lenfam + lensty;
5104 x_scale = ft_face->size->metrics.x_scale;
5105 y_scale = ft_face->size->metrics.y_scale;
5107 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5109 FIXME("Can't find OS/2 table - not TT font?\n");
5114 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5116 FIXME("Can't find HHEA table - not TT font?\n");
5121 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5123 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",
5124 pOS2->usWinAscent, pOS2->usWinDescent,
5125 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5126 ft_face->ascender, ft_face->descender, ft_face->height,
5127 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5128 ft_face->bbox.yMax, ft_face->bbox.yMin);
5130 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5131 font->potm->otmSize = needed;
5133 #define TM font->potm->otmTextMetrics
5135 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5136 ascent = pHori->Ascender;
5137 descent = -pHori->Descender;
5139 ascent = pOS2->usWinAscent;
5140 descent = pOS2->usWinDescent;
5144 TM.tmAscent = font->yMax;
5145 TM.tmDescent = -font->yMin;
5146 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5148 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5149 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5150 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5151 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5154 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5157 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5159 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5160 ((ascent + descent) -
5161 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5163 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5164 if (TM.tmAveCharWidth == 0) {
5165 TM.tmAveCharWidth = 1;
5167 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5168 TM.tmWeight = (font->fake_bold || (ft_face->style_flags & FT_STYLE_FLAG_BOLD)) ? FW_BOLD : FW_REGULAR;
5170 TM.tmDigitizedAspectX = 300;
5171 TM.tmDigitizedAspectY = 300;
5172 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5173 * symbol range to 0 - f0ff
5175 if (font->charset == SYMBOL_CHARSET)
5178 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
5182 TM.tmFirstChar = pOS2->usFirstCharIndex;
5183 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0xffff;
5185 TM.tmLastChar = pOS2->usLastCharIndex;
5186 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
5187 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5188 TM.tmUnderlined = font->underline;
5189 TM.tmStruckOut = font->strikeout;
5191 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5192 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5193 (pOS2->version == 0xFFFFU ||
5194 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5195 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5197 TM.tmPitchAndFamily = 0;
5199 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
5200 case PAN_FAMILY_SCRIPT:
5201 TM.tmPitchAndFamily |= FF_SCRIPT;
5203 case PAN_FAMILY_DECORATIVE:
5204 case PAN_FAMILY_PICTORIAL:
5205 TM.tmPitchAndFamily |= FF_DECORATIVE;
5207 case PAN_FAMILY_TEXT_DISPLAY:
5208 if(TM.tmPitchAndFamily == 0) /* fixed */
5209 TM.tmPitchAndFamily = FF_MODERN;
5211 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
5212 case PAN_SERIF_NORMAL_SANS:
5213 case PAN_SERIF_OBTUSE_SANS:
5214 case PAN_SERIF_PERP_SANS:
5215 TM.tmPitchAndFamily |= FF_SWISS;
5218 TM.tmPitchAndFamily |= FF_ROMAN;
5223 TM.tmPitchAndFamily |= FF_DONTCARE;
5226 if(FT_IS_SCALABLE(ft_face))
5227 TM.tmPitchAndFamily |= TMPF_VECTOR;
5229 if(FT_IS_SFNT(ft_face))
5231 if (font->ntmFlags & NTM_PS_OPENTYPE)
5232 TM.tmPitchAndFamily |= TMPF_DEVICE;
5234 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5237 TM.tmCharSet = font->charset;
5239 font->potm->otmFiller = 0;
5240 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5241 font->potm->otmfsSelection = pOS2->fsSelection;
5242 font->potm->otmfsType = pOS2->fsType;
5243 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5244 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5245 font->potm->otmItalicAngle = 0; /* POST table */
5246 font->potm->otmEMSquare = ft_face->units_per_EM;
5247 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5248 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5249 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5250 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5251 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5252 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5253 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5254 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5255 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5256 font->potm->otmMacAscent = TM.tmAscent;
5257 font->potm->otmMacDescent = -TM.tmDescent;
5258 font->potm->otmMacLineGap = font->potm->otmLineGap;
5259 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5260 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5261 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5262 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5263 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5264 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5265 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5266 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5267 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5268 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5269 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5271 font->potm->otmsUnderscoreSize = 0;
5272 font->potm->otmsUnderscorePosition = 0;
5274 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5275 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5279 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5280 cp = (char*)font->potm + sizeof(*font->potm);
5281 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5282 strcpyW((WCHAR*)cp, family_nameW);
5284 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5285 strcpyW((WCHAR*)cp, style_nameW);
5287 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5288 strcpyW((WCHAR*)cp, family_nameW);
5289 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5290 strcatW((WCHAR*)cp, spaceW);
5291 strcatW((WCHAR*)cp, style_nameW);
5292 cp += lenfam + lensty;
5295 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5296 strcpyW((WCHAR*)cp, family_nameW);
5297 strcatW((WCHAR*)cp, spaceW);
5298 strcatW((WCHAR*)cp, style_nameW);
5301 if(potm && needed <= cbSize)
5303 memcpy(potm, font->potm, font->potm->otmSize);
5304 scale_outline_font_metrics(font, potm);
5308 HeapFree(GetProcessHeap(), 0, style_nameW);
5309 HeapFree(GetProcessHeap(), 0, family_nameW);
5311 LeaveCriticalSection( &freetype_cs );
5315 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5317 HFONTLIST *hfontlist;
5318 child->font = alloc_font();
5319 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5320 if(!child->font->ft_face)
5322 free_font(child->font);
5327 child->font->ntmFlags = child->face->ntmFlags;
5328 child->font->orientation = font->orientation;
5329 child->font->scale_y = font->scale_y;
5330 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5331 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5332 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5333 child->font->base_font = font;
5334 list_add_head(&child_font_list, &child->font->entry);
5335 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5339 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5342 CHILD_FONT *child_font;
5345 font = font->base_font;
5347 *linked_font = font;
5349 if((*glyph = get_glyph_index(font, c)))
5352 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5354 if(!child_font->font)
5355 if(!load_child_font(font, child_font))
5358 if(!child_font->font->ft_face)
5360 g = get_glyph_index(child_font->font, c);
5364 *linked_font = child_font->font;
5371 /*************************************************************
5372 * WineEngGetCharWidth
5375 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5380 FT_UInt glyph_index;
5381 GdiFont *linked_font;
5383 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5385 EnterCriticalSection( &freetype_cs );
5386 for(c = firstChar; c <= lastChar; c++) {
5387 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5388 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5389 &gm, 0, NULL, NULL);
5390 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5392 LeaveCriticalSection( &freetype_cs );
5396 /*************************************************************
5397 * WineEngGetCharABCWidths
5400 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5405 FT_UInt glyph_index;
5406 GdiFont *linked_font;
5408 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5410 if(!FT_IS_SCALABLE(font->ft_face))
5413 EnterCriticalSection( &freetype_cs );
5415 for(c = firstChar; c <= lastChar; c++) {
5416 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5417 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5418 &gm, 0, NULL, NULL);
5419 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5420 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5421 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5422 FONT_GM(linked_font,glyph_index)->bbx;
5424 LeaveCriticalSection( &freetype_cs );
5428 /*************************************************************
5429 * WineEngGetCharABCWidthsI
5432 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5437 FT_UInt glyph_index;
5438 GdiFont *linked_font;
5440 if(!FT_HAS_HORIZONTAL(font->ft_face))
5443 EnterCriticalSection( &freetype_cs );
5445 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5447 for(c = firstChar; c < firstChar+count; c++) {
5448 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5449 &gm, 0, NULL, NULL);
5450 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5451 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5452 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5453 - FONT_GM(linked_font,c)->bbx;
5456 for(c = 0; c < count; c++) {
5457 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5458 &gm, 0, NULL, NULL);
5459 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5460 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5461 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5462 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5465 LeaveCriticalSection( &freetype_cs );
5469 /*************************************************************
5470 * WineEngGetTextExtentExPoint
5473 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5474 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5480 FT_UInt glyph_index;
5481 GdiFont *linked_font;
5483 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5486 EnterCriticalSection( &freetype_cs );
5489 WineEngGetTextMetrics(font, &tm);
5490 size->cy = tm.tmHeight;
5492 for(idx = 0; idx < count; idx++) {
5493 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5494 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5495 &gm, 0, NULL, NULL);
5496 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5498 if (! pnfit || ext <= max_ext) {
5508 LeaveCriticalSection( &freetype_cs );
5509 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5513 /*************************************************************
5514 * WineEngGetTextExtentExPointI
5517 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5518 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5525 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5527 EnterCriticalSection( &freetype_cs );
5530 WineEngGetTextMetrics(font, &tm);
5531 size->cy = tm.tmHeight;
5533 for(idx = 0; idx < count; idx++) {
5534 WineEngGetGlyphOutline(font, indices[idx],
5535 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
5537 size->cx += FONT_GM(font,indices[idx])->adv;
5539 if (! pnfit || ext <= max_ext) {
5549 LeaveCriticalSection( &freetype_cs );
5550 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5554 /*************************************************************
5555 * WineEngGetFontData
5558 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5561 FT_Face ft_face = font->ft_face;
5565 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5566 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
5567 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
5569 if(!FT_IS_SFNT(ft_face))
5577 if(table) { /* MS tags differ in endianness from FT ones */
5578 table = table >> 24 | table << 24 |
5579 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
5582 /* make sure value of len is the value freetype says it needs */
5585 FT_ULong needed = 0;
5586 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
5587 if( !err && needed < len) len = needed;
5589 err = load_sfnt_table(ft_face, table, offset, buf, &len);
5592 TRACE("Can't find table %c%c%c%c\n",
5593 /* bytes were reversed */
5594 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
5595 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
5601 /*************************************************************
5602 * WineEngGetTextFace
5605 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5607 INT n = strlenW(font->name) + 1;
5609 lstrcpynW(str, font->name, count);
5610 return min(count, n);
5615 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5617 if (fs) *fs = font->fs;
5618 return font->charset;
5621 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5623 GdiFont *font = dc->gdiFont, *linked_font;
5624 struct list *first_hfont;
5627 EnterCriticalSection( &freetype_cs );
5628 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
5629 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
5630 if(font == linked_font)
5631 *new_hfont = dc->hFont;
5634 first_hfont = list_head(&linked_font->hfontlist);
5635 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
5637 LeaveCriticalSection( &freetype_cs );
5641 /* Retrieve a list of supported Unicode ranges for a given font.
5642 * Can be called with NULL gs to calculate the buffer size. Returns
5643 * the number of ranges found.
5645 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
5647 DWORD num_ranges = 0;
5649 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5652 FT_ULong char_code, char_code_prev;
5655 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
5657 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5658 face->num_glyphs, glyph_code, char_code);
5660 if (!glyph_code) return 0;
5664 gs->ranges[0].wcLow = (USHORT)char_code;
5665 gs->ranges[0].cGlyphs = 0;
5666 gs->cGlyphsSupported = 0;
5672 if (char_code < char_code_prev)
5674 ERR("expected increasing char code from FT_Get_Next_Char\n");
5677 if (char_code - char_code_prev > 1)
5682 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5683 gs->ranges[num_ranges - 1].cGlyphs = 1;
5684 gs->cGlyphsSupported++;
5689 gs->ranges[num_ranges - 1].cGlyphs++;
5690 gs->cGlyphsSupported++;
5692 char_code_prev = char_code;
5693 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5697 FIXME("encoding %u not supported\n", face->charmap->encoding);
5702 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5705 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
5707 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5710 glyphset->cbThis = size;
5711 glyphset->cRanges = num_ranges;
5716 /*************************************************************
5719 BOOL WineEngFontIsLinked(GdiFont *font)
5722 EnterCriticalSection( &freetype_cs );
5723 ret = !list_empty(&font->child_fonts);
5724 LeaveCriticalSection( &freetype_cs );
5728 static BOOL is_hinting_enabled(void)
5730 /* Use the >= 2.2.0 function if available */
5731 if(pFT_Get_TrueType_Engine_Type)
5733 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
5734 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
5736 #ifdef FT_DRIVER_HAS_HINTER
5741 /* otherwise if we've been compiled with < 2.2.0 headers
5742 use the internal macro */
5743 mod = pFT_Get_Module(library, "truetype");
5744 if(mod && FT_DRIVER_HAS_HINTER(mod))
5752 /*************************************************************************
5753 * GetRasterizerCaps (GDI32.@)
5755 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5757 static int hinting = -1;
5761 hinting = is_hinting_enabled();
5762 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
5765 lprs->nSize = sizeof(RASTERIZER_STATUS);
5766 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
5767 lprs->nLanguageID = 0;
5771 /*************************************************************
5772 * WineEngRealizationInfo
5774 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
5776 FIXME("(%p, %p): stub!\n", font, info);
5779 if(FT_IS_SCALABLE(font->ft_face))
5782 info->cache_num = font->cache_num;
5783 info->unknown2 = -1;
5787 /*************************************************************************
5788 * Kerning support for TrueType fonts
5790 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5792 struct TT_kern_table
5798 struct TT_kern_subtable
5807 USHORT horizontal : 1;
5809 USHORT cross_stream: 1;
5810 USHORT override : 1;
5811 USHORT reserved1 : 4;
5817 struct TT_format0_kern_subtable
5821 USHORT entrySelector;
5832 static DWORD parse_format0_kern_subtable(GdiFont *font,
5833 const struct TT_format0_kern_subtable *tt_f0_ks,
5834 const USHORT *glyph_to_char,
5835 KERNINGPAIR *kern_pair, DWORD cPairs)
5838 const struct TT_kern_pair *tt_kern_pair;
5840 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
5842 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
5844 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5845 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
5846 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
5848 if (!kern_pair || !cPairs)
5851 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
5853 nPairs = min(nPairs, cPairs);
5855 for (i = 0; i < nPairs; i++)
5857 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
5858 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
5859 /* this algorithm appears to better match what Windows does */
5860 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
5861 if (kern_pair->iKernAmount < 0)
5863 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
5864 kern_pair->iKernAmount -= font->ppem;
5866 else if (kern_pair->iKernAmount > 0)
5868 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
5869 kern_pair->iKernAmount += font->ppem;
5871 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
5873 TRACE("left %u right %u value %d\n",
5874 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
5878 TRACE("copied %u entries\n", nPairs);
5882 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5886 const struct TT_kern_table *tt_kern_table;
5887 const struct TT_kern_subtable *tt_kern_subtable;
5889 USHORT *glyph_to_char;
5891 EnterCriticalSection( &freetype_cs );
5892 if (font->total_kern_pairs != (DWORD)-1)
5894 if (cPairs && kern_pair)
5896 cPairs = min(cPairs, font->total_kern_pairs);
5897 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5898 LeaveCriticalSection( &freetype_cs );
5901 LeaveCriticalSection( &freetype_cs );
5902 return font->total_kern_pairs;
5905 font->total_kern_pairs = 0;
5907 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5909 if (length == GDI_ERROR)
5911 TRACE("no kerning data in the font\n");
5912 LeaveCriticalSection( &freetype_cs );
5916 buf = HeapAlloc(GetProcessHeap(), 0, length);
5919 WARN("Out of memory\n");
5920 LeaveCriticalSection( &freetype_cs );
5924 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5926 /* build a glyph index to char code map */
5927 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5930 WARN("Out of memory allocating a glyph index to char code map\n");
5931 HeapFree(GetProcessHeap(), 0, buf);
5932 LeaveCriticalSection( &freetype_cs );
5936 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5942 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5944 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5945 font->ft_face->num_glyphs, glyph_code, char_code);
5949 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5951 /* FIXME: This doesn't match what Windows does: it does some fancy
5952 * things with duplicate glyph index to char code mappings, while
5953 * we just avoid overriding existing entries.
5955 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5956 glyph_to_char[glyph_code] = (USHORT)char_code;
5958 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5965 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5966 for (n = 0; n <= 65535; n++)
5967 glyph_to_char[n] = (USHORT)n;
5970 tt_kern_table = buf;
5971 nTables = GET_BE_WORD(tt_kern_table->nTables);
5972 TRACE("version %u, nTables %u\n",
5973 GET_BE_WORD(tt_kern_table->version), nTables);
5975 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5977 for (i = 0; i < nTables; i++)
5979 struct TT_kern_subtable tt_kern_subtable_copy;
5981 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5982 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5983 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5985 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5986 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
5987 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
5989 /* According to the TrueType specification this is the only format
5990 * that will be properly interpreted by Windows and OS/2
5992 if (tt_kern_subtable_copy.coverage.bits.format == 0)
5994 DWORD new_chunk, old_total = font->total_kern_pairs;
5996 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5997 glyph_to_char, NULL, 0);
5998 font->total_kern_pairs += new_chunk;
6000 if (!font->kern_pairs)
6001 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6002 font->total_kern_pairs * sizeof(*font->kern_pairs));
6004 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6005 font->total_kern_pairs * sizeof(*font->kern_pairs));
6007 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6008 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6011 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6013 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6016 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6017 HeapFree(GetProcessHeap(), 0, buf);
6019 if (cPairs && kern_pair)
6021 cPairs = min(cPairs, font->total_kern_pairs);
6022 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6023 LeaveCriticalSection( &freetype_cs );
6026 LeaveCriticalSection( &freetype_cs );
6027 return font->total_kern_pairs;
6030 #else /* HAVE_FREETYPE */
6032 /*************************************************************************/
6034 BOOL WineEngInit(void)
6038 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6042 BOOL WineEngDestroyFontInstance(HFONT hfont)
6047 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6052 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6053 LPWORD pgi, DWORD flags)
6058 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6059 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6062 ERR("called but we don't have FreeType\n");
6066 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6068 ERR("called but we don't have FreeType\n");
6072 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6073 OUTLINETEXTMETRICW *potm)
6075 ERR("called but we don't have FreeType\n");
6079 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6082 ERR("called but we don't have FreeType\n");
6086 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6089 ERR("called but we don't have FreeType\n");
6093 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6096 ERR("called but we don't have FreeType\n");
6100 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6101 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6103 ERR("called but we don't have FreeType\n");
6107 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6108 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6110 ERR("called but we don't have FreeType\n");
6114 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6117 ERR("called but we don't have FreeType\n");
6121 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6123 ERR("called but we don't have FreeType\n");
6127 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6133 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6139 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6145 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6148 return DEFAULT_CHARSET;
6151 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6156 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6158 FIXME("(%p, %p): stub\n", font, glyphset);
6162 BOOL WineEngFontIsLinked(GdiFont *font)
6167 /*************************************************************************
6168 * GetRasterizerCaps (GDI32.@)
6170 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6172 lprs->nSize = sizeof(RASTERIZER_STATUS);
6174 lprs->nLanguageID = 0;
6178 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6180 ERR("called but we don't have FreeType\n");
6184 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6186 ERR("called but we don't have FreeType\n");
6190 #endif /* HAVE_FREETYPE */