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);
1030 /*****************************************************************
1031 * get_name_table_entry
1033 * Supply the platform, encoding, language and name ids in req
1034 * and if the name exists the function will fill in the string
1035 * and string_len members. The string is owned by FreeType so
1036 * don't free it. Returns TRUE if the name is found else FALSE.
1038 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1041 FT_UInt num_names, name_index;
1043 if(FT_IS_SFNT(ft_face))
1045 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1047 for(name_index = 0; name_index < num_names; name_index++)
1049 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1051 if((name.platform_id == req->platform_id) &&
1052 (name.encoding_id == req->encoding_id) &&
1053 (name.language_id == req->language_id) &&
1054 (name.name_id == req->name_id))
1056 req->string = name.string;
1057 req->string_len = name.string_len;
1064 req->string_len = 0;
1068 static WCHAR *get_familyname(FT_Face ft_face)
1070 WCHAR *family = NULL;
1073 name.platform_id = TT_PLATFORM_MICROSOFT;
1074 name.encoding_id = TT_MS_ID_UNICODE_CS;
1075 name.language_id = GetUserDefaultLCID();
1076 name.name_id = TT_NAME_ID_FONT_FAMILY;
1078 if(get_name_table_entry(ft_face, &name))
1082 /* String is not nul terminated and string_len is a byte length. */
1083 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1084 for(i = 0; i < name.string_len / 2; i++)
1086 WORD *tmp = (WORD *)&name.string[i * 2];
1087 family[i] = GET_BE_WORD(*tmp);
1090 TRACE("Got localised name %s\n", debugstr_w(family));
1097 /*****************************************************************
1100 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1101 * of FreeType that don't export this function.
1104 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1109 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1110 if(pFT_Load_Sfnt_Table)
1112 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1114 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1115 else /* Do it the hard way */
1117 TT_Face tt_face = (TT_Face) ft_face;
1118 SFNT_Interface *sfnt;
1119 if (FT_Version.major==2 && FT_Version.minor==0)
1122 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1126 /* A field was added in the middle of the structure in 2.1.x */
1127 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1129 err = sfnt->load_any(tt_face, table, offset, buf, len);
1137 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1138 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1139 "Please upgrade your freetype library.\n");
1142 err = FT_Err_Unimplemented_Feature;
1148 static inline int TestStyles(DWORD flags, DWORD styles)
1150 return (flags & styles) == styles;
1153 static int StyleOrdering(Face *face)
1155 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1157 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1159 if (TestStyles(face->ntmFlags, NTM_BOLD))
1161 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1164 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1165 debugstr_w(face->family->FamilyName),
1166 debugstr_w(face->StyleName),
1172 /* Add a style of face to a font family using an ordering of the list such
1173 that regular fonts come before bold and italic, and single styles come
1174 before compound styles. */
1175 static void AddFaceToFamily(Face *face, Family *family)
1179 LIST_FOR_EACH( entry, &family->faces )
1181 Face *ent = LIST_ENTRY(entry, Face, entry);
1182 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1184 list_add_before( entry, &face->entry );
1187 #define ADDFONT_EXTERNAL_FONT 0x01
1188 #define ADDFONT_FORCE_BITMAP 0x02
1189 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1193 TT_Header *pHeader = NULL;
1194 WCHAR *english_family, *localised_family, *StyleW;
1198 struct list *family_elem_ptr, *face_elem_ptr;
1200 FT_Long face_index = 0, num_faces;
1201 #ifdef HAVE_FREETYPE_FTWINFNT_H
1202 FT_WinFNT_HeaderRec winfnt_header;
1204 int i, bitmap_num, internal_leading;
1207 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1208 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1210 #ifdef HAVE_CARBON_CARBON_H
1211 if(file && !fake_family)
1213 char **mac_list = expand_mac_font(file);
1216 BOOL had_one = FALSE;
1218 for(cursor = mac_list; *cursor; cursor++)
1221 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1222 HeapFree(GetProcessHeap(), 0, *cursor);
1224 HeapFree(GetProcessHeap(), 0, mac_list);
1229 #endif /* HAVE_CARBON_CARBON_H */
1232 char *family_name = fake_family;
1236 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1237 err = pFT_New_Face(library, file, face_index, &ft_face);
1240 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1241 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1245 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1249 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*/
1250 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1251 pFT_Done_Face(ft_face);
1255 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1256 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1257 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1258 pFT_Done_Face(ft_face);
1262 if(FT_IS_SFNT(ft_face))
1264 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1265 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1266 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1268 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1269 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1270 pFT_Done_Face(ft_face);
1274 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1275 we don't want to load these. */
1276 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1280 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1282 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1283 pFT_Done_Face(ft_face);
1289 if(!ft_face->family_name || !ft_face->style_name) {
1290 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1291 pFT_Done_Face(ft_face);
1295 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1297 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1298 pFT_Done_Face(ft_face);
1304 localised_family = get_familyname(ft_face);
1305 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1307 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1308 HeapFree(GetProcessHeap(), 0, localised_family);
1309 num_faces = ft_face->num_faces;
1310 pFT_Done_Face(ft_face);
1313 HeapFree(GetProcessHeap(), 0, localised_family);
1317 family_name = ft_face->family_name;
1321 My_FT_Bitmap_Size *size = NULL;
1324 if(!FT_IS_SCALABLE(ft_face))
1325 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1327 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1328 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1329 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1331 localised_family = NULL;
1333 localised_family = get_familyname(ft_face);
1334 if(localised_family && !strcmpW(localised_family, english_family)) {
1335 HeapFree(GetProcessHeap(), 0, localised_family);
1336 localised_family = NULL;
1341 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1342 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1343 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1348 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1349 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1350 list_init(&family->faces);
1351 list_add_tail(&font_list, &family->entry);
1353 if(localised_family) {
1354 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1355 subst->from.name = strdupW(english_family);
1356 subst->from.charset = -1;
1357 subst->to.name = strdupW(localised_family);
1358 subst->to.charset = -1;
1359 add_font_subst(&font_subst_list, subst, 0);
1362 HeapFree(GetProcessHeap(), 0, localised_family);
1363 HeapFree(GetProcessHeap(), 0, english_family);
1365 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1366 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1367 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1369 internal_leading = 0;
1370 memset(&fs, 0, sizeof(fs));
1372 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1374 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1375 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1376 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1377 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1378 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1379 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1380 if(pOS2->version == 0) {
1383 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1384 fs.fsCsb[0] |= FS_LATIN1;
1386 fs.fsCsb[0] |= FS_SYMBOL;
1389 #ifdef HAVE_FREETYPE_FTWINFNT_H
1390 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1392 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1393 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1394 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1396 internal_leading = winfnt_header.internal_leading;
1400 face_elem_ptr = list_head(&family->faces);
1401 while(face_elem_ptr) {
1402 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1403 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1404 if(!strcmpW(face->StyleName, StyleW) &&
1405 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1406 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1407 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1408 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1411 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1412 HeapFree(GetProcessHeap(), 0, StyleW);
1413 pFT_Done_Face(ft_face);
1416 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1417 TRACE("Original font is newer so skipping this one\n");
1418 HeapFree(GetProcessHeap(), 0, StyleW);
1419 pFT_Done_Face(ft_face);
1422 TRACE("Replacing original with this one\n");
1423 list_remove(&face->entry);
1424 HeapFree(GetProcessHeap(), 0, face->file);
1425 HeapFree(GetProcessHeap(), 0, face->StyleName);
1426 HeapFree(GetProcessHeap(), 0, face);
1431 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1432 face->cached_enum_data = NULL;
1433 face->StyleName = StyleW;
1436 face->file = strdupA(file);
1437 face->font_data_ptr = NULL;
1438 face->font_data_size = 0;
1443 face->font_data_ptr = font_data_ptr;
1444 face->font_data_size = font_data_size;
1446 face->face_index = face_index;
1448 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1449 face->ntmFlags |= NTM_ITALIC;
1450 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1451 face->ntmFlags |= NTM_BOLD;
1452 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1453 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1454 face->family = family;
1455 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1457 memset(&face->fs_links, 0, sizeof(face->fs_links));
1459 if(FT_IS_SCALABLE(ft_face)) {
1460 memset(&face->size, 0, sizeof(face->size));
1461 face->scalable = TRUE;
1463 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1464 size->height, size->width, size->size >> 6,
1465 size->x_ppem >> 6, size->y_ppem >> 6);
1466 face->size.height = size->height;
1467 face->size.width = size->width;
1468 face->size.size = size->size;
1469 face->size.x_ppem = size->x_ppem;
1470 face->size.y_ppem = size->y_ppem;
1471 face->size.internal_leading = internal_leading;
1472 face->scalable = FALSE;
1475 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1477 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1479 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1480 face->ntmFlags |= NTM_PS_OPENTYPE;
1483 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1484 face->fs.fsCsb[0], face->fs.fsCsb[1],
1485 face->fs.fsUsb[0], face->fs.fsUsb[1],
1486 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1489 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1490 for(i = 0; i < ft_face->num_charmaps; i++) {
1491 switch(ft_face->charmaps[i]->encoding) {
1492 case FT_ENCODING_UNICODE:
1493 case FT_ENCODING_APPLE_ROMAN:
1494 face->fs.fsCsb[0] |= FS_LATIN1;
1496 case FT_ENCODING_MS_SYMBOL:
1497 face->fs.fsCsb[0] |= FS_SYMBOL;
1505 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1506 have_installed_roman_font = TRUE;
1508 AddFaceToFamily(face, family);
1510 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1512 num_faces = ft_face->num_faces;
1513 pFT_Done_Face(ft_face);
1514 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1515 debugstr_w(StyleW));
1516 } while(num_faces > ++face_index);
1520 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1522 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1525 static void DumpFontList(void)
1529 struct list *family_elem_ptr, *face_elem_ptr;
1531 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1532 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1533 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1534 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1535 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1536 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1538 TRACE(" %d", face->size.height);
1545 /***********************************************************
1546 * The replacement list is a way to map an entire font
1547 * family onto another family. For example adding
1549 * [HKCU\Software\Wine\Fonts\Replacements]
1550 * "Wingdings"="Winedings"
1552 * would enumerate the Winedings font both as Winedings and
1553 * Wingdings. However if a real Wingdings font is present the
1554 * replacement does not take place.
1557 static void LoadReplaceList(void)
1560 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1565 struct list *family_elem_ptr, *face_elem_ptr;
1568 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1569 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1571 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1572 &valuelen, &datalen, NULL, NULL);
1574 valuelen++; /* returned value doesn't include room for '\0' */
1575 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1576 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1580 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1581 &dlen) == ERROR_SUCCESS) {
1582 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1583 /* "NewName"="Oldname" */
1584 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1586 /* Find the old family and hence all of the font files
1588 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1589 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1590 if(!strcmpiW(family->FamilyName, data)) {
1591 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1592 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1593 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1594 debugstr_w(face->StyleName), familyA);
1595 /* Now add a new entry with the new family name */
1596 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1601 /* reset dlen and vlen */
1605 HeapFree(GetProcessHeap(), 0, data);
1606 HeapFree(GetProcessHeap(), 0, value);
1611 /*************************************************************
1614 static BOOL init_system_links(void)
1616 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1617 'W','i','n','d','o','w','s',' ','N','T','\\',
1618 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1619 'S','y','s','t','e','m','L','i','n','k',0};
1622 DWORD type, max_val, max_data, val_len, data_len, index;
1623 WCHAR *value, *data;
1624 WCHAR *entry, *next;
1625 SYSTEM_LINKS *font_link, *system_font_link;
1626 CHILD_FONT *child_font;
1627 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1628 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1629 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1635 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1637 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1638 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1639 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1640 val_len = max_val + 1;
1641 data_len = max_data;
1643 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1645 TRACE("%s:\n", debugstr_w(value));
1647 memset(&fs, 0, sizeof(fs));
1648 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1649 psub = get_font_subst(&font_subst_list, value, -1);
1650 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1651 list_init(&font_link->links);
1652 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1655 CHILD_FONT *child_font;
1657 TRACE("\t%s\n", debugstr_w(entry));
1659 next = entry + strlenW(entry) + 1;
1661 face_name = strchrW(entry, ',');
1665 while(isspaceW(*face_name))
1668 psub = get_font_subst(&font_subst_list, face_name, -1);
1670 face_name = psub->to.name;
1672 face = find_face_from_filename(entry, face_name);
1675 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1679 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1680 child_font->face = face;
1681 child_font->font = NULL;
1682 fs.fsCsb[0] |= face->fs.fsCsb[0];
1683 fs.fsCsb[1] |= face->fs.fsCsb[1];
1684 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1685 list_add_tail(&font_link->links, &child_font->entry);
1687 family = find_family_from_name(font_link->font_name);
1690 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1692 face->fs_links = fs;
1695 list_add_tail(&system_links, &font_link->entry);
1696 val_len = max_val + 1;
1697 data_len = max_data;
1700 HeapFree(GetProcessHeap(), 0, value);
1701 HeapFree(GetProcessHeap(), 0, data);
1705 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1708 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1709 system_font_link->font_name = strdupW(System);
1710 list_init(&system_font_link->links);
1712 face = find_face_from_filename(tahoma_ttf, Tahoma);
1715 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1716 child_font->face = face;
1717 child_font->font = NULL;
1718 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1719 list_add_tail(&system_font_link->links, &child_font->entry);
1721 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1723 if(!strcmpiW(font_link->font_name, Tahoma))
1725 CHILD_FONT *font_link_entry;
1726 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1728 CHILD_FONT *new_child;
1729 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1730 new_child->face = font_link_entry->face;
1731 new_child->font = NULL;
1732 list_add_tail(&system_font_link->links, &new_child->entry);
1737 list_add_tail(&system_links, &system_font_link->entry);
1741 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1744 struct dirent *dent;
1745 char path[MAX_PATH];
1747 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1749 dir = opendir(dirname);
1751 WARN("Can't open directory %s\n", debugstr_a(dirname));
1754 while((dent = readdir(dir)) != NULL) {
1755 struct stat statbuf;
1757 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1760 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1762 sprintf(path, "%s/%s", dirname, dent->d_name);
1764 if(stat(path, &statbuf) == -1)
1766 WARN("Can't stat %s\n", debugstr_a(path));
1769 if(S_ISDIR(statbuf.st_mode))
1770 ReadFontDir(path, external_fonts);
1772 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1778 static void load_fontconfig_fonts(void)
1780 #ifdef SONAME_LIBFONTCONFIG
1781 void *fc_handle = NULL;
1790 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1792 TRACE("Wine cannot find the fontconfig library (%s).\n",
1793 SONAME_LIBFONTCONFIG);
1796 #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;}
1797 LOAD_FUNCPTR(FcConfigGetCurrent);
1798 LOAD_FUNCPTR(FcFontList);
1799 LOAD_FUNCPTR(FcFontSetDestroy);
1800 LOAD_FUNCPTR(FcInit);
1801 LOAD_FUNCPTR(FcObjectSetAdd);
1802 LOAD_FUNCPTR(FcObjectSetCreate);
1803 LOAD_FUNCPTR(FcObjectSetDestroy);
1804 LOAD_FUNCPTR(FcPatternCreate);
1805 LOAD_FUNCPTR(FcPatternDestroy);
1806 LOAD_FUNCPTR(FcPatternGetBool);
1807 LOAD_FUNCPTR(FcPatternGetString);
1810 if(!pFcInit()) return;
1812 config = pFcConfigGetCurrent();
1813 pat = pFcPatternCreate();
1814 os = pFcObjectSetCreate();
1815 pFcObjectSetAdd(os, FC_FILE);
1816 pFcObjectSetAdd(os, FC_SCALABLE);
1817 fontset = pFcFontList(config, pat, os);
1818 if(!fontset) return;
1819 for(i = 0; i < fontset->nfont; i++) {
1822 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1824 TRACE("fontconfig: %s\n", file);
1826 /* We're just interested in OT/TT fonts for now, so this hack just
1827 picks up the scalable fonts without extensions .pf[ab] to save time
1828 loading every other font */
1830 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1832 TRACE("not scalable\n");
1836 len = strlen( file );
1837 if(len < 4) continue;
1838 ext = &file[ len - 3 ];
1839 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1840 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1842 pFcFontSetDestroy(fontset);
1843 pFcObjectSetDestroy(os);
1844 pFcPatternDestroy(pat);
1850 static BOOL load_font_from_data_dir(LPCWSTR file)
1853 const char *data_dir = wine_get_data_dir();
1855 if (!data_dir) data_dir = wine_get_build_dir();
1862 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1864 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1866 strcpy(unix_name, data_dir);
1867 strcat(unix_name, "/fonts/");
1869 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1871 EnterCriticalSection( &freetype_cs );
1872 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1873 LeaveCriticalSection( &freetype_cs );
1874 HeapFree(GetProcessHeap(), 0, unix_name);
1879 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1881 static const WCHAR slashW[] = {'\\','\0'};
1883 WCHAR windowsdir[MAX_PATH];
1886 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1887 strcatW(windowsdir, fontsW);
1888 strcatW(windowsdir, slashW);
1889 strcatW(windowsdir, file);
1890 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1891 EnterCriticalSection( &freetype_cs );
1892 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1893 LeaveCriticalSection( &freetype_cs );
1894 HeapFree(GetProcessHeap(), 0, unixname);
1899 static void load_system_fonts(void)
1902 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1903 const WCHAR * const *value;
1905 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1908 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1909 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1910 strcatW(windowsdir, fontsW);
1911 for(value = SystemFontValues; *value; value++) {
1912 dlen = sizeof(data);
1913 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1917 sprintfW(pathW, fmtW, windowsdir, data);
1918 if((unixname = wine_get_unix_file_name(pathW))) {
1919 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1920 HeapFree(GetProcessHeap(), 0, unixname);
1923 load_font_from_data_dir(data);
1930 /*************************************************************
1932 * This adds registry entries for any externally loaded fonts
1933 * (fonts from fontconfig or FontDirs). It also deletes entries
1934 * of no longer existing fonts.
1937 static void update_reg_entries(void)
1939 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1944 struct list *family_elem_ptr, *face_elem_ptr;
1946 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1947 static const WCHAR spaceW[] = {' ', '\0'};
1950 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1951 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1952 ERR("Can't create Windows font reg key\n");
1956 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1957 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1958 ERR("Can't create Windows font reg key\n");
1962 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1963 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1964 ERR("Can't create external font reg key\n");
1968 /* enumerate the fonts and add external ones to the two keys */
1970 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1971 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1972 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1973 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1974 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1975 if(!face->external) continue;
1977 if (!(face->ntmFlags & NTM_REGULAR))
1978 len = len_fam + strlenW(face->StyleName) + 1;
1979 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1980 strcpyW(valueW, family->FamilyName);
1981 if(len != len_fam) {
1982 strcatW(valueW, spaceW);
1983 strcatW(valueW, face->StyleName);
1985 strcatW(valueW, TrueType);
1987 file = wine_get_dos_file_name(face->file);
1989 len = strlenW(file) + 1;
1992 if((path = strrchr(face->file, '/')) == NULL)
1996 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1998 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1999 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2001 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2002 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2003 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2005 HeapFree(GetProcessHeap(), 0, file);
2006 HeapFree(GetProcessHeap(), 0, valueW);
2010 if(external_key) RegCloseKey(external_key);
2011 if(win9x_key) RegCloseKey(win9x_key);
2012 if(winnt_key) RegCloseKey(winnt_key);
2016 static void delete_external_font_keys(void)
2018 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2019 DWORD dlen, vlen, datalen, valuelen, i, type;
2023 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2024 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2025 ERR("Can't create Windows font reg key\n");
2029 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2030 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2031 ERR("Can't create Windows font reg key\n");
2035 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2036 ERR("Can't create external font reg key\n");
2040 /* Delete all external fonts added last time */
2042 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2043 &valuelen, &datalen, NULL, NULL);
2044 valuelen++; /* returned value doesn't include room for '\0' */
2045 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2046 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2048 dlen = datalen * sizeof(WCHAR);
2051 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2052 &dlen) == ERROR_SUCCESS) {
2054 RegDeleteValueW(winnt_key, valueW);
2055 RegDeleteValueW(win9x_key, valueW);
2056 /* reset dlen and vlen */
2060 HeapFree(GetProcessHeap(), 0, data);
2061 HeapFree(GetProcessHeap(), 0, valueW);
2063 /* Delete the old external fonts key */
2064 RegCloseKey(external_key);
2065 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2068 if(win9x_key) RegCloseKey(win9x_key);
2069 if(winnt_key) RegCloseKey(winnt_key);
2072 /*************************************************************
2073 * WineEngAddFontResourceEx
2076 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2079 if (ft_handle) /* do it only if we have freetype up and running */
2084 FIXME("Ignoring flags %x\n", flags);
2086 if((unixname = wine_get_unix_file_name(file)))
2088 EnterCriticalSection( &freetype_cs );
2089 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2090 LeaveCriticalSection( &freetype_cs );
2091 HeapFree(GetProcessHeap(), 0, unixname);
2093 if (!ret && !strchrW(file, '\\')) {
2094 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2095 ret = load_font_from_winfonts_dir(file);
2097 /* Try in datadir/fonts (or builddir/fonts),
2098 * needed for Magic the Gathering Online
2100 ret = load_font_from_data_dir(file);
2107 /*************************************************************
2108 * WineEngAddFontMemResourceEx
2111 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2113 if (ft_handle) /* do it only if we have freetype up and running */
2115 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2117 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2118 memcpy(pFontCopy, pbFont, cbFont);
2120 EnterCriticalSection( &freetype_cs );
2121 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2122 LeaveCriticalSection( &freetype_cs );
2126 TRACE("AddFontToList failed\n");
2127 HeapFree(GetProcessHeap(), 0, pFontCopy);
2130 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2131 * For now return something unique but quite random
2133 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2134 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2141 /*************************************************************
2142 * WineEngRemoveFontResourceEx
2145 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2151 static const struct nls_update_font_list
2153 UINT ansi_cp, oem_cp;
2154 const char *oem, *fixed, *system;
2155 const char *courier, *serif, *small, *sserif;
2156 /* these are for font substitutes */
2157 const char *shelldlg, *tmsrmn;
2158 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2162 const char *from, *to;
2163 } arial_0, courier_new_0, times_new_roman_0;
2164 } nls_update_font_list[] =
2166 /* Latin 1 (United States) */
2167 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2168 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2169 "Tahoma","Times New Roman",
2170 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2173 /* Latin 1 (Multilingual) */
2174 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2175 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2176 "Tahoma","Times New Roman", /* FIXME unverified */
2177 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2180 /* Eastern Europe */
2181 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2182 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2183 "Tahoma","Times New Roman", /* FIXME unverified */
2184 "Fixedsys,238", "System,238",
2185 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2186 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2187 { "Arial CE,0", "Arial,238" },
2188 { "Courier New CE,0", "Courier New,238" },
2189 { "Times New Roman CE,0", "Times New Roman,238" }
2192 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2193 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2194 "Tahoma","Times New Roman", /* FIXME unverified */
2195 "Fixedsys,204", "System,204",
2196 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2197 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2198 { "Arial Cyr,0", "Arial,204" },
2199 { "Courier New Cyr,0", "Courier New,204" },
2200 { "Times New Roman Cyr,0", "Times New Roman,204" }
2203 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2204 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2205 "Tahoma","Times New Roman", /* FIXME unverified */
2206 "Fixedsys,161", "System,161",
2207 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2208 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2209 { "Arial Greek,0", "Arial,161" },
2210 { "Courier New Greek,0", "Courier New,161" },
2211 { "Times New Roman Greek,0", "Times New Roman,161" }
2214 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2215 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2216 "Tahoma","Times New Roman", /* FIXME unverified */
2217 "Fixedsys,162", "System,162",
2218 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2219 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2220 { "Arial Tur,0", "Arial,162" },
2221 { "Courier New Tur,0", "Courier New,162" },
2222 { "Times New Roman Tur,0", "Times New Roman,162" }
2225 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2226 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2227 "Tahoma","Times New Roman", /* FIXME unverified */
2228 "Fixedsys,177", "System,177",
2229 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2230 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2234 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2235 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2236 "Tahoma","Times New Roman", /* FIXME unverified */
2237 "Fixedsys,178", "System,178",
2238 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2239 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2243 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2244 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2245 "Tahoma","Times New Roman", /* FIXME unverified */
2246 "Fixedsys,186", "System,186",
2247 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2248 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2249 { "Arial Baltic,0", "Arial,186" },
2250 { "Courier New Baltic,0", "Courier New,186" },
2251 { "Times New Roman Baltic,0", "Times New Roman,186" }
2254 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2255 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2256 "Tahoma","Times New Roman", /* FIXME unverified */
2257 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2261 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2262 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2263 "Tahoma","Times New Roman", /* FIXME unverified */
2264 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2268 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2269 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2270 "MS UI Gothic","MS Serif",
2271 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2274 /* Chinese Simplified */
2275 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2276 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2277 "Tahoma", "Times New Roman", /* FIXME unverified */
2278 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2282 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2283 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2285 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2288 /* Chinese Traditional */
2289 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2290 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2291 "PMingLiU", "MingLiU",
2292 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2297 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2299 return ( ansi_cp == 932 /* CP932 for Japanese */
2300 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2301 || ansi_cp == 949 /* CP949 for Korean */
2302 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2305 static inline HKEY create_fonts_NT_registry_key(void)
2309 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2310 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2314 static inline HKEY create_fonts_9x_registry_key(void)
2318 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2319 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2323 static inline HKEY create_config_fonts_registry_key(void)
2327 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2328 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2332 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2334 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2335 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2336 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2337 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2340 static void set_value_key(HKEY hkey, const char *name, const char *value)
2343 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2345 RegDeleteValueA(hkey, name);
2348 static void update_font_info(void)
2350 char buf[40], cpbuf[40];
2353 UINT i, ansi_cp = 0, oem_cp = 0;
2356 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2359 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2360 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2361 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2362 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2363 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2365 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2366 if (is_dbcs_ansi_cp(ansi_cp))
2367 use_default_fallback = TRUE;
2370 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2372 if (!strcmp( buf, cpbuf )) /* already set correctly */
2377 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2379 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2381 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2384 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2388 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2389 nls_update_font_list[i].oem_cp == oem_cp)
2391 hkey = create_config_fonts_registry_key();
2392 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2393 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2394 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2397 hkey = create_fonts_NT_registry_key();
2398 add_font_list(hkey, &nls_update_font_list[i]);
2401 hkey = create_fonts_9x_registry_key();
2402 add_font_list(hkey, &nls_update_font_list[i]);
2405 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2407 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2408 strlen(nls_update_font_list[i].shelldlg)+1);
2409 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2410 strlen(nls_update_font_list[i].tmsrmn)+1);
2412 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2413 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2414 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2415 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2416 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2417 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2418 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2419 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2421 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2422 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2423 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2431 /* Delete the FontSubstitutes from other locales */
2432 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2434 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2435 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2436 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2442 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2446 static BOOL init_freetype(void)
2448 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2451 "Wine cannot find the FreeType font library. To enable Wine to\n"
2452 "use TrueType fonts please install a version of FreeType greater than\n"
2453 "or equal to 2.0.5.\n"
2454 "http://www.freetype.org\n");
2458 #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;}
2460 LOAD_FUNCPTR(FT_Vector_Unit)
2461 LOAD_FUNCPTR(FT_Done_Face)
2462 LOAD_FUNCPTR(FT_Get_Char_Index)
2463 LOAD_FUNCPTR(FT_Get_Module)
2464 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2465 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2466 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2467 LOAD_FUNCPTR(FT_Init_FreeType)
2468 LOAD_FUNCPTR(FT_Load_Glyph)
2469 LOAD_FUNCPTR(FT_Matrix_Multiply)
2470 #ifndef FT_MULFIX_INLINED
2471 LOAD_FUNCPTR(FT_MulFix)
2473 LOAD_FUNCPTR(FT_New_Face)
2474 LOAD_FUNCPTR(FT_New_Memory_Face)
2475 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2476 LOAD_FUNCPTR(FT_Outline_Transform)
2477 LOAD_FUNCPTR(FT_Outline_Translate)
2478 LOAD_FUNCPTR(FT_Select_Charmap)
2479 LOAD_FUNCPTR(FT_Set_Charmap)
2480 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2481 LOAD_FUNCPTR(FT_Vector_Transform)
2484 /* Don't warn if these ones are missing */
2485 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2486 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2487 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2488 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2489 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2490 #ifdef HAVE_FREETYPE_FTWINFNT_H
2491 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2493 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2494 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2495 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2496 <= 2.0.3 has FT_Sqrt64 */
2500 if(pFT_Init_FreeType(&library) != 0) {
2501 ERR("Can't init FreeType library\n");
2502 wine_dlclose(ft_handle, NULL, 0);
2506 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2507 if (pFT_Library_Version)
2508 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2510 if (FT_Version.major<=0)
2516 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2517 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2518 ((FT_Version.minor << 8) & 0x00ff00) |
2519 ((FT_Version.patch ) & 0x0000ff);
2525 "Wine cannot find certain functions that it needs inside the FreeType\n"
2526 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2527 "FreeType to at least version 2.0.5.\n"
2528 "http://www.freetype.org\n");
2529 wine_dlclose(ft_handle, NULL, 0);
2534 /*************************************************************
2537 * Initialize FreeType library and create a list of available faces
2539 BOOL WineEngInit(void)
2541 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2542 static const WCHAR pathW[] = {'P','a','t','h',0};
2544 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2546 WCHAR windowsdir[MAX_PATH];
2549 const char *data_dir;
2553 /* update locale dependent font info in registry */
2556 if(!init_freetype()) return FALSE;
2558 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2559 ERR("Failed to create font mutex\n");
2562 WaitForSingleObject(font_mutex, INFINITE);
2564 delete_external_font_keys();
2566 /* load the system bitmap fonts */
2567 load_system_fonts();
2569 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2570 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2571 strcatW(windowsdir, fontsW);
2572 if((unixname = wine_get_unix_file_name(windowsdir)))
2574 ReadFontDir(unixname, FALSE);
2575 HeapFree(GetProcessHeap(), 0, unixname);
2578 /* load the system truetype fonts */
2579 data_dir = wine_get_data_dir();
2580 if (!data_dir) data_dir = wine_get_build_dir();
2581 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2582 strcpy(unixname, data_dir);
2583 strcat(unixname, "/fonts/");
2584 ReadFontDir(unixname, TRUE);
2585 HeapFree(GetProcessHeap(), 0, unixname);
2588 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2589 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2590 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2592 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2593 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2594 &hkey) == ERROR_SUCCESS) {
2596 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2597 &valuelen, &datalen, NULL, NULL);
2599 valuelen++; /* returned value doesn't include room for '\0' */
2600 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2601 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2604 dlen = datalen * sizeof(WCHAR);
2606 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2607 &dlen) == ERROR_SUCCESS) {
2608 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2610 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2612 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2613 HeapFree(GetProcessHeap(), 0, unixname);
2616 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2618 WCHAR pathW[MAX_PATH];
2619 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2622 sprintfW(pathW, fmtW, windowsdir, data);
2623 if((unixname = wine_get_unix_file_name(pathW)))
2625 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2626 HeapFree(GetProcessHeap(), 0, unixname);
2629 load_font_from_data_dir(data);
2631 /* reset dlen and vlen */
2636 HeapFree(GetProcessHeap(), 0, data);
2637 HeapFree(GetProcessHeap(), 0, valueW);
2641 load_fontconfig_fonts();
2643 /* then look in any directories that we've specified in the config file */
2644 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2645 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2651 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2653 len += sizeof(WCHAR);
2654 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2655 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2657 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2658 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2659 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2660 TRACE( "got font path %s\n", debugstr_a(valueA) );
2664 LPSTR next = strchr( ptr, ':' );
2665 if (next) *next++ = 0;
2666 ReadFontDir( ptr, TRUE );
2669 HeapFree( GetProcessHeap(), 0, valueA );
2671 HeapFree( GetProcessHeap(), 0, valueW );
2680 update_reg_entries();
2682 init_system_links();
2684 ReleaseMutex(font_mutex);
2689 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2692 TT_HoriHeader *pHori;
2696 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2697 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2699 if(height == 0) height = 16;
2701 /* Calc. height of EM square:
2703 * For +ve lfHeight we have
2704 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2705 * Re-arranging gives:
2706 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2708 * For -ve lfHeight we have
2710 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2711 * with il = winAscent + winDescent - units_per_em]
2716 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2717 ppem = MulDiv(ft_face->units_per_EM, height,
2718 pHori->Ascender - pHori->Descender);
2720 ppem = MulDiv(ft_face->units_per_EM, height,
2721 pOS2->usWinAscent + pOS2->usWinDescent);
2729 static struct font_mapping *map_font_file( const char *name )
2731 struct font_mapping *mapping;
2735 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2736 if (fstat( fd, &st ) == -1) goto error;
2738 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2740 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2742 mapping->refcount++;
2747 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2750 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2753 if (mapping->data == MAP_FAILED)
2755 HeapFree( GetProcessHeap(), 0, mapping );
2758 mapping->refcount = 1;
2759 mapping->dev = st.st_dev;
2760 mapping->ino = st.st_ino;
2761 mapping->size = st.st_size;
2762 list_add_tail( &mappings_list, &mapping->entry );
2770 static void unmap_font_file( struct font_mapping *mapping )
2772 if (!--mapping->refcount)
2774 list_remove( &mapping->entry );
2775 munmap( mapping->data, mapping->size );
2776 HeapFree( GetProcessHeap(), 0, mapping );
2780 static LONG load_VDMX(GdiFont*, LONG);
2782 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2789 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2793 if (!(font->mapping = map_font_file( face->file )))
2795 WARN("failed to map %s\n", debugstr_a(face->file));
2798 data_ptr = font->mapping->data;
2799 data_size = font->mapping->size;
2803 data_ptr = face->font_data_ptr;
2804 data_size = face->font_data_size;
2807 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2809 ERR("FT_New_Face rets %d\n", err);
2813 /* set it here, as load_VDMX needs it */
2814 font->ft_face = ft_face;
2816 if(FT_IS_SCALABLE(ft_face)) {
2817 /* load the VDMX table if we have one */
2818 font->ppem = load_VDMX(font, height);
2820 font->ppem = calc_ppem_for_height(ft_face, height);
2821 TRACE("height %d => ppem %d\n", height, font->ppem);
2823 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2824 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2826 font->ppem = height;
2827 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2828 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2834 static int get_nearest_charset(Face *face, int *cp)
2836 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2837 a single face with the requested charset. The idea is to check if
2838 the selected font supports the current ANSI codepage, if it does
2839 return the corresponding charset, else return the first charset */
2842 int acp = GetACP(), i;
2846 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2847 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2848 return csi.ciCharset;
2850 for(i = 0; i < 32; i++) {
2852 if(face->fs.fsCsb[0] & fs0) {
2853 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2855 return csi.ciCharset;
2858 FIXME("TCI failing on %x\n", fs0);
2862 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2863 face->fs.fsCsb[0], face->file);
2865 return DEFAULT_CHARSET;
2868 static GdiFont *alloc_font(void)
2870 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2872 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2873 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2875 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2876 ret->total_kern_pairs = (DWORD)-1;
2877 ret->kern_pairs = NULL;
2878 list_init(&ret->hfontlist);
2879 list_init(&ret->child_fonts);
2883 static void free_font(GdiFont *font)
2885 struct list *cursor, *cursor2;
2888 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2890 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2891 struct list *first_hfont;
2892 HFONTLIST *hfontlist;
2893 list_remove(cursor);
2896 first_hfont = list_head(&child->font->hfontlist);
2897 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2898 DeleteObject(hfontlist->hfont);
2899 HeapFree(GetProcessHeap(), 0, hfontlist);
2900 free_font(child->font);
2902 HeapFree(GetProcessHeap(), 0, child);
2905 if (font->ft_face) pFT_Done_Face(font->ft_face);
2906 if (font->mapping) unmap_font_file( font->mapping );
2907 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2908 HeapFree(GetProcessHeap(), 0, font->potm);
2909 HeapFree(GetProcessHeap(), 0, font->name);
2910 for (i = 0; i < font->gmsize; i++)
2911 HeapFree(GetProcessHeap(),0,font->gm[i]);
2912 HeapFree(GetProcessHeap(), 0, font->gm);
2913 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2914 HeapFree(GetProcessHeap(), 0, font);
2918 /*************************************************************
2921 * load the vdmx entry for the specified height
2924 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2925 ( ( (FT_ULong)_x4 << 24 ) | \
2926 ( (FT_ULong)_x3 << 16 ) | \
2927 ( (FT_ULong)_x2 << 8 ) | \
2930 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2945 static LONG load_VDMX(GdiFont *font, LONG height)
2949 BYTE devXRatio, devYRatio;
2950 USHORT numRecs, numRatios;
2951 DWORD result, offset = -1;
2955 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2957 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2960 /* FIXME: need the real device aspect ratio */
2964 numRecs = GET_BE_WORD(hdr[1]);
2965 numRatios = GET_BE_WORD(hdr[2]);
2967 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2968 for(i = 0; i < numRatios; i++) {
2971 offset = (3 * 2) + (i * sizeof(Ratios));
2972 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2975 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2977 if((ratio.xRatio == 0 &&
2978 ratio.yStartRatio == 0 &&
2979 ratio.yEndRatio == 0) ||
2980 (devXRatio == ratio.xRatio &&
2981 devYRatio >= ratio.yStartRatio &&
2982 devYRatio <= ratio.yEndRatio))
2984 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2985 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2986 offset = GET_BE_WORD(tmp);
2992 FIXME("No suitable ratio found\n");
2996 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2998 BYTE startsz, endsz;
3001 recs = GET_BE_WORD(group.recs);
3002 startsz = group.startsz;
3003 endsz = group.endsz;
3005 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3007 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3008 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3009 if(result == GDI_ERROR) {
3010 FIXME("Failed to retrieve vTable\n");
3015 for(i = 0; i < recs; i++) {
3016 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3017 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3018 ppem = GET_BE_WORD(vTable[i * 3]);
3020 if(yMax + -yMin == height) {
3023 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3026 if(yMax + -yMin > height) {
3029 goto end; /* failed */
3031 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3032 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3033 ppem = GET_BE_WORD(vTable[i * 3]);
3034 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3040 TRACE("ppem not found for height %d\n", height);
3044 if(ppem < startsz || ppem > endsz)
3047 for(i = 0; i < recs; i++) {
3049 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3051 if(yPelHeight > ppem)
3054 if(yPelHeight == ppem) {
3055 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3056 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3057 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
3063 HeapFree(GetProcessHeap(), 0, vTable);
3069 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3071 if(font->font_desc.hash != fd->hash) return TRUE;
3072 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3073 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3074 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3075 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3078 static void calc_hash(FONT_DESC *pfd)
3080 DWORD hash = 0, *ptr, two_chars;
3084 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3086 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3088 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3090 pwc = (WCHAR *)&two_chars;
3092 *pwc = toupperW(*pwc);
3094 *pwc = toupperW(*pwc);
3098 hash ^= !pfd->can_use_bitmap;
3103 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3108 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3112 fd.can_use_bitmap = can_use_bitmap;
3115 /* try the in-use list */
3116 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3117 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3118 if(!fontcmp(ret, &fd)) {
3119 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3120 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3121 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3122 if(hflist->hfont == hfont)
3125 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3126 hflist->hfont = hfont;
3127 list_add_head(&ret->hfontlist, &hflist->entry);
3132 /* then the unused list */
3133 font_elem_ptr = list_head(&unused_gdi_font_list);
3134 while(font_elem_ptr) {
3135 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3136 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3137 if(!fontcmp(ret, &fd)) {
3138 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3139 assert(list_empty(&ret->hfontlist));
3140 TRACE("Found %p in unused list\n", ret);
3141 list_remove(&ret->entry);
3142 list_add_head(&gdi_font_list, &ret->entry);
3143 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3144 hflist->hfont = hfont;
3145 list_add_head(&ret->hfontlist, &hflist->entry);
3152 static void add_to_cache(GdiFont *font)
3154 static DWORD cache_num = 1;
3156 font->cache_num = cache_num++;
3157 list_add_head(&gdi_font_list, &font->entry);
3160 /*************************************************************
3161 * create_child_font_list
3163 static BOOL create_child_font_list(GdiFont *font)
3166 SYSTEM_LINKS *font_link;
3167 CHILD_FONT *font_link_entry, *new_child;
3169 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3171 if(!strcmpW(font_link->font_name, font->name))
3173 TRACE("found entry in system list\n");
3174 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3176 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3177 new_child->face = font_link_entry->face;
3178 new_child->font = NULL;
3179 list_add_tail(&font->child_fonts, &new_child->entry);
3180 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3187 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3188 * Sans Serif. This is how asian windows get default fallbacks for fonts
3190 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3191 font->charset != OEM_CHARSET &&
3192 strcmpW(font->name,szDefaultFallbackLink) != 0)
3193 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3195 if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3197 TRACE("found entry in default fallback list\n");
3198 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3200 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3201 new_child->face = font_link_entry->face;
3202 new_child->font = NULL;
3203 list_add_tail(&font->child_fonts, &new_child->entry);
3204 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3214 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3216 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3218 if (pFT_Set_Charmap)
3221 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3223 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3225 for (i = 0; i < ft_face->num_charmaps; i++)
3227 if (ft_face->charmaps[i]->encoding == encoding)
3229 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3230 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3232 switch (ft_face->charmaps[i]->platform_id)
3235 cmap_def = ft_face->charmaps[i];
3237 case 0: /* Apple Unicode */
3238 cmap0 = ft_face->charmaps[i];
3240 case 1: /* Macintosh */
3241 cmap1 = ft_face->charmaps[i];
3244 cmap2 = ft_face->charmaps[i];
3246 case 3: /* Microsoft */
3247 cmap3 = ft_face->charmaps[i];
3252 if (cmap3) /* prefer Microsoft cmap table */
3253 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3255 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3257 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3259 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3261 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3263 return ft_err == FT_Err_Ok;
3266 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3269 /*************************************************************
3270 * WineEngCreateFontInstance
3273 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3276 Face *face, *best, *best_bitmap;
3277 Family *family, *last_resort_family;
3278 struct list *family_elem_ptr, *face_elem_ptr;
3279 INT height, width = 0;
3280 unsigned int score = 0, new_score;
3281 signed int diff = 0, newdiff;
3282 BOOL bd, it, can_use_bitmap;
3287 FontSubst *psub = NULL;
3289 EnterCriticalSection( &freetype_cs );
3291 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
3293 struct list *first_hfont = list_head(&ret->hfontlist);
3294 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3295 if(hflist->hfont == hfont)
3297 LeaveCriticalSection( &freetype_cs );
3302 if (!GetObjectW( hfont, sizeof(lf), &lf ))
3304 LeaveCriticalSection( &freetype_cs );
3307 lf.lfWidth = abs(lf.lfWidth);
3309 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3311 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3312 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3313 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3316 if(dc->GraphicsMode == GM_ADVANCED)
3317 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3320 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3321 font scaling abilities. */
3322 dcmat.eM11 = dcmat.eM22 = fabs(dc->xformWorld2Vport.eM22);
3323 dcmat.eM21 = dcmat.eM12 = 0;
3326 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3327 dcmat.eM21, dcmat.eM22);
3329 /* check the cache first */
3330 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3331 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3332 LeaveCriticalSection( &freetype_cs );
3336 TRACE("not in cache\n");
3337 if(list_empty(&font_list)) /* No fonts installed */
3339 TRACE("No fonts installed\n");
3340 LeaveCriticalSection( &freetype_cs );
3343 if(!have_installed_roman_font)
3345 TRACE("No roman font installed\n");
3346 LeaveCriticalSection( &freetype_cs );
3352 ret->font_desc.matrix = dcmat;
3353 ret->font_desc.lf = lf;
3354 ret->font_desc.can_use_bitmap = can_use_bitmap;
3355 calc_hash(&ret->font_desc);
3356 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3357 hflist->hfont = hfont;
3358 list_add_head(&ret->hfontlist, &hflist->entry);
3360 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3361 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3362 original value lfCharSet. Note this is a special case for
3363 Symbol and doesn't happen at least for "Wingdings*" */
3365 if(!strcmpiW(lf.lfFaceName, SymbolW))
3366 lf.lfCharSet = SYMBOL_CHARSET;
3368 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3369 switch(lf.lfCharSet) {
3370 case DEFAULT_CHARSET:
3371 csi.fs.fsCsb[0] = 0;
3374 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3375 csi.fs.fsCsb[0] = 0;
3381 if(lf.lfFaceName[0] != '\0') {
3382 SYSTEM_LINKS *font_link;
3383 CHILD_FONT *font_link_entry;
3384 LPWSTR FaceName = lf.lfFaceName;
3387 * Check for a leading '@' this signals that the font is being
3388 * requested in tategaki mode (vertical writing substitution) but
3389 * does not affect the fontface that is to be selected.
3391 if (lf.lfFaceName[0]=='@')
3392 FaceName = &lf.lfFaceName[1];
3394 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3397 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3398 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3399 if (psub->to.charset != -1)
3400 lf.lfCharSet = psub->to.charset;
3403 /* We want a match on name and charset or just name if
3404 charset was DEFAULT_CHARSET. If the latter then
3405 we fixup the returned charset later in get_nearest_charset
3406 where we'll either use the charset of the current ansi codepage
3407 or if that's unavailable the first charset that the font supports.
3409 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3410 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3411 if (!strcmpiW(family->FamilyName, FaceName) ||
3412 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3414 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3415 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3416 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3417 if(face->scalable || can_use_bitmap)
3424 * Try check the SystemLink list first for a replacement font.
3425 * We may find good replacements there.
3427 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3429 if(!strcmpiW(font_link->font_name, FaceName))
3431 TRACE("found entry in system list\n");
3432 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3434 face = font_link_entry->face;
3435 family = face->family;
3436 if(csi.fs.fsCsb[0] &
3437 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3439 if(face->scalable || can_use_bitmap)
3447 psub = NULL; /* substitution is no more relevant */
3449 /* If requested charset was DEFAULT_CHARSET then try using charset
3450 corresponding to the current ansi codepage */
3451 if (!csi.fs.fsCsb[0] || lf.lfWeight == FW_DONTCARE)
3454 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3455 FIXME("TCI failed on codepage %d\n", acp);
3456 csi.fs.fsCsb[0] = 0;
3458 lf.lfCharSet = csi.ciCharset;
3461 /* Face families are in the top 4 bits of lfPitchAndFamily,
3462 so mask with 0xF0 before testing */
3464 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3465 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3466 strcpyW(lf.lfFaceName, defFixed);
3467 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3468 strcpyW(lf.lfFaceName, defSerif);
3469 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3470 strcpyW(lf.lfFaceName, defSans);
3472 strcpyW(lf.lfFaceName, defSans);
3473 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3474 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3475 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3476 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3477 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3478 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3479 if(face->scalable || can_use_bitmap)
3485 last_resort_family = NULL;
3486 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3487 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3488 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3489 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3490 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3493 if(can_use_bitmap && !last_resort_family)
3494 last_resort_family = family;
3499 if(last_resort_family) {
3500 family = last_resort_family;
3501 csi.fs.fsCsb[0] = 0;
3505 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3506 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3507 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3508 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3509 if(face->scalable) {
3510 csi.fs.fsCsb[0] = 0;
3511 WARN("just using first face for now\n");
3514 if(can_use_bitmap && !last_resort_family)
3515 last_resort_family = family;
3518 if(!last_resort_family) {
3519 FIXME("can't find a single appropriate font - bailing\n");
3521 LeaveCriticalSection( &freetype_cs );
3525 WARN("could only find a bitmap font - this will probably look awful!\n");
3526 family = last_resort_family;
3527 csi.fs.fsCsb[0] = 0;
3530 it = lf.lfItalic ? 1 : 0;
3531 bd = lf.lfWeight > 550 ? 1 : 0;
3533 height = lf.lfHeight;
3535 face = best = best_bitmap = NULL;
3536 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3538 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3542 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3543 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3544 new_score = (italic ^ it) + (bold ^ bd);
3545 if(!best || new_score <= score)
3547 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3548 italic, bold, it, bd);
3551 if(best->scalable && score == 0) break;
3555 newdiff = height - (signed int)(best->size.height);
3557 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3558 if(!best_bitmap || new_score < score ||
3559 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3561 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3564 if(score == 0 && diff == 0) break;
3571 face = best->scalable ? best : best_bitmap;
3572 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3573 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3577 if(csi.fs.fsCsb[0]) {
3578 ret->charset = lf.lfCharSet;
3579 ret->codepage = csi.ciACP;
3582 ret->charset = get_nearest_charset(face, &ret->codepage);
3584 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3585 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3587 ret->aveWidth = height ? lf.lfWidth : 0;
3589 if(!face->scalable) {
3590 /* Windows uses integer scaling factors for bitmap fonts */
3591 INT scale, scaled_height;
3593 /* FIXME: rotation of bitmap fonts is ignored */
3594 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3596 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3597 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3599 if (height != 0) height = diff;
3600 height += face->size.height;
3602 scale = (height + face->size.height - 1) / face->size.height;
3603 scaled_height = scale * face->size.height;
3604 /* XP allows not more than 10% deviation */
3605 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3606 ret->scale_y = scale;
3608 width = face->size.x_ppem >> 6;
3609 height = face->size.y_ppem >> 6;
3613 TRACE("font scale y: %f\n", ret->scale_y);
3615 ret->ft_face = OpenFontFace(ret, face, width, height);
3620 LeaveCriticalSection( &freetype_cs );
3624 ret->ntmFlags = face->ntmFlags;
3626 if (ret->charset == SYMBOL_CHARSET &&
3627 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3630 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3634 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3637 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3638 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3639 ret->underline = lf.lfUnderline ? 0xff : 0;
3640 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3641 create_child_font_list(ret);
3643 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3645 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3646 if (length != GDI_ERROR)
3648 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3649 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3650 TRACE("Loaded GSUB table of %i bytes\n",length);
3654 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3657 LeaveCriticalSection( &freetype_cs );
3661 static void dump_gdi_font_list(void)
3664 struct list *elem_ptr;
3666 TRACE("---------- gdiFont Cache ----------\n");
3667 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3668 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3669 TRACE("gdiFont=%p %s %d\n",
3670 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3673 TRACE("---------- Unused gdiFont Cache ----------\n");
3674 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3675 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3676 TRACE("gdiFont=%p %s %d\n",
3677 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3681 /*************************************************************
3682 * WineEngDestroyFontInstance
3684 * free the gdiFont associated with this handle
3687 BOOL WineEngDestroyFontInstance(HFONT handle)
3692 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3695 EnterCriticalSection( &freetype_cs );
3697 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3699 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3700 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3701 if(hflist->hfont == handle)
3703 TRACE("removing child font %p from child list\n", gdiFont);
3704 list_remove(&gdiFont->entry);
3705 LeaveCriticalSection( &freetype_cs );
3710 TRACE("destroying hfont=%p\n", handle);
3712 dump_gdi_font_list();
3714 font_elem_ptr = list_head(&gdi_font_list);
3715 while(font_elem_ptr) {
3716 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3717 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3719 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3720 while(hfontlist_elem_ptr) {
3721 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3722 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3723 if(hflist->hfont == handle) {
3724 list_remove(&hflist->entry);
3725 HeapFree(GetProcessHeap(), 0, hflist);
3729 if(list_empty(&gdiFont->hfontlist)) {
3730 TRACE("Moving to Unused list\n");
3731 list_remove(&gdiFont->entry);
3732 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3737 font_elem_ptr = list_head(&unused_gdi_font_list);
3738 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3739 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3740 while(font_elem_ptr) {
3741 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3742 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3743 TRACE("freeing %p\n", gdiFont);
3744 list_remove(&gdiFont->entry);
3747 LeaveCriticalSection( &freetype_cs );
3751 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3752 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3757 if (face->cached_enum_data)
3760 *pelf = face->cached_enum_data->elf;
3761 *pntm = face->cached_enum_data->ntm;
3762 *ptype = face->cached_enum_data->type;
3766 font = alloc_font();
3768 if(face->scalable) {
3769 height = -2048; /* 2048 is the most common em size */
3772 height = face->size.y_ppem >> 6;
3773 width = face->size.x_ppem >> 6;
3775 font->scale_y = 1.0;
3777 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3783 font->name = strdupW(face->family->FamilyName);
3784 font->ntmFlags = face->ntmFlags;
3786 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3788 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3790 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3792 lstrcpynW(pelf->elfLogFont.lfFaceName,
3793 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3795 lstrcpynW(pelf->elfFullName,
3796 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3798 lstrcpynW(pelf->elfStyle,
3799 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3804 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3806 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3808 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3809 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3810 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3813 pntm->ntmTm.ntmFlags = face->ntmFlags;
3814 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3815 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3816 pntm->ntmFontSig = face->fs;
3818 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3820 pelf->elfLogFont.lfEscapement = 0;
3821 pelf->elfLogFont.lfOrientation = 0;
3822 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3823 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3824 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3825 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3826 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3827 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3828 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3829 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3830 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3831 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3832 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3835 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3836 *ptype |= TRUETYPE_FONTTYPE;
3837 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3838 *ptype |= DEVICE_FONTTYPE;
3839 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3840 *ptype |= RASTER_FONTTYPE;
3842 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3843 if (face->cached_enum_data)
3845 face->cached_enum_data->elf = *pelf;
3846 face->cached_enum_data->ntm = *pntm;
3847 face->cached_enum_data->type = *ptype;
3853 /*************************************************************
3857 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3861 struct list *family_elem_ptr, *face_elem_ptr;
3863 NEWTEXTMETRICEXW ntm;
3872 lf.lfCharSet = DEFAULT_CHARSET;
3873 lf.lfPitchAndFamily = 0;
3874 lf.lfFaceName[0] = 0;
3878 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3880 EnterCriticalSection( &freetype_cs );
3881 if(plf->lfFaceName[0]) {
3883 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3886 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3887 debugstr_w(psub->to.name));
3889 strcpyW(lf.lfFaceName, psub->to.name);
3893 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3894 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3895 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3896 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3897 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3898 GetEnumStructs(face, &elf, &ntm, &type);
3899 for(i = 0; i < 32; i++) {
3900 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3901 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3902 strcpyW(elf.elfScript, OEM_DOSW);
3903 i = 32; /* break out of loop */
3904 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3907 fs.fsCsb[0] = 1L << i;
3909 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3911 csi.ciCharset = DEFAULT_CHARSET;
3912 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3913 if(csi.ciCharset != DEFAULT_CHARSET) {
3914 elf.elfLogFont.lfCharSet =
3915 ntm.ntmTm.tmCharSet = csi.ciCharset;
3917 strcpyW(elf.elfScript, ElfScriptsW[i]);
3919 FIXME("Unknown elfscript for bit %d\n", i);
3922 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3923 debugstr_w(elf.elfLogFont.lfFaceName),
3924 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3925 csi.ciCharset, type, debugstr_w(elf.elfScript),
3926 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3927 ntm.ntmTm.ntmFlags);
3928 /* release section before callback (FIXME) */
3929 LeaveCriticalSection( &freetype_cs );
3930 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3931 EnterCriticalSection( &freetype_cs );
3937 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3938 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3939 face_elem_ptr = list_head(&family->faces);
3940 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3941 GetEnumStructs(face, &elf, &ntm, &type);
3942 for(i = 0; i < 32; i++) {
3943 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3944 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3945 strcpyW(elf.elfScript, OEM_DOSW);
3946 i = 32; /* break out of loop */
3947 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3950 fs.fsCsb[0] = 1L << i;
3952 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3954 csi.ciCharset = DEFAULT_CHARSET;
3955 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3956 if(csi.ciCharset != DEFAULT_CHARSET) {
3957 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3960 strcpyW(elf.elfScript, ElfScriptsW[i]);
3962 FIXME("Unknown elfscript for bit %d\n", i);
3965 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3966 debugstr_w(elf.elfLogFont.lfFaceName),
3967 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3968 csi.ciCharset, type, debugstr_w(elf.elfScript),
3969 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3970 ntm.ntmTm.ntmFlags);
3971 /* release section before callback (FIXME) */
3972 LeaveCriticalSection( &freetype_cs );
3973 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3974 EnterCriticalSection( &freetype_cs );
3978 LeaveCriticalSection( &freetype_cs );
3982 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3984 pt->x.value = vec->x >> 6;
3985 pt->x.fract = (vec->x & 0x3f) << 10;
3986 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3987 pt->y.value = vec->y >> 6;
3988 pt->y.fract = (vec->y & 0x3f) << 10;
3989 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3993 /***************************************************
3994 * According to the MSDN documentation on WideCharToMultiByte,
3995 * certain codepages cannot set the default_used parameter.
3996 * This returns TRUE if the codepage can set that parameter, false else
3997 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3999 static BOOL codepage_sets_default_used(UINT codepage)
4013 * GSUB Table handling functions
4016 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4018 const GSUB_CoverageFormat1* cf1;
4020 cf1 = (GSUB_CoverageFormat1*)table;
4022 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4024 int count = GET_BE_WORD(cf1->GlyphCount);
4026 TRACE("Coverage Format 1, %i glyphs\n",count);
4027 for (i = 0; i < count; i++)
4028 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4032 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4034 const GSUB_CoverageFormat2* cf2;
4037 cf2 = (GSUB_CoverageFormat2*)cf1;
4039 count = GET_BE_WORD(cf2->RangeCount);
4040 TRACE("Coverage Format 2, %i ranges\n",count);
4041 for (i = 0; i < count; i++)
4043 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4045 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4046 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4048 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4049 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4055 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4060 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4062 const GSUB_ScriptList *script;
4063 const GSUB_Script *deflt = NULL;
4065 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
4067 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4068 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4070 const GSUB_Script *scr;
4073 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4074 scr = (GSUB_Script*)((LPBYTE)script + offset);
4076 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4078 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4084 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4088 const GSUB_LangSys *Lang;
4090 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4092 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4094 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4095 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4097 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4100 offset = GET_BE_WORD(script->DefaultLangSys);
4103 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4109 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4112 const GSUB_FeatureList *feature;
4113 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
4115 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4116 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4118 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4119 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4121 const GSUB_Feature *feat;
4122 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4129 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4133 const GSUB_LookupList *lookup;
4134 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
4136 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4137 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4139 const GSUB_LookupTable *look;
4140 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4141 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
4142 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4143 if (GET_BE_WORD(look->LookupType) != 1)
4144 FIXME("We only handle SubType 1\n");
4149 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4151 const GSUB_SingleSubstFormat1 *ssf1;
4152 offset = GET_BE_WORD(look->SubTable[j]);
4153 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
4154 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4156 int offset = GET_BE_WORD(ssf1->Coverage);
4157 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4158 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
4160 TRACE(" Glyph 0x%x ->",glyph);
4161 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4162 TRACE(" 0x%x\n",glyph);
4167 const GSUB_SingleSubstFormat2 *ssf2;
4171 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
4172 offset = GET_BE_WORD(ssf1->Coverage);
4173 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4174 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
4175 TRACE(" Coverage index %i\n",index);
4178 TRACE(" Glyph is 0x%x ->",glyph);
4179 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4180 TRACE("0x%x\n",glyph);
4189 static const char* get_opentype_script(const GdiFont *font)
4192 * I am not sure if this is the correct way to generate our script tag
4195 switch (font->charset)
4197 case ANSI_CHARSET: return "latn";
4198 case BALTIC_CHARSET: return "latn"; /* ?? */
4199 case CHINESEBIG5_CHARSET: return "hani";
4200 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4201 case GB2312_CHARSET: return "hani";
4202 case GREEK_CHARSET: return "grek";
4203 case HANGUL_CHARSET: return "hang";
4204 case RUSSIAN_CHARSET: return "cyrl";
4205 case SHIFTJIS_CHARSET: return "kana";
4206 case TURKISH_CHARSET: return "latn"; /* ?? */
4207 case VIETNAMESE_CHARSET: return "latn";
4208 case JOHAB_CHARSET: return "latn"; /* ?? */
4209 case ARABIC_CHARSET: return "arab";
4210 case HEBREW_CHARSET: return "hebr";
4211 case THAI_CHARSET: return "thai";
4212 default: return "latn";
4216 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4218 const GSUB_Header *header;
4219 const GSUB_Script *script;
4220 const GSUB_LangSys *language;
4221 const GSUB_Feature *feature;
4223 if (!font->GSUB_Table)
4226 header = font->GSUB_Table;
4228 script = GSUB_get_script_table(header, get_opentype_script(font));
4231 TRACE("Script not found\n");
4234 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4237 TRACE("Language not found\n");
4240 feature = GSUB_get_feature(header, language, "vrt2");
4242 feature = GSUB_get_feature(header, language, "vert");
4245 TRACE("vrt2/vert feature not found\n");
4248 return GSUB_apply_feature(header, feature, glyph);
4251 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4255 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4256 WCHAR wc = (WCHAR)glyph;
4258 BOOL *default_used_pointer;
4261 default_used_pointer = NULL;
4262 default_used = FALSE;
4263 if (codepage_sets_default_used(font->codepage))
4264 default_used_pointer = &default_used;
4265 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4268 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4269 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4270 return get_GSUB_vert_glyph(font,ret);
4273 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4274 glyph = glyph + 0xf000;
4275 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4276 return get_GSUB_vert_glyph(font,glyphId);
4279 /*************************************************************
4280 * WineEngGetGlyphIndices
4283 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4284 LPWORD pgi, DWORD flags)
4287 int default_char = -1;
4289 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4291 for(i = 0; i < count; i++)
4293 pgi[i] = get_glyph_index(font, lpstr[i]);
4296 if (default_char == -1)
4298 if (FT_IS_SFNT(font->ft_face))
4300 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4301 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4306 WineEngGetTextMetrics(font, &textm);
4307 default_char = textm.tmDefaultChar;
4310 pgi[i] = default_char;
4316 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4318 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4319 return !memcmp(matrix, &identity, sizeof(FMAT2));
4322 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4324 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4325 return !memcmp(matrix, &identity, sizeof(MAT2));
4328 /*************************************************************
4329 * WineEngGetGlyphOutline
4331 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4332 * except that the first parameter is the HWINEENGFONT of the font in
4333 * question rather than an HDC.
4336 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4337 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4340 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4341 FT_Face ft_face = incoming_font->ft_face;
4342 GdiFont *font = incoming_font;
4343 FT_UInt glyph_index;
4344 DWORD width, height, pitch, needed = 0;
4345 FT_Bitmap ft_bitmap;
4347 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4349 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4350 double widthRatio = 1.0;
4351 FT_Matrix transMat = identityMat;
4352 FT_Matrix transMatUnrotated;
4353 BOOL needsTransform = FALSE;
4354 BOOL tategaki = (font->GSUB_Table != NULL);
4355 UINT original_index;
4357 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4358 buflen, buf, lpmat);
4360 TRACE("font transform %f %f %f %f\n",
4361 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4362 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4364 EnterCriticalSection( &freetype_cs );
4366 if(format & GGO_GLYPH_INDEX) {
4367 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4368 original_index = glyph;
4369 format &= ~GGO_GLYPH_INDEX;
4371 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4372 ft_face = font->ft_face;
4373 original_index = glyph_index;
4376 /* tategaki never appears to happen to lower glyph index */
4377 if (glyph_index < TATEGAKI_LOWER_BOUND )
4380 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4381 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4382 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4383 font->gmsize * sizeof(GM*));
4385 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4386 FONT_GM(font,original_index)->init && (!lpmat || is_identity_MAT2(lpmat)))
4388 *lpgm = FONT_GM(font,original_index)->gm;
4389 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4390 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4391 lpgm->gmCellIncX, lpgm->gmCellIncY);
4392 LeaveCriticalSection( &freetype_cs );
4393 return 1; /* FIXME */
4397 if (!font->gm[original_index / GM_BLOCK_SIZE])
4398 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4400 /* Scaling factor */
4405 WineEngGetTextMetrics(font, &tm);
4407 widthRatio = (double)font->aveWidth;
4408 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4411 widthRatio = font->scale_y;
4413 /* Scaling transform */
4414 if (widthRatio != 1.0 || font->scale_y != 1.0)
4417 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4420 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4422 pFT_Matrix_Multiply(&scaleMat, &transMat);
4423 needsTransform = TRUE;
4426 /* Slant transform */
4427 if (font->fake_italic) {
4430 slantMat.xx = (1 << 16);
4431 slantMat.xy = ((1 << 16) >> 2);
4433 slantMat.yy = (1 << 16);
4434 pFT_Matrix_Multiply(&slantMat, &transMat);
4435 needsTransform = TRUE;
4438 /* Rotation transform */
4439 transMatUnrotated = transMat;
4440 if(font->orientation && !tategaki) {
4441 FT_Matrix rotationMat;
4443 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4444 pFT_Vector_Unit(&vecAngle, angle);
4445 rotationMat.xx = vecAngle.x;
4446 rotationMat.xy = -vecAngle.y;
4447 rotationMat.yx = -rotationMat.xy;
4448 rotationMat.yy = rotationMat.xx;
4450 pFT_Matrix_Multiply(&rotationMat, &transMat);
4451 needsTransform = TRUE;
4454 /* World transform */
4455 if (!is_identity_FMAT2(&font->font_desc.matrix))
4458 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4459 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4460 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4461 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4462 pFT_Matrix_Multiply(&worldMat, &transMat);
4463 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4464 needsTransform = TRUE;
4467 /* Extra transformation specified by caller */
4468 if (lpmat && !is_identity_MAT2(lpmat))
4471 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4472 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
4473 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
4474 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4475 pFT_Matrix_Multiply(&extraMat, &transMat);
4476 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4477 needsTransform = TRUE;
4480 if (needsTransform || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP))
4481 load_flags |= FT_LOAD_NO_BITMAP;
4483 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4486 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4487 LeaveCriticalSection( &freetype_cs );
4491 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4492 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4494 adv = (INT)((ft_face->glyph->metrics.horiAdvance) + 63) >> 6;
4496 bbx = (right - left) >> 6;
4498 if(!needsTransform) {
4499 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4500 bottom = (ft_face->glyph->metrics.horiBearingY -
4501 ft_face->glyph->metrics.height) & -64;
4502 lpgm->gmCellIncX = adv;
4503 lpgm->gmCellIncY = 0;
4507 for(xc = 0; xc < 2; xc++) {
4508 for(yc = 0; yc < 2; yc++) {
4509 vec.x = (ft_face->glyph->metrics.horiBearingX +
4510 xc * ft_face->glyph->metrics.width);
4511 vec.y = ft_face->glyph->metrics.horiBearingY -
4512 yc * ft_face->glyph->metrics.height;
4513 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4514 pFT_Vector_Transform(&vec, &transMat);
4515 if(xc == 0 && yc == 0) {
4516 left = right = vec.x;
4517 top = bottom = vec.y;
4519 if(vec.x < left) left = vec.x;
4520 else if(vec.x > right) right = vec.x;
4521 if(vec.y < bottom) bottom = vec.y;
4522 else if(vec.y > top) top = vec.y;
4527 right = (right + 63) & -64;
4528 bottom = bottom & -64;
4529 top = (top + 63) & -64;
4531 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4532 vec.x = ft_face->glyph->metrics.horiAdvance;
4534 pFT_Vector_Transform(&vec, &transMat);
4535 lpgm->gmCellIncX = (vec.x+63) >> 6;
4536 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4538 vec.x = ft_face->glyph->metrics.horiAdvance;
4540 pFT_Vector_Transform(&vec, &transMatUnrotated);
4541 adv = (vec.x+63) >> 6;
4543 lpgm->gmBlackBoxX = (right - left) >> 6;
4544 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4545 lpgm->gmptGlyphOrigin.x = left >> 6;
4546 lpgm->gmptGlyphOrigin.y = top >> 6;
4548 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4549 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4550 lpgm->gmCellIncX, lpgm->gmCellIncY);
4552 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4553 (!lpmat || is_identity_MAT2(lpmat))) /* don't cache custom transforms */
4555 FONT_GM(font,original_index)->gm = *lpgm;
4556 FONT_GM(font,original_index)->adv = adv;
4557 FONT_GM(font,original_index)->lsb = lsb;
4558 FONT_GM(font,original_index)->bbx = bbx;
4559 FONT_GM(font,original_index)->init = TRUE;
4562 if(format == GGO_METRICS)
4564 LeaveCriticalSection( &freetype_cs );
4565 return 1; /* FIXME */
4568 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
4569 TRACE("loaded a bitmap\n");
4570 LeaveCriticalSection( &freetype_cs );
4576 width = lpgm->gmBlackBoxX;
4577 height = lpgm->gmBlackBoxY;
4578 pitch = ((width + 31) >> 5) << 2;
4579 needed = pitch * height;
4581 if(!buf || !buflen) break;
4583 switch(ft_face->glyph->format) {
4584 case ft_glyph_format_bitmap:
4586 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4587 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4588 INT h = ft_face->glyph->bitmap.rows;
4590 memcpy(dst, src, w);
4591 src += ft_face->glyph->bitmap.pitch;
4597 case ft_glyph_format_outline:
4598 ft_bitmap.width = width;
4599 ft_bitmap.rows = height;
4600 ft_bitmap.pitch = pitch;
4601 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4602 ft_bitmap.buffer = buf;
4604 if(needsTransform) {
4605 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4608 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4610 /* Note: FreeType will only set 'black' bits for us. */
4611 memset(buf, 0, needed);
4612 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4616 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4617 LeaveCriticalSection( &freetype_cs );
4622 case GGO_GRAY2_BITMAP:
4623 case GGO_GRAY4_BITMAP:
4624 case GGO_GRAY8_BITMAP:
4625 case WINE_GGO_GRAY16_BITMAP:
4627 unsigned int mult, row, col;
4630 width = lpgm->gmBlackBoxX;
4631 height = lpgm->gmBlackBoxY;
4632 pitch = (width + 3) / 4 * 4;
4633 needed = pitch * height;
4635 if(!buf || !buflen) break;
4637 switch(ft_face->glyph->format) {
4638 case ft_glyph_format_bitmap:
4640 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4641 INT h = ft_face->glyph->bitmap.rows;
4644 for(x = 0; x < pitch; x++)
4646 if(x < ft_face->glyph->bitmap.width)
4647 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4651 src += ft_face->glyph->bitmap.pitch;
4654 LeaveCriticalSection( &freetype_cs );
4657 case ft_glyph_format_outline:
4659 ft_bitmap.width = width;
4660 ft_bitmap.rows = height;
4661 ft_bitmap.pitch = pitch;
4662 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4663 ft_bitmap.buffer = buf;
4666 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4668 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4670 memset(ft_bitmap.buffer, 0, buflen);
4672 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4674 if(format == GGO_GRAY2_BITMAP)
4676 else if(format == GGO_GRAY4_BITMAP)
4678 else if(format == GGO_GRAY8_BITMAP)
4680 else /* format == WINE_GGO_GRAY16_BITMAP */
4682 LeaveCriticalSection( &freetype_cs );
4688 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4689 LeaveCriticalSection( &freetype_cs );
4694 for(row = 0; row < height; row++) {
4696 for(col = 0; col < width; col++, ptr++) {
4697 *ptr = (((int)*ptr) * mult + 128) / 256;
4706 int contour, point = 0, first_pt;
4707 FT_Outline *outline = &ft_face->glyph->outline;
4708 TTPOLYGONHEADER *pph;
4710 DWORD pph_start, cpfx, type;
4712 if(buflen == 0) buf = NULL;
4714 if (needsTransform && buf) {
4715 pFT_Outline_Transform(outline, &transMat);
4718 for(contour = 0; contour < outline->n_contours; contour++) {
4720 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4723 pph->dwType = TT_POLYGON_TYPE;
4724 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4726 needed += sizeof(*pph);
4728 while(point <= outline->contours[contour]) {
4729 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4730 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4731 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4735 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4738 } while(point <= outline->contours[contour] &&
4739 (outline->tags[point] & FT_Curve_Tag_On) ==
4740 (outline->tags[point-1] & FT_Curve_Tag_On));
4741 /* At the end of a contour Windows adds the start point, but
4743 if(point > outline->contours[contour] &&
4744 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4746 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4748 } else if(point <= outline->contours[contour] &&
4749 outline->tags[point] & FT_Curve_Tag_On) {
4750 /* add closing pt for bezier */
4752 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4760 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4763 pph->cb = needed - pph_start;
4769 /* Convert the quadratic Beziers to cubic Beziers.
4770 The parametric eqn for a cubic Bezier is, from PLRM:
4771 r(t) = at^3 + bt^2 + ct + r0
4772 with the control points:
4777 A quadratic Beizer has the form:
4778 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4780 So equating powers of t leads to:
4781 r1 = 2/3 p1 + 1/3 p0
4782 r2 = 2/3 p1 + 1/3 p2
4783 and of course r0 = p0, r3 = p2
4786 int contour, point = 0, first_pt;
4787 FT_Outline *outline = &ft_face->glyph->outline;
4788 TTPOLYGONHEADER *pph;
4790 DWORD pph_start, cpfx, type;
4791 FT_Vector cubic_control[4];
4792 if(buflen == 0) buf = NULL;
4794 if (needsTransform && buf) {
4795 pFT_Outline_Transform(outline, &transMat);
4798 for(contour = 0; contour < outline->n_contours; contour++) {
4800 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4803 pph->dwType = TT_POLYGON_TYPE;
4804 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4806 needed += sizeof(*pph);
4808 while(point <= outline->contours[contour]) {
4809 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4810 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4811 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4814 if(type == TT_PRIM_LINE) {
4816 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4820 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4823 /* FIXME: Possible optimization in endpoint calculation
4824 if there are two consecutive curves */
4825 cubic_control[0] = outline->points[point-1];
4826 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4827 cubic_control[0].x += outline->points[point].x + 1;
4828 cubic_control[0].y += outline->points[point].y + 1;
4829 cubic_control[0].x >>= 1;
4830 cubic_control[0].y >>= 1;
4832 if(point+1 > outline->contours[contour])
4833 cubic_control[3] = outline->points[first_pt];
4835 cubic_control[3] = outline->points[point+1];
4836 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4837 cubic_control[3].x += outline->points[point].x + 1;
4838 cubic_control[3].y += outline->points[point].y + 1;
4839 cubic_control[3].x >>= 1;
4840 cubic_control[3].y >>= 1;
4843 /* r1 = 1/3 p0 + 2/3 p1
4844 r2 = 1/3 p2 + 2/3 p1 */
4845 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4846 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4847 cubic_control[2] = cubic_control[1];
4848 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4849 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4850 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4851 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4853 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4854 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4855 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4860 } while(point <= outline->contours[contour] &&
4861 (outline->tags[point] & FT_Curve_Tag_On) ==
4862 (outline->tags[point-1] & FT_Curve_Tag_On));
4863 /* At the end of a contour Windows adds the start point,
4864 but only for Beziers and we've already done that.
4866 if(point <= outline->contours[contour] &&
4867 outline->tags[point] & FT_Curve_Tag_On) {
4868 /* This is the closing pt of a bezier, but we've already
4869 added it, so just inc point and carry on */
4876 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4879 pph->cb = needed - pph_start;
4885 FIXME("Unsupported format %d\n", format);
4886 LeaveCriticalSection( &freetype_cs );
4889 LeaveCriticalSection( &freetype_cs );
4893 static BOOL get_bitmap_text_metrics(GdiFont *font)
4895 FT_Face ft_face = font->ft_face;
4896 #ifdef HAVE_FREETYPE_FTWINFNT_H
4897 FT_WinFNT_HeaderRec winfnt_header;
4899 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4900 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4901 font->potm->otmSize = size;
4903 #define TM font->potm->otmTextMetrics
4904 #ifdef HAVE_FREETYPE_FTWINFNT_H
4905 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4907 TM.tmHeight = winfnt_header.pixel_height;
4908 TM.tmAscent = winfnt_header.ascent;
4909 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4910 TM.tmInternalLeading = winfnt_header.internal_leading;
4911 TM.tmExternalLeading = winfnt_header.external_leading;
4912 TM.tmAveCharWidth = winfnt_header.avg_width;
4913 TM.tmMaxCharWidth = winfnt_header.max_width;
4914 TM.tmWeight = winfnt_header.weight;
4916 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4917 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4918 TM.tmFirstChar = winfnt_header.first_char;
4919 TM.tmLastChar = winfnt_header.last_char;
4920 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4921 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4922 TM.tmItalic = winfnt_header.italic;
4923 TM.tmUnderlined = font->underline;
4924 TM.tmStruckOut = font->strikeout;
4925 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4926 TM.tmCharSet = winfnt_header.charset;
4931 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4932 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4933 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4934 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4935 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4936 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4937 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4938 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4940 TM.tmDigitizedAspectX = 96; /* FIXME */
4941 TM.tmDigitizedAspectY = 96; /* FIXME */
4943 TM.tmLastChar = 255;
4944 TM.tmDefaultChar = 32;
4945 TM.tmBreakChar = 32;
4946 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4947 TM.tmUnderlined = font->underline;
4948 TM.tmStruckOut = font->strikeout;
4949 /* NB inverted meaning of TMPF_FIXED_PITCH */
4950 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4951 TM.tmCharSet = font->charset;
4959 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
4961 double scale_x, scale_y;
4965 scale_x = (double)font->aveWidth;
4966 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4969 scale_x = font->scale_y;
4971 scale_x *= fabs(font->font_desc.matrix.eM11);
4972 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
4974 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
4975 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
4977 SCALE_Y(ptm->tmHeight);
4978 SCALE_Y(ptm->tmAscent);
4979 SCALE_Y(ptm->tmDescent);
4980 SCALE_Y(ptm->tmInternalLeading);
4981 SCALE_Y(ptm->tmExternalLeading);
4982 SCALE_Y(ptm->tmOverhang);
4984 SCALE_X(ptm->tmAveCharWidth);
4985 SCALE_X(ptm->tmMaxCharWidth);
4991 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
4993 double scale_x, scale_y;
4997 scale_x = (double)font->aveWidth;
4998 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5001 scale_x = font->scale_y;
5003 scale_x *= fabs(font->font_desc.matrix.eM11);
5004 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5006 scale_font_metrics(font, &potm->otmTextMetrics);
5008 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5009 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5011 SCALE_Y(potm->otmAscent);
5012 SCALE_Y(potm->otmDescent);
5013 SCALE_Y(potm->otmLineGap);
5014 SCALE_Y(potm->otmsCapEmHeight);
5015 SCALE_Y(potm->otmsXHeight);
5016 SCALE_Y(potm->otmrcFontBox.top);
5017 SCALE_Y(potm->otmrcFontBox.bottom);
5018 SCALE_X(potm->otmrcFontBox.left);
5019 SCALE_X(potm->otmrcFontBox.right);
5020 SCALE_Y(potm->otmMacAscent);
5021 SCALE_Y(potm->otmMacDescent);
5022 SCALE_Y(potm->otmMacLineGap);
5023 SCALE_X(potm->otmptSubscriptSize.x);
5024 SCALE_Y(potm->otmptSubscriptSize.y);
5025 SCALE_X(potm->otmptSubscriptOffset.x);
5026 SCALE_Y(potm->otmptSubscriptOffset.y);
5027 SCALE_X(potm->otmptSuperscriptSize.x);
5028 SCALE_Y(potm->otmptSuperscriptSize.y);
5029 SCALE_X(potm->otmptSuperscriptOffset.x);
5030 SCALE_Y(potm->otmptSuperscriptOffset.y);
5031 SCALE_Y(potm->otmsStrikeoutSize);
5032 SCALE_Y(potm->otmsStrikeoutPosition);
5033 SCALE_Y(potm->otmsUnderscoreSize);
5034 SCALE_Y(potm->otmsUnderscorePosition);
5040 /*************************************************************
5041 * WineEngGetTextMetrics
5044 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5046 EnterCriticalSection( &freetype_cs );
5048 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5049 if(!get_bitmap_text_metrics(font))
5051 LeaveCriticalSection( &freetype_cs );
5057 LeaveCriticalSection( &freetype_cs );
5060 *ptm = font->potm->otmTextMetrics;
5061 scale_font_metrics(font, ptm);
5062 LeaveCriticalSection( &freetype_cs );
5067 /*************************************************************
5068 * WineEngGetOutlineTextMetrics
5071 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5072 OUTLINETEXTMETRICW *potm)
5074 FT_Face ft_face = font->ft_face;
5075 UINT needed, lenfam, lensty, ret;
5077 TT_HoriHeader *pHori;
5078 TT_Postscript *pPost;
5079 FT_Fixed x_scale, y_scale;
5080 WCHAR *family_nameW, *style_nameW;
5081 static const WCHAR spaceW[] = {' ', '\0'};
5083 INT ascent, descent;
5085 TRACE("font=%p\n", font);
5087 if(!FT_IS_SCALABLE(ft_face))
5090 EnterCriticalSection( &freetype_cs );
5093 if(cbSize >= font->potm->otmSize)
5095 memcpy(potm, font->potm, font->potm->otmSize);
5096 scale_outline_font_metrics(font, potm);
5098 LeaveCriticalSection( &freetype_cs );
5099 return font->potm->otmSize;
5103 needed = sizeof(*potm);
5105 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5106 family_nameW = strdupW(font->name);
5108 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5110 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5111 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5112 style_nameW, lensty/sizeof(WCHAR));
5114 /* These names should be read from the TT name table */
5116 /* length of otmpFamilyName */
5119 /* length of otmpFaceName */
5120 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5121 needed += lenfam; /* just the family name */
5123 needed += lenfam + lensty; /* family + " " + style */
5126 /* length of otmpStyleName */
5129 /* length of otmpFullName */
5130 needed += lenfam + lensty;
5133 x_scale = ft_face->size->metrics.x_scale;
5134 y_scale = ft_face->size->metrics.y_scale;
5136 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5138 FIXME("Can't find OS/2 table - not TT font?\n");
5143 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5145 FIXME("Can't find HHEA table - not TT font?\n");
5150 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5152 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",
5153 pOS2->usWinAscent, pOS2->usWinDescent,
5154 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5155 ft_face->ascender, ft_face->descender, ft_face->height,
5156 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5157 ft_face->bbox.yMax, ft_face->bbox.yMin);
5159 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5160 font->potm->otmSize = needed;
5162 #define TM font->potm->otmTextMetrics
5164 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5165 ascent = pHori->Ascender;
5166 descent = -pHori->Descender;
5168 ascent = pOS2->usWinAscent;
5169 descent = pOS2->usWinDescent;
5173 TM.tmAscent = font->yMax;
5174 TM.tmDescent = -font->yMin;
5175 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5177 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5178 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5179 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5180 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5183 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5186 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5188 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5189 ((ascent + descent) -
5190 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5192 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5193 if (TM.tmAveCharWidth == 0) {
5194 TM.tmAveCharWidth = 1;
5196 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5197 TM.tmWeight = (font->fake_bold || (ft_face->style_flags & FT_STYLE_FLAG_BOLD)) ? FW_BOLD : FW_REGULAR;
5199 TM.tmDigitizedAspectX = 300;
5200 TM.tmDigitizedAspectY = 300;
5201 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5202 * symbol range to 0 - f0ff
5204 if (font->charset == SYMBOL_CHARSET)
5207 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
5211 TM.tmFirstChar = pOS2->usFirstCharIndex;
5212 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0xffff;
5214 TM.tmLastChar = pOS2->usLastCharIndex;
5215 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
5216 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5217 TM.tmUnderlined = font->underline;
5218 TM.tmStruckOut = font->strikeout;
5220 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5221 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5222 (pOS2->version == 0xFFFFU ||
5223 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5224 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5226 TM.tmPitchAndFamily = 0;
5228 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
5229 case PAN_FAMILY_SCRIPT:
5230 TM.tmPitchAndFamily |= FF_SCRIPT;
5232 case PAN_FAMILY_DECORATIVE:
5233 case PAN_FAMILY_PICTORIAL:
5234 TM.tmPitchAndFamily |= FF_DECORATIVE;
5236 case PAN_FAMILY_TEXT_DISPLAY:
5237 if(TM.tmPitchAndFamily == 0) /* fixed */
5238 TM.tmPitchAndFamily = FF_MODERN;
5240 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
5241 case PAN_SERIF_NORMAL_SANS:
5242 case PAN_SERIF_OBTUSE_SANS:
5243 case PAN_SERIF_PERP_SANS:
5244 TM.tmPitchAndFamily |= FF_SWISS;
5247 TM.tmPitchAndFamily |= FF_ROMAN;
5252 TM.tmPitchAndFamily |= FF_DONTCARE;
5255 if(FT_IS_SCALABLE(ft_face))
5256 TM.tmPitchAndFamily |= TMPF_VECTOR;
5258 if(FT_IS_SFNT(ft_face))
5260 if (font->ntmFlags & NTM_PS_OPENTYPE)
5261 TM.tmPitchAndFamily |= TMPF_DEVICE;
5263 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5266 TM.tmCharSet = font->charset;
5268 font->potm->otmFiller = 0;
5269 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5270 font->potm->otmfsSelection = pOS2->fsSelection;
5271 font->potm->otmfsType = pOS2->fsType;
5272 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5273 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5274 font->potm->otmItalicAngle = 0; /* POST table */
5275 font->potm->otmEMSquare = ft_face->units_per_EM;
5276 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5277 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5278 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5279 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5280 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5281 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5282 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5283 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5284 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5285 font->potm->otmMacAscent = TM.tmAscent;
5286 font->potm->otmMacDescent = -TM.tmDescent;
5287 font->potm->otmMacLineGap = font->potm->otmLineGap;
5288 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5289 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5290 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5291 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5292 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5293 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5294 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5295 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5296 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5297 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5298 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5300 font->potm->otmsUnderscoreSize = 0;
5301 font->potm->otmsUnderscorePosition = 0;
5303 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5304 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5308 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5309 cp = (char*)font->potm + sizeof(*font->potm);
5310 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5311 strcpyW((WCHAR*)cp, family_nameW);
5313 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5314 strcpyW((WCHAR*)cp, style_nameW);
5316 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5317 strcpyW((WCHAR*)cp, family_nameW);
5318 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5319 strcatW((WCHAR*)cp, spaceW);
5320 strcatW((WCHAR*)cp, style_nameW);
5321 cp += lenfam + lensty;
5324 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5325 strcpyW((WCHAR*)cp, family_nameW);
5326 strcatW((WCHAR*)cp, spaceW);
5327 strcatW((WCHAR*)cp, style_nameW);
5330 if(potm && needed <= cbSize)
5332 memcpy(potm, font->potm, font->potm->otmSize);
5333 scale_outline_font_metrics(font, potm);
5337 HeapFree(GetProcessHeap(), 0, style_nameW);
5338 HeapFree(GetProcessHeap(), 0, family_nameW);
5340 LeaveCriticalSection( &freetype_cs );
5344 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5346 HFONTLIST *hfontlist;
5347 child->font = alloc_font();
5348 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5349 if(!child->font->ft_face)
5351 free_font(child->font);
5356 child->font->ntmFlags = child->face->ntmFlags;
5357 child->font->orientation = font->orientation;
5358 child->font->scale_y = font->scale_y;
5359 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5360 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5361 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5362 child->font->base_font = font;
5363 list_add_head(&child_font_list, &child->font->entry);
5364 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5368 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5371 CHILD_FONT *child_font;
5374 font = font->base_font;
5376 *linked_font = font;
5378 if((*glyph = get_glyph_index(font, c)))
5381 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5383 if(!child_font->font)
5384 if(!load_child_font(font, child_font))
5387 if(!child_font->font->ft_face)
5389 g = get_glyph_index(child_font->font, c);
5393 *linked_font = child_font->font;
5400 /*************************************************************
5401 * WineEngGetCharWidth
5404 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5409 FT_UInt glyph_index;
5410 GdiFont *linked_font;
5412 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5414 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] = FONT_GM(linked_font,glyph_index)->adv;
5421 LeaveCriticalSection( &freetype_cs );
5425 /*************************************************************
5426 * WineEngGetCharABCWidths
5429 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5434 FT_UInt glyph_index;
5435 GdiFont *linked_font;
5437 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5439 if(!FT_IS_SCALABLE(font->ft_face))
5442 EnterCriticalSection( &freetype_cs );
5444 for(c = firstChar; c <= lastChar; c++) {
5445 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5446 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5447 &gm, 0, NULL, NULL);
5448 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5449 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5450 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5451 FONT_GM(linked_font,glyph_index)->bbx;
5453 LeaveCriticalSection( &freetype_cs );
5457 /*************************************************************
5458 * WineEngGetCharABCWidthsI
5461 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5466 FT_UInt glyph_index;
5467 GdiFont *linked_font;
5469 if(!FT_HAS_HORIZONTAL(font->ft_face))
5472 EnterCriticalSection( &freetype_cs );
5474 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5476 for(c = firstChar; c < firstChar+count; c++) {
5477 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5478 &gm, 0, NULL, NULL);
5479 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5480 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5481 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5482 - FONT_GM(linked_font,c)->bbx;
5485 for(c = 0; c < count; c++) {
5486 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5487 &gm, 0, NULL, NULL);
5488 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5489 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5490 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5491 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5494 LeaveCriticalSection( &freetype_cs );
5498 /*************************************************************
5499 * WineEngGetTextExtentExPoint
5502 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5503 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5509 FT_UInt glyph_index;
5510 GdiFont *linked_font;
5512 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5515 EnterCriticalSection( &freetype_cs );
5518 WineEngGetTextMetrics(font, &tm);
5519 size->cy = tm.tmHeight;
5521 for(idx = 0; idx < count; idx++) {
5522 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5523 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5524 &gm, 0, NULL, NULL);
5525 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5527 if (! pnfit || ext <= max_ext) {
5537 LeaveCriticalSection( &freetype_cs );
5538 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5542 /*************************************************************
5543 * WineEngGetTextExtentExPointI
5546 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5547 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5554 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5556 EnterCriticalSection( &freetype_cs );
5559 WineEngGetTextMetrics(font, &tm);
5560 size->cy = tm.tmHeight;
5562 for(idx = 0; idx < count; idx++) {
5563 WineEngGetGlyphOutline(font, indices[idx],
5564 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
5566 size->cx += FONT_GM(font,indices[idx])->adv;
5568 if (! pnfit || ext <= max_ext) {
5578 LeaveCriticalSection( &freetype_cs );
5579 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5583 /*************************************************************
5584 * WineEngGetFontData
5587 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5590 FT_Face ft_face = font->ft_face;
5594 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5595 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
5596 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
5598 if(!FT_IS_SFNT(ft_face))
5606 if(table) { /* MS tags differ in endianness from FT ones */
5607 table = table >> 24 | table << 24 |
5608 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
5611 /* make sure value of len is the value freetype says it needs */
5614 FT_ULong needed = 0;
5615 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
5616 if( !err && needed < len) len = needed;
5618 err = load_sfnt_table(ft_face, table, offset, buf, &len);
5621 TRACE("Can't find table %c%c%c%c\n",
5622 /* bytes were reversed */
5623 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
5624 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
5630 /*************************************************************
5631 * WineEngGetTextFace
5634 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5636 INT n = strlenW(font->name) + 1;
5638 lstrcpynW(str, font->name, count);
5639 return min(count, n);
5644 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5646 if (fs) *fs = font->fs;
5647 return font->charset;
5650 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5652 GdiFont *font = dc->gdiFont, *linked_font;
5653 struct list *first_hfont;
5656 EnterCriticalSection( &freetype_cs );
5657 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
5658 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
5659 if(font == linked_font)
5660 *new_hfont = dc->hFont;
5663 first_hfont = list_head(&linked_font->hfontlist);
5664 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
5666 LeaveCriticalSection( &freetype_cs );
5670 /* Retrieve a list of supported Unicode ranges for a given font.
5671 * Can be called with NULL gs to calculate the buffer size. Returns
5672 * the number of ranges found.
5674 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
5676 DWORD num_ranges = 0;
5678 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5681 FT_ULong char_code, char_code_prev;
5684 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
5686 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5687 face->num_glyphs, glyph_code, char_code);
5689 if (!glyph_code) return 0;
5693 gs->ranges[0].wcLow = (USHORT)char_code;
5694 gs->ranges[0].cGlyphs = 0;
5695 gs->cGlyphsSupported = 0;
5701 if (char_code < char_code_prev)
5703 ERR("expected increasing char code from FT_Get_Next_Char\n");
5706 if (char_code - char_code_prev > 1)
5711 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5712 gs->ranges[num_ranges - 1].cGlyphs = 1;
5713 gs->cGlyphsSupported++;
5718 gs->ranges[num_ranges - 1].cGlyphs++;
5719 gs->cGlyphsSupported++;
5721 char_code_prev = char_code;
5722 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5726 FIXME("encoding %u not supported\n", face->charmap->encoding);
5731 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5734 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
5736 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5739 glyphset->cbThis = size;
5740 glyphset->cRanges = num_ranges;
5745 /*************************************************************
5748 BOOL WineEngFontIsLinked(GdiFont *font)
5751 EnterCriticalSection( &freetype_cs );
5752 ret = !list_empty(&font->child_fonts);
5753 LeaveCriticalSection( &freetype_cs );
5757 static BOOL is_hinting_enabled(void)
5759 /* Use the >= 2.2.0 function if available */
5760 if(pFT_Get_TrueType_Engine_Type)
5762 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
5763 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
5765 #ifdef FT_DRIVER_HAS_HINTER
5770 /* otherwise if we've been compiled with < 2.2.0 headers
5771 use the internal macro */
5772 mod = pFT_Get_Module(library, "truetype");
5773 if(mod && FT_DRIVER_HAS_HINTER(mod))
5781 /*************************************************************************
5782 * GetRasterizerCaps (GDI32.@)
5784 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5786 static int hinting = -1;
5790 hinting = is_hinting_enabled();
5791 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
5794 lprs->nSize = sizeof(RASTERIZER_STATUS);
5795 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
5796 lprs->nLanguageID = 0;
5800 /*************************************************************
5801 * WineEngRealizationInfo
5803 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
5805 FIXME("(%p, %p): stub!\n", font, info);
5808 if(FT_IS_SCALABLE(font->ft_face))
5811 info->cache_num = font->cache_num;
5812 info->unknown2 = -1;
5816 /*************************************************************************
5817 * Kerning support for TrueType fonts
5819 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5821 struct TT_kern_table
5827 struct TT_kern_subtable
5836 USHORT horizontal : 1;
5838 USHORT cross_stream: 1;
5839 USHORT override : 1;
5840 USHORT reserved1 : 4;
5846 struct TT_format0_kern_subtable
5850 USHORT entrySelector;
5861 static DWORD parse_format0_kern_subtable(GdiFont *font,
5862 const struct TT_format0_kern_subtable *tt_f0_ks,
5863 const USHORT *glyph_to_char,
5864 KERNINGPAIR *kern_pair, DWORD cPairs)
5867 const struct TT_kern_pair *tt_kern_pair;
5869 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
5871 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
5873 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5874 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
5875 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
5877 if (!kern_pair || !cPairs)
5880 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
5882 nPairs = min(nPairs, cPairs);
5884 for (i = 0; i < nPairs; i++)
5886 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
5887 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
5888 /* this algorithm appears to better match what Windows does */
5889 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
5890 if (kern_pair->iKernAmount < 0)
5892 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
5893 kern_pair->iKernAmount -= font->ppem;
5895 else if (kern_pair->iKernAmount > 0)
5897 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
5898 kern_pair->iKernAmount += font->ppem;
5900 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
5902 TRACE("left %u right %u value %d\n",
5903 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
5907 TRACE("copied %u entries\n", nPairs);
5911 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5915 const struct TT_kern_table *tt_kern_table;
5916 const struct TT_kern_subtable *tt_kern_subtable;
5918 USHORT *glyph_to_char;
5920 EnterCriticalSection( &freetype_cs );
5921 if (font->total_kern_pairs != (DWORD)-1)
5923 if (cPairs && kern_pair)
5925 cPairs = min(cPairs, font->total_kern_pairs);
5926 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5927 LeaveCriticalSection( &freetype_cs );
5930 LeaveCriticalSection( &freetype_cs );
5931 return font->total_kern_pairs;
5934 font->total_kern_pairs = 0;
5936 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5938 if (length == GDI_ERROR)
5940 TRACE("no kerning data in the font\n");
5941 LeaveCriticalSection( &freetype_cs );
5945 buf = HeapAlloc(GetProcessHeap(), 0, length);
5948 WARN("Out of memory\n");
5949 LeaveCriticalSection( &freetype_cs );
5953 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5955 /* build a glyph index to char code map */
5956 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5959 WARN("Out of memory allocating a glyph index to char code map\n");
5960 HeapFree(GetProcessHeap(), 0, buf);
5961 LeaveCriticalSection( &freetype_cs );
5965 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5971 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5973 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5974 font->ft_face->num_glyphs, glyph_code, char_code);
5978 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5980 /* FIXME: This doesn't match what Windows does: it does some fancy
5981 * things with duplicate glyph index to char code mappings, while
5982 * we just avoid overriding existing entries.
5984 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5985 glyph_to_char[glyph_code] = (USHORT)char_code;
5987 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5994 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5995 for (n = 0; n <= 65535; n++)
5996 glyph_to_char[n] = (USHORT)n;
5999 tt_kern_table = buf;
6000 nTables = GET_BE_WORD(tt_kern_table->nTables);
6001 TRACE("version %u, nTables %u\n",
6002 GET_BE_WORD(tt_kern_table->version), nTables);
6004 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6006 for (i = 0; i < nTables; i++)
6008 struct TT_kern_subtable tt_kern_subtable_copy;
6010 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6011 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6012 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6014 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6015 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6016 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6018 /* According to the TrueType specification this is the only format
6019 * that will be properly interpreted by Windows and OS/2
6021 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6023 DWORD new_chunk, old_total = font->total_kern_pairs;
6025 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6026 glyph_to_char, NULL, 0);
6027 font->total_kern_pairs += new_chunk;
6029 if (!font->kern_pairs)
6030 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6031 font->total_kern_pairs * sizeof(*font->kern_pairs));
6033 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6034 font->total_kern_pairs * sizeof(*font->kern_pairs));
6036 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6037 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6040 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6042 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6045 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6046 HeapFree(GetProcessHeap(), 0, buf);
6048 if (cPairs && kern_pair)
6050 cPairs = min(cPairs, font->total_kern_pairs);
6051 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6052 LeaveCriticalSection( &freetype_cs );
6055 LeaveCriticalSection( &freetype_cs );
6056 return font->total_kern_pairs;
6059 #else /* HAVE_FREETYPE */
6061 /*************************************************************************/
6063 BOOL WineEngInit(void)
6067 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6071 BOOL WineEngDestroyFontInstance(HFONT hfont)
6076 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6081 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6082 LPWORD pgi, DWORD flags)
6087 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6088 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6091 ERR("called but we don't have FreeType\n");
6095 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6097 ERR("called but we don't have FreeType\n");
6101 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6102 OUTLINETEXTMETRICW *potm)
6104 ERR("called but we don't have FreeType\n");
6108 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6111 ERR("called but we don't have FreeType\n");
6115 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6118 ERR("called but we don't have FreeType\n");
6122 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6125 ERR("called but we don't have FreeType\n");
6129 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6130 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6132 ERR("called but we don't have FreeType\n");
6136 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6137 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6139 ERR("called but we don't have FreeType\n");
6143 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6146 ERR("called but we don't have FreeType\n");
6150 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6152 ERR("called but we don't have FreeType\n");
6156 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6162 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6168 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6174 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6177 return DEFAULT_CHARSET;
6180 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6185 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6187 FIXME("(%p, %p): stub\n", font, glyphset);
6191 BOOL WineEngFontIsLinked(GdiFont *font)
6196 /*************************************************************************
6197 * GetRasterizerCaps (GDI32.@)
6199 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6201 lprs->nSize = sizeof(RASTERIZER_STATUS);
6203 lprs->nLanguageID = 0;
6207 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6209 ERR("called but we don't have FreeType\n");
6213 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6215 ERR("called but we don't have FreeType\n");
6219 #endif /* HAVE_FREETYPE */