2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
40 #ifdef HAVE_CARBON_CARBON_H
41 #define LoadResource __carbon_LoadResource
42 #define CompareString __carbon_CompareString
43 #define GetCurrentThread __carbon_GetCurrentThread
44 #define GetCurrentProcess __carbon_GetCurrentProcess
45 #define AnimatePalette __carbon_AnimatePalette
46 #define EqualRgn __carbon_EqualRgn
47 #define FillRgn __carbon_FillRgn
48 #define FrameRgn __carbon_FrameRgn
49 #define GetPixel __carbon_GetPixel
50 #define InvertRgn __carbon_InvertRgn
51 #define LineTo __carbon_LineTo
52 #define OffsetRgn __carbon_OffsetRgn
53 #define PaintRgn __carbon_PaintRgn
54 #define Polygon __carbon_Polygon
55 #define ResizePalette __carbon_ResizePalette
56 #define SetRectRgn __carbon_SetRectRgn
57 #include <Carbon/Carbon.h>
60 #undef GetCurrentThread
63 #undef GetCurrentProcess
76 #endif /* HAVE_CARBON_CARBON_H */
84 #include "gdi_private.h"
85 #include "wine/unicode.h"
86 #include "wine/debug.h"
87 #include "wine/list.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(font);
93 #ifdef HAVE_FT2BUILD_H
96 #ifdef HAVE_FREETYPE_FREETYPE_H
97 #include <freetype/freetype.h>
99 #ifdef HAVE_FREETYPE_FTGLYPH_H
100 #include <freetype/ftglyph.h>
102 #ifdef HAVE_FREETYPE_TTTABLES_H
103 #include <freetype/tttables.h>
105 #ifdef HAVE_FREETYPE_FTTYPES_H
106 #include <freetype/fttypes.h>
108 #ifdef HAVE_FREETYPE_FTSNAMES_H
109 #include <freetype/ftsnames.h>
111 # ifdef HAVE_FREETYPE_FTNAMES_H
112 # include <freetype/ftnames.h>
115 #ifdef HAVE_FREETYPE_TTNAMEID_H
116 #include <freetype/ttnameid.h>
118 #ifdef HAVE_FREETYPE_FTOUTLN_H
119 #include <freetype/ftoutln.h>
121 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
122 #include <freetype/internal/sfnt.h>
124 #ifdef HAVE_FREETYPE_FTTRIGON_H
125 #include <freetype/fttrigon.h>
127 #ifdef HAVE_FREETYPE_FTWINFNT_H
128 #include <freetype/ftwinfnt.h>
130 #ifdef HAVE_FREETYPE_FTMODAPI_H
131 #include <freetype/ftmodapi.h>
134 #ifndef HAVE_FT_TRUETYPEENGINETYPE
137 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
138 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
139 FT_TRUETYPE_ENGINE_TYPE_PATENTED
140 } FT_TrueTypeEngineType;
143 static FT_Library library = 0;
150 static FT_Version_t FT_Version;
151 static DWORD FT_SimpleVersion;
153 static void *ft_handle = NULL;
155 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
156 MAKE_FUNCPTR(FT_Vector_Unit);
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_Module);
160 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
163 MAKE_FUNCPTR(FT_Init_FreeType);
164 MAKE_FUNCPTR(FT_Load_Glyph);
165 MAKE_FUNCPTR(FT_Matrix_Multiply);
166 MAKE_FUNCPTR(FT_MulFix);
167 MAKE_FUNCPTR(FT_New_Face);
168 MAKE_FUNCPTR(FT_New_Memory_Face);
169 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
170 MAKE_FUNCPTR(FT_Outline_Transform);
171 MAKE_FUNCPTR(FT_Outline_Translate);
172 MAKE_FUNCPTR(FT_Select_Charmap);
173 MAKE_FUNCPTR(FT_Set_Charmap);
174 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
175 MAKE_FUNCPTR(FT_Vector_Transform);
176 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
177 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
178 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
179 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
180 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
181 #ifdef HAVE_FREETYPE_FTWINFNT_H
182 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
185 #ifdef SONAME_LIBFONTCONFIG
186 #include <fontconfig/fontconfig.h>
187 MAKE_FUNCPTR(FcConfigGetCurrent);
188 MAKE_FUNCPTR(FcFontList);
189 MAKE_FUNCPTR(FcFontSetDestroy);
190 MAKE_FUNCPTR(FcInit);
191 MAKE_FUNCPTR(FcObjectSetAdd);
192 MAKE_FUNCPTR(FcObjectSetCreate);
193 MAKE_FUNCPTR(FcObjectSetDestroy);
194 MAKE_FUNCPTR(FcPatternCreate);
195 MAKE_FUNCPTR(FcPatternDestroy);
196 MAKE_FUNCPTR(FcPatternGetBool);
197 MAKE_FUNCPTR(FcPatternGetString);
203 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
204 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
205 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
208 #ifndef ft_encoding_none
209 #define FT_ENCODING_NONE ft_encoding_none
211 #ifndef ft_encoding_ms_symbol
212 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
214 #ifndef ft_encoding_unicode
215 #define FT_ENCODING_UNICODE ft_encoding_unicode
217 #ifndef ft_encoding_apple_roman
218 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
221 #ifdef WORDS_BIGENDIAN
222 #define GET_BE_WORD(x) (x)
224 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
227 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
234 FT_Short internal_leading;
237 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
238 So to let this compile on older versions of FreeType we'll define the
239 new structure here. */
241 FT_Short height, width;
242 FT_Pos size, x_ppem, y_ppem;
248 NEWTEXTMETRICEXW ntm;
252 typedef struct tagFace {
257 DWORD font_data_size;
262 FONTSIGNATURE fs_links;
263 DWORD ntmFlags; /* Only some bits stored here. Others are computed on the fly */
264 FT_Fixed font_version;
266 Bitmap_Size size; /* set if face is a bitmap */
267 BOOL external; /* TRUE if we should manually add this font to the registry */
268 struct tagFamily *family;
269 /* Cached data for Enum */
270 struct enum_data *cached_enum_data;
273 typedef struct tagFamily {
275 const WCHAR *FamilyName;
281 INT adv; /* These three hold to widths of the unrotated chars */
299 typedef struct tagHFONTLIST {
314 struct list hfontlist;
315 OUTLINETEXTMETRICW *potm;
316 DWORD total_kern_pairs;
317 KERNINGPAIR *kern_pairs;
318 struct list child_fonts;
320 /* the following members can be accessed without locking, they are never modified after creation */
322 struct font_mapping *mapping;
344 const WCHAR *font_name;
348 #define GM_BLOCK_SIZE 128
349 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
351 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
352 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
353 #define UNUSED_CACHE_SIZE 10
354 static struct list child_font_list = LIST_INIT(child_font_list);
355 static struct list system_links = LIST_INIT(system_links);
357 static struct list font_subst_list = LIST_INIT(font_subst_list);
359 static struct list font_list = LIST_INIT(font_list);
361 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
362 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
363 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
365 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
367 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
368 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
369 'W','i','n','d','o','w','s','\\',
370 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
371 'F','o','n','t','s','\0'};
373 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
374 'W','i','n','d','o','w','s',' ','N','T','\\',
375 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
376 'F','o','n','t','s','\0'};
378 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
379 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
380 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
381 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
383 static const WCHAR * const SystemFontValues[4] = {
390 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
391 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
393 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
394 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
395 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
396 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
397 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
398 'E','u','r','o','p','e','a','n','\0'};
399 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
400 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
401 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
402 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
403 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
404 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
405 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
406 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
407 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
408 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
409 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
410 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
412 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
422 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
430 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
439 typedef struct tagFontSubst {
455 static struct list mappings_list = LIST_INIT( mappings_list );
457 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
459 static CRITICAL_SECTION freetype_cs;
460 static CRITICAL_SECTION_DEBUG critsect_debug =
463 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
464 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
466 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
468 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
470 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
471 static BOOL use_default_fallback = FALSE;
473 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
475 /****************************************
476 * Notes on .fon files
478 * The fonts System, FixedSys and Terminal are special. There are typically multiple
479 * versions installed for different resolutions and codepages. Windows stores which one to use
480 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
482 * FIXEDFON.FON FixedSys
484 * OEMFONT.FON Terminal
485 * LogPixels Current dpi set by the display control panel applet
486 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
487 * also has a LogPixels value that appears to mirror this)
489 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
490 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
491 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
492 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
493 * so that makes sense.
495 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
496 * to be mapped into the registry on Windows 2000 at least).
499 * ega80woa.fon=ega80850.fon
500 * ega40woa.fon=ega40850.fon
501 * cga80woa.fon=cga80850.fon
502 * cga40woa.fon=cga40850.fon
505 /* These are all structures needed for the GSUB table */
507 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
508 #define TATEGAKI_LOWER_BOUND 0x02F1
524 GSUB_ScriptRecord ScriptRecord[1];
530 } GSUB_LangSysRecord;
535 GSUB_LangSysRecord LangSysRecord[1];
539 WORD LookupOrder; /* Reserved */
540 WORD ReqFeatureIndex;
542 WORD FeatureIndex[1];
548 } GSUB_FeatureRecord;
552 GSUB_FeatureRecord FeatureRecord[1];
556 WORD FeatureParams; /* Reserved */
558 WORD LookupListIndex[1];
577 } GSUB_CoverageFormat1;
582 WORD StartCoverageIndex;
588 GSUB_RangeRecord RangeRecord[1];
589 } GSUB_CoverageFormat2;
592 WORD SubstFormat; /* = 1 */
595 } GSUB_SingleSubstFormat1;
598 WORD SubstFormat; /* = 2 */
602 }GSUB_SingleSubstFormat2;
604 #ifdef HAVE_CARBON_CARBON_H
605 static char *find_cache_dir(void)
609 static char cached_path[MAX_PATH];
610 static const char *wine = "/Wine", *fonts = "/Fonts";
612 if(*cached_path) return cached_path;
614 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
617 WARN("can't create cached data folder\n");
620 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
623 WARN("can't create cached data path\n");
627 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
629 ERR("Could not create full path\n");
633 strcat(cached_path, wine);
635 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
637 WARN("Couldn't mkdir %s\n", cached_path);
641 strcat(cached_path, fonts);
642 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
644 WARN("Couldn't mkdir %s\n", cached_path);
651 /******************************************************************
654 * Extracts individual TrueType font files from a Mac suitcase font
655 * and saves them into the user's caches directory (see
657 * Returns a NULL terminated array of filenames.
659 * We do this because they are apps that try to read ttf files
660 * themselves and they don't like Mac suitcase files.
662 static char **expand_mac_font(const char *path)
669 const char *filename;
673 unsigned int size, max_size;
676 TRACE("path %s\n", path);
678 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
681 WARN("failed to get ref\n");
685 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
688 TRACE("no data fork, so trying resource fork\n");
689 res_ref = FSOpenResFile(&ref, fsRdPerm);
692 TRACE("unable to open resource fork\n");
699 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
702 CloseResFile(res_ref);
706 out_dir = find_cache_dir();
708 filename = strrchr(path, '/');
709 if(!filename) filename = path;
712 /* output filename has the form out_dir/filename_%04x.ttf */
713 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
720 unsigned short *num_faces_ptr, num_faces, face;
723 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
725 fond = Get1IndResource(fond_res, idx);
727 TRACE("got fond resource %d\n", idx);
730 fam_rec = *(FamRec**)fond;
731 num_faces_ptr = (unsigned short *)(fam_rec + 1);
732 num_faces = GET_BE_WORD(*num_faces_ptr);
734 assoc = (AsscEntry*)(num_faces_ptr + 1);
735 TRACE("num faces %04x\n", num_faces);
736 for(face = 0; face < num_faces; face++, assoc++)
739 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
740 unsigned short size, font_id;
743 size = GET_BE_WORD(assoc->fontSize);
744 font_id = GET_BE_WORD(assoc->fontID);
747 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
751 TRACE("trying to load sfnt id %04x\n", font_id);
752 sfnt = GetResource(sfnt_res, font_id);
755 TRACE("can't get sfnt resource %04x\n", font_id);
759 output = HeapAlloc(GetProcessHeap(), 0, output_len);
764 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
766 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
767 if(fd != -1 || errno == EEXIST)
771 unsigned char *sfnt_data;
774 sfnt_data = *(unsigned char**)sfnt;
775 write(fd, sfnt_data, GetHandleSize(sfnt));
779 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
782 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
784 ret.array[ret.size++] = output;
788 WARN("unable to create %s\n", output);
789 HeapFree(GetProcessHeap(), 0, output);
792 ReleaseResource(sfnt);
795 ReleaseResource(fond);
798 CloseResFile(res_ref);
803 #endif /* HAVE_CARBON_CARBON_H */
805 static inline BOOL is_win9x(void)
807 return GetVersion() & 0x80000000;
810 This function builds an FT_Fixed from a float. It puts the integer part
811 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
812 It fails if the integer part of the float number is greater than SHORT_MAX.
814 static inline FT_Fixed FT_FixedFromFloat(float f)
817 unsigned short fract = (f - value) * 0xFFFF;
818 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
822 This function builds an FT_Fixed from a FIXED. It simply put f.value
823 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
825 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
827 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
831 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
836 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
837 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
839 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
840 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
842 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
844 if(face_name && strcmpiW(face_name, family->FamilyName))
846 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
850 file = strrchr(face->file, '/');
855 if(!strcasecmp(file, file_nameA))
857 HeapFree(GetProcessHeap(), 0, file_nameA);
862 HeapFree(GetProcessHeap(), 0, file_nameA);
866 static Family *find_family_from_name(const WCHAR *name)
870 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
872 if(!strcmpiW(family->FamilyName, name))
879 static void DumpSubstList(void)
883 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
885 if(psub->from.charset != -1 || psub->to.charset != -1)
886 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
887 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
889 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
890 debugstr_w(psub->to.name));
895 static LPWSTR strdupW(LPCWSTR p)
898 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
899 ret = HeapAlloc(GetProcessHeap(), 0, len);
904 static LPSTR strdupA(LPCSTR p)
907 DWORD len = (strlen(p) + 1);
908 ret = HeapAlloc(GetProcessHeap(), 0, len);
913 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
918 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
920 if(!strcmpiW(element->from.name, from_name) &&
921 (element->from.charset == from_charset ||
922 element->from.charset == -1))
929 #define ADD_FONT_SUBST_FORCE 1
931 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
933 FontSubst *from_exist, *to_exist;
935 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
937 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
939 list_remove(&from_exist->entry);
940 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
941 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
942 HeapFree(GetProcessHeap(), 0, from_exist);
948 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
952 HeapFree(GetProcessHeap(), 0, subst->to.name);
953 subst->to.name = strdupW(to_exist->to.name);
956 list_add_tail(subst_list, &subst->entry);
961 HeapFree(GetProcessHeap(), 0, subst->from.name);
962 HeapFree(GetProcessHeap(), 0, subst->to.name);
963 HeapFree(GetProcessHeap(), 0, subst);
967 static void split_subst_info(NameCs *nc, LPSTR str)
969 CHAR *p = strrchr(str, ',');
974 nc->charset = strtol(p+1, NULL, 10);
977 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
978 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
979 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
982 static void LoadSubstList(void)
986 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
990 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
991 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
992 &hkey) == ERROR_SUCCESS) {
994 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
995 &valuelen, &datalen, NULL, NULL);
997 valuelen++; /* returned value doesn't include room for '\0' */
998 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
999 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1003 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1004 &dlen) == ERROR_SUCCESS) {
1005 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1007 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1008 split_subst_info(&psub->from, value);
1009 split_subst_info(&psub->to, data);
1011 /* Win 2000 doesn't allow mapping between different charsets
1012 or mapping of DEFAULT_CHARSET */
1013 if((psub->to.charset != psub->from.charset) ||
1014 psub->to.charset == DEFAULT_CHARSET) {
1015 HeapFree(GetProcessHeap(), 0, psub->to.name);
1016 HeapFree(GetProcessHeap(), 0, psub->from.name);
1017 HeapFree(GetProcessHeap(), 0, psub);
1019 add_font_subst(&font_subst_list, psub, 0);
1021 /* reset dlen and vlen */
1025 HeapFree(GetProcessHeap(), 0, data);
1026 HeapFree(GetProcessHeap(), 0, value);
1031 static WCHAR *get_familyname(FT_Face ft_face)
1033 WCHAR *family = NULL;
1035 FT_UInt num_names, name_index, i;
1037 if(FT_IS_SFNT(ft_face))
1039 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1041 for(name_index = 0; name_index < num_names; name_index++)
1043 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1045 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
1046 (name.language_id == GetUserDefaultLCID()) &&
1047 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
1048 (name.encoding_id == TT_MS_ID_UNICODE_CS))
1050 /* String is not nul terminated and string_len is a byte length. */
1051 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1052 for(i = 0; i < name.string_len / 2; i++)
1054 WORD *tmp = (WORD *)&name.string[i * 2];
1055 family[i] = GET_BE_WORD(*tmp);
1059 TRACE("Got localised name %s\n", debugstr_w(family));
1070 /*****************************************************************
1073 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1074 * of FreeType that don't export this function.
1077 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1082 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1083 if(pFT_Load_Sfnt_Table)
1085 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1087 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1088 else /* Do it the hard way */
1090 TT_Face tt_face = (TT_Face) ft_face;
1091 SFNT_Interface *sfnt;
1092 if (FT_Version.major==2 && FT_Version.minor==0)
1095 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1099 /* A field was added in the middle of the structure in 2.1.x */
1100 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1102 err = sfnt->load_any(tt_face, table, offset, buf, len);
1110 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1111 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1112 "Please upgrade your freetype library.\n");
1115 err = FT_Err_Unimplemented_Feature;
1122 #define ADDFONT_EXTERNAL_FONT 0x01
1123 #define ADDFONT_FORCE_BITMAP 0x02
1124 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1128 TT_Header *pHeader = NULL;
1129 WCHAR *english_family, *localised_family, *StyleW;
1133 struct list *family_elem_ptr, *face_elem_ptr;
1135 FT_Long face_index = 0, num_faces;
1136 #ifdef HAVE_FREETYPE_FTWINFNT_H
1137 FT_WinFNT_HeaderRec winfnt_header;
1139 int i, bitmap_num, internal_leading;
1142 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1143 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1145 #ifdef HAVE_CARBON_CARBON_H
1146 if(file && !fake_family)
1148 char **mac_list = expand_mac_font(file);
1151 BOOL had_one = FALSE;
1153 for(cursor = mac_list; *cursor; cursor++)
1156 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1157 HeapFree(GetProcessHeap(), 0, *cursor);
1159 HeapFree(GetProcessHeap(), 0, mac_list);
1164 #endif /* HAVE_CARBON_CARBON_H */
1167 char *family_name = fake_family;
1171 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1172 err = pFT_New_Face(library, file, face_index, &ft_face);
1175 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1176 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1180 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1184 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*/
1185 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1186 pFT_Done_Face(ft_face);
1190 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1191 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1192 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1193 pFT_Done_Face(ft_face);
1197 if(FT_IS_SFNT(ft_face))
1199 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1200 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1201 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1203 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1204 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1205 pFT_Done_Face(ft_face);
1209 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1210 we don't want to load these. */
1211 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1215 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1217 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1218 pFT_Done_Face(ft_face);
1224 if(!ft_face->family_name || !ft_face->style_name) {
1225 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1226 pFT_Done_Face(ft_face);
1230 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1232 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1233 pFT_Done_Face(ft_face);
1239 localised_family = get_familyname(ft_face);
1240 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1242 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1243 HeapFree(GetProcessHeap(), 0, localised_family);
1244 num_faces = ft_face->num_faces;
1245 pFT_Done_Face(ft_face);
1248 HeapFree(GetProcessHeap(), 0, localised_family);
1252 family_name = ft_face->family_name;
1256 My_FT_Bitmap_Size *size = NULL;
1259 if(!FT_IS_SCALABLE(ft_face))
1260 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1262 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1263 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1264 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1266 localised_family = NULL;
1268 localised_family = get_familyname(ft_face);
1269 if(localised_family && !strcmpW(localised_family, english_family)) {
1270 HeapFree(GetProcessHeap(), 0, localised_family);
1271 localised_family = NULL;
1276 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1277 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1278 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1283 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1284 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1285 list_init(&family->faces);
1286 list_add_tail(&font_list, &family->entry);
1288 if(localised_family) {
1289 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1290 subst->from.name = strdupW(english_family);
1291 subst->from.charset = -1;
1292 subst->to.name = strdupW(localised_family);
1293 subst->to.charset = -1;
1294 add_font_subst(&font_subst_list, subst, 0);
1297 HeapFree(GetProcessHeap(), 0, localised_family);
1298 HeapFree(GetProcessHeap(), 0, english_family);
1300 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1301 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1302 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1304 internal_leading = 0;
1305 memset(&fs, 0, sizeof(fs));
1307 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1309 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1310 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1311 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1312 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1313 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1314 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1315 if(pOS2->version == 0) {
1318 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1319 fs.fsCsb[0] |= FS_LATIN1;
1321 fs.fsCsb[0] |= FS_SYMBOL;
1324 #ifdef HAVE_FREETYPE_FTWINFNT_H
1325 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1327 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1328 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1329 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1331 internal_leading = winfnt_header.internal_leading;
1335 face_elem_ptr = list_head(&family->faces);
1336 while(face_elem_ptr) {
1337 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1338 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1339 if(!strcmpW(face->StyleName, StyleW) &&
1340 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1341 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1342 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1343 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1346 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1347 HeapFree(GetProcessHeap(), 0, StyleW);
1348 pFT_Done_Face(ft_face);
1351 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1352 TRACE("Original font is newer so skipping this one\n");
1353 HeapFree(GetProcessHeap(), 0, StyleW);
1354 pFT_Done_Face(ft_face);
1357 TRACE("Replacing original with this one\n");
1358 list_remove(&face->entry);
1359 HeapFree(GetProcessHeap(), 0, face->file);
1360 HeapFree(GetProcessHeap(), 0, face->StyleName);
1361 HeapFree(GetProcessHeap(), 0, face);
1366 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1367 face->cached_enum_data = NULL;
1368 list_add_tail(&family->faces, &face->entry);
1369 face->StyleName = StyleW;
1372 face->file = strdupA(file);
1373 face->font_data_ptr = NULL;
1374 face->font_data_size = 0;
1379 face->font_data_ptr = font_data_ptr;
1380 face->font_data_size = font_data_size;
1382 face->face_index = face_index;
1383 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
1384 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
1385 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1386 face->family = family;
1387 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1389 memset(&face->fs_links, 0, sizeof(face->fs_links));
1391 if(FT_IS_SCALABLE(ft_face)) {
1392 memset(&face->size, 0, sizeof(face->size));
1393 face->scalable = TRUE;
1395 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1396 size->height, size->width, size->size >> 6,
1397 size->x_ppem >> 6, size->y_ppem >> 6);
1398 face->size.height = size->height;
1399 face->size.width = size->width;
1400 face->size.size = size->size;
1401 face->size.x_ppem = size->x_ppem;
1402 face->size.y_ppem = size->y_ppem;
1403 face->size.internal_leading = internal_leading;
1404 face->scalable = FALSE;
1407 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1409 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1411 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1412 face->ntmFlags = NTM_PS_OPENTYPE;
1417 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1418 face->fs.fsCsb[0], face->fs.fsCsb[1],
1419 face->fs.fsUsb[0], face->fs.fsUsb[1],
1420 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1423 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1424 for(i = 0; i < ft_face->num_charmaps; i++) {
1425 switch(ft_face->charmaps[i]->encoding) {
1426 case FT_ENCODING_UNICODE:
1427 case FT_ENCODING_APPLE_ROMAN:
1428 face->fs.fsCsb[0] |= FS_LATIN1;
1430 case FT_ENCODING_MS_SYMBOL:
1431 face->fs.fsCsb[0] |= FS_SYMBOL;
1439 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1440 have_installed_roman_font = TRUE;
1441 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1443 num_faces = ft_face->num_faces;
1444 pFT_Done_Face(ft_face);
1445 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1446 debugstr_w(StyleW));
1447 } while(num_faces > ++face_index);
1451 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1453 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1456 static void DumpFontList(void)
1460 struct list *family_elem_ptr, *face_elem_ptr;
1462 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1463 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1464 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1465 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1466 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1467 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1469 TRACE(" %d", face->size.height);
1476 /***********************************************************
1477 * The replacement list is a way to map an entire font
1478 * family onto another family. For example adding
1480 * [HKCU\Software\Wine\Fonts\Replacements]
1481 * "Wingdings"="Winedings"
1483 * would enumerate the Winedings font both as Winedings and
1484 * Wingdings. However if a real Wingdings font is present the
1485 * replacement does not take place.
1488 static void LoadReplaceList(void)
1491 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1496 struct list *family_elem_ptr, *face_elem_ptr;
1499 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1500 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1502 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1503 &valuelen, &datalen, NULL, NULL);
1505 valuelen++; /* returned value doesn't include room for '\0' */
1506 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1507 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1511 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1512 &dlen) == ERROR_SUCCESS) {
1513 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1514 /* "NewName"="Oldname" */
1515 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1517 /* Find the old family and hence all of the font files
1519 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1520 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1521 if(!strcmpiW(family->FamilyName, data)) {
1522 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1523 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1524 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1525 debugstr_w(face->StyleName), familyA);
1526 /* Now add a new entry with the new family name */
1527 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1532 /* reset dlen and vlen */
1536 HeapFree(GetProcessHeap(), 0, data);
1537 HeapFree(GetProcessHeap(), 0, value);
1542 /*************************************************************
1545 static BOOL init_system_links(void)
1547 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1548 'W','i','n','d','o','w','s',' ','N','T','\\',
1549 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1550 'S','y','s','t','e','m','L','i','n','k',0};
1553 DWORD type, max_val, max_data, val_len, data_len, index;
1554 WCHAR *value, *data;
1555 WCHAR *entry, *next;
1556 SYSTEM_LINKS *font_link, *system_font_link;
1557 CHILD_FONT *child_font;
1558 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1559 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1560 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1566 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1568 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1569 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1570 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1571 val_len = max_val + 1;
1572 data_len = max_data;
1574 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1576 TRACE("%s:\n", debugstr_w(value));
1578 memset(&fs, 0, sizeof(fs));
1579 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1580 psub = get_font_subst(&font_subst_list, value, -1);
1581 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1582 list_init(&font_link->links);
1583 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1586 CHILD_FONT *child_font;
1588 TRACE("\t%s\n", debugstr_w(entry));
1590 next = entry + strlenW(entry) + 1;
1592 face_name = strchrW(entry, ',');
1596 while(isspaceW(*face_name))
1599 psub = get_font_subst(&font_subst_list, face_name, -1);
1601 face_name = psub->to.name;
1603 face = find_face_from_filename(entry, face_name);
1606 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1610 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1611 child_font->face = face;
1612 child_font->font = NULL;
1613 fs.fsCsb[0] |= face->fs.fsCsb[0];
1614 fs.fsCsb[1] |= face->fs.fsCsb[1];
1615 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1616 list_add_tail(&font_link->links, &child_font->entry);
1618 family = find_family_from_name(font_link->font_name);
1621 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1623 face->fs_links = fs;
1626 list_add_tail(&system_links, &font_link->entry);
1627 val_len = max_val + 1;
1628 data_len = max_data;
1631 HeapFree(GetProcessHeap(), 0, value);
1632 HeapFree(GetProcessHeap(), 0, data);
1636 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1639 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1640 system_font_link->font_name = strdupW(System);
1641 list_init(&system_font_link->links);
1643 face = find_face_from_filename(tahoma_ttf, Tahoma);
1646 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1647 child_font->face = face;
1648 child_font->font = NULL;
1649 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1650 list_add_tail(&system_font_link->links, &child_font->entry);
1652 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1654 if(!strcmpiW(font_link->font_name, Tahoma))
1656 CHILD_FONT *font_link_entry;
1657 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1659 CHILD_FONT *new_child;
1660 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1661 new_child->face = font_link_entry->face;
1662 new_child->font = NULL;
1663 list_add_tail(&system_font_link->links, &new_child->entry);
1668 list_add_tail(&system_links, &system_font_link->entry);
1672 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1675 struct dirent *dent;
1676 char path[MAX_PATH];
1678 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1680 dir = opendir(dirname);
1682 WARN("Can't open directory %s\n", debugstr_a(dirname));
1685 while((dent = readdir(dir)) != NULL) {
1686 struct stat statbuf;
1688 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1691 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1693 sprintf(path, "%s/%s", dirname, dent->d_name);
1695 if(stat(path, &statbuf) == -1)
1697 WARN("Can't stat %s\n", debugstr_a(path));
1700 if(S_ISDIR(statbuf.st_mode))
1701 ReadFontDir(path, external_fonts);
1703 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1709 static void load_fontconfig_fonts(void)
1711 #ifdef SONAME_LIBFONTCONFIG
1712 void *fc_handle = NULL;
1721 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1723 TRACE("Wine cannot find the fontconfig library (%s).\n",
1724 SONAME_LIBFONTCONFIG);
1727 #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;}
1728 LOAD_FUNCPTR(FcConfigGetCurrent);
1729 LOAD_FUNCPTR(FcFontList);
1730 LOAD_FUNCPTR(FcFontSetDestroy);
1731 LOAD_FUNCPTR(FcInit);
1732 LOAD_FUNCPTR(FcObjectSetAdd);
1733 LOAD_FUNCPTR(FcObjectSetCreate);
1734 LOAD_FUNCPTR(FcObjectSetDestroy);
1735 LOAD_FUNCPTR(FcPatternCreate);
1736 LOAD_FUNCPTR(FcPatternDestroy);
1737 LOAD_FUNCPTR(FcPatternGetBool);
1738 LOAD_FUNCPTR(FcPatternGetString);
1741 if(!pFcInit()) return;
1743 config = pFcConfigGetCurrent();
1744 pat = pFcPatternCreate();
1745 os = pFcObjectSetCreate();
1746 pFcObjectSetAdd(os, FC_FILE);
1747 pFcObjectSetAdd(os, FC_SCALABLE);
1748 fontset = pFcFontList(config, pat, os);
1749 if(!fontset) return;
1750 for(i = 0; i < fontset->nfont; i++) {
1753 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1755 TRACE("fontconfig: %s\n", file);
1757 /* We're just interested in OT/TT fonts for now, so this hack just
1758 picks up the scalable fonts without extensions .pf[ab] to save time
1759 loading every other font */
1761 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1763 TRACE("not scalable\n");
1767 len = strlen( file );
1768 if(len < 4) continue;
1769 ext = &file[ len - 3 ];
1770 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1771 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1773 pFcFontSetDestroy(fontset);
1774 pFcObjectSetDestroy(os);
1775 pFcPatternDestroy(pat);
1781 static BOOL load_font_from_data_dir(LPCWSTR file)
1784 const char *data_dir = wine_get_data_dir();
1786 if (!data_dir) data_dir = wine_get_build_dir();
1793 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1795 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1797 strcpy(unix_name, data_dir);
1798 strcat(unix_name, "/fonts/");
1800 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1802 EnterCriticalSection( &freetype_cs );
1803 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1804 LeaveCriticalSection( &freetype_cs );
1805 HeapFree(GetProcessHeap(), 0, unix_name);
1810 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1812 static const WCHAR slashW[] = {'\\','\0'};
1814 WCHAR windowsdir[MAX_PATH];
1817 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1818 strcatW(windowsdir, fontsW);
1819 strcatW(windowsdir, slashW);
1820 strcatW(windowsdir, file);
1821 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1822 EnterCriticalSection( &freetype_cs );
1823 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1824 LeaveCriticalSection( &freetype_cs );
1825 HeapFree(GetProcessHeap(), 0, unixname);
1830 static void load_system_fonts(void)
1833 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1834 const WCHAR * const *value;
1836 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1839 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1840 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1841 strcatW(windowsdir, fontsW);
1842 for(value = SystemFontValues; *value; value++) {
1843 dlen = sizeof(data);
1844 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1848 sprintfW(pathW, fmtW, windowsdir, data);
1849 if((unixname = wine_get_unix_file_name(pathW))) {
1850 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1851 HeapFree(GetProcessHeap(), 0, unixname);
1854 load_font_from_data_dir(data);
1861 /*************************************************************
1863 * This adds registry entries for any externally loaded fonts
1864 * (fonts from fontconfig or FontDirs). It also deletes entries
1865 * of no longer existing fonts.
1868 static void update_reg_entries(void)
1870 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1875 struct list *family_elem_ptr, *face_elem_ptr;
1877 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1878 static const WCHAR spaceW[] = {' ', '\0'};
1881 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1882 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1883 ERR("Can't create Windows font reg key\n");
1887 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1888 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1889 ERR("Can't create Windows font reg key\n");
1893 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1894 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1895 ERR("Can't create external font reg key\n");
1899 /* enumerate the fonts and add external ones to the two keys */
1901 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1902 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1903 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1904 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1905 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1906 if(!face->external) continue;
1908 if(strcmpiW(face->StyleName, RegularW))
1909 len = len_fam + strlenW(face->StyleName) + 1;
1910 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1911 strcpyW(valueW, family->FamilyName);
1912 if(len != len_fam) {
1913 strcatW(valueW, spaceW);
1914 strcatW(valueW, face->StyleName);
1916 strcatW(valueW, TrueType);
1918 file = wine_get_dos_file_name(face->file);
1920 len = strlenW(file) + 1;
1923 if((path = strrchr(face->file, '/')) == NULL)
1927 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1929 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1930 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1932 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1933 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1934 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1936 HeapFree(GetProcessHeap(), 0, file);
1937 HeapFree(GetProcessHeap(), 0, valueW);
1941 if(external_key) RegCloseKey(external_key);
1942 if(win9x_key) RegCloseKey(win9x_key);
1943 if(winnt_key) RegCloseKey(winnt_key);
1947 static void delete_external_font_keys(void)
1949 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1950 DWORD dlen, vlen, datalen, valuelen, i, type;
1954 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1955 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1956 ERR("Can't create Windows font reg key\n");
1960 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1961 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1962 ERR("Can't create Windows font reg key\n");
1966 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
1967 ERR("Can't create external font reg key\n");
1971 /* Delete all external fonts added last time */
1973 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1974 &valuelen, &datalen, NULL, NULL);
1975 valuelen++; /* returned value doesn't include room for '\0' */
1976 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1977 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1979 dlen = datalen * sizeof(WCHAR);
1982 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
1983 &dlen) == ERROR_SUCCESS) {
1985 RegDeleteValueW(winnt_key, valueW);
1986 RegDeleteValueW(win9x_key, valueW);
1987 /* reset dlen and vlen */
1991 HeapFree(GetProcessHeap(), 0, data);
1992 HeapFree(GetProcessHeap(), 0, valueW);
1994 /* Delete the old external fonts key */
1995 RegCloseKey(external_key);
1996 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1999 if(win9x_key) RegCloseKey(win9x_key);
2000 if(winnt_key) RegCloseKey(winnt_key);
2003 /*************************************************************
2004 * WineEngAddFontResourceEx
2007 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2010 if (ft_handle) /* do it only if we have freetype up and running */
2015 FIXME("Ignoring flags %x\n", flags);
2017 if((unixname = wine_get_unix_file_name(file)))
2019 EnterCriticalSection( &freetype_cs );
2020 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2021 LeaveCriticalSection( &freetype_cs );
2022 HeapFree(GetProcessHeap(), 0, unixname);
2024 if (!ret && !strchrW(file, '\\')) {
2025 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2026 ret = load_font_from_winfonts_dir(file);
2028 /* Try in datadir/fonts (or builddir/fonts),
2029 * needed for Magic the Gathering Online
2031 ret = load_font_from_data_dir(file);
2038 /*************************************************************
2039 * WineEngAddFontMemResourceEx
2042 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2044 if (ft_handle) /* do it only if we have freetype up and running */
2046 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2048 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2049 memcpy(pFontCopy, pbFont, cbFont);
2051 EnterCriticalSection( &freetype_cs );
2052 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2053 LeaveCriticalSection( &freetype_cs );
2057 TRACE("AddFontToList failed\n");
2058 HeapFree(GetProcessHeap(), 0, pFontCopy);
2061 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2062 * For now return something unique but quite random
2064 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2065 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2072 /*************************************************************
2073 * WineEngRemoveFontResourceEx
2076 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2082 static const struct nls_update_font_list
2084 UINT ansi_cp, oem_cp;
2085 const char *oem, *fixed, *system;
2086 const char *courier, *serif, *small, *sserif;
2087 /* these are for font substitute */
2088 const char *shelldlg, *tmsrmn;
2089 } nls_update_font_list[] =
2091 /* Latin 1 (United States) */
2092 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2093 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2094 "Tahoma","Times New Roman",
2096 /* Latin 1 (Multilingual) */
2097 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2098 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2099 "Tahoma","Times New Roman", /* FIXME unverified */
2101 /* Eastern Europe */
2102 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2103 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2104 "Tahoma","Times New Roman", /* FIXME unverified */
2107 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2108 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2109 "Tahoma","Times New Roman", /* FIXME unverified */
2112 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2113 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2114 "Tahoma","Times New Roman", /* FIXME unverified */
2117 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2118 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2119 "Tahoma","Times New Roman", /* FIXME unverified */
2122 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2123 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2124 "Tahoma","Times New Roman", /* FIXME unverified */
2127 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2128 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2129 "Tahoma","Times New Roman", /* FIXME unverified */
2132 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2133 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2134 "Tahoma","Times New Roman", /* FIXME unverified */
2137 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2138 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2139 "Tahoma","Times New Roman", /* FIXME unverified */
2142 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2143 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2144 "Tahoma","Times New Roman", /* FIXME unverified */
2147 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2148 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2149 "MS UI Gothic","MS Serif",
2151 /* Chinese Simplified */
2152 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2153 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2154 "Tahoma", "Times New Roman", /* FIXME unverified */
2157 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2158 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2161 /* Chinese Traditional */
2162 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2163 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2164 "PMingLiU", "MingLiU",
2168 static inline HKEY create_fonts_NT_registry_key(void)
2172 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2173 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2177 static inline HKEY create_fonts_9x_registry_key(void)
2181 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2182 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2186 static inline HKEY create_config_fonts_registry_key(void)
2190 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2191 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2195 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2197 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2198 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2199 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2200 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2203 static void update_font_info(void)
2205 char buf[40], cpbuf[40];
2208 UINT i, ansi_cp = 0, oem_cp = 0;
2210 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2213 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2214 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2215 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2216 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2217 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2219 /* Setup DefaultFallback usage */
2221 use_default_fallback = TRUE;
2224 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2226 if (!strcmp( buf, cpbuf )) /* already set correctly */
2231 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2233 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2235 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2238 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2240 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2241 nls_update_font_list[i].oem_cp == oem_cp)
2245 hkey = create_config_fonts_registry_key();
2246 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2247 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2248 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2251 hkey = create_fonts_NT_registry_key();
2252 add_font_list(hkey, &nls_update_font_list[i]);
2255 hkey = create_fonts_9x_registry_key();
2256 add_font_list(hkey, &nls_update_font_list[i]);
2259 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2261 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2262 strlen(nls_update_font_list[i].shelldlg)+1);
2263 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2264 strlen(nls_update_font_list[i].tmsrmn)+1);
2270 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2274 static BOOL init_freetype(void)
2276 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2279 "Wine cannot find the FreeType font library. To enable Wine to\n"
2280 "use TrueType fonts please install a version of FreeType greater than\n"
2281 "or equal to 2.0.5.\n"
2282 "http://www.freetype.org\n");
2286 #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;}
2288 LOAD_FUNCPTR(FT_Vector_Unit)
2289 LOAD_FUNCPTR(FT_Done_Face)
2290 LOAD_FUNCPTR(FT_Get_Char_Index)
2291 LOAD_FUNCPTR(FT_Get_Module)
2292 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2293 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2294 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2295 LOAD_FUNCPTR(FT_Init_FreeType)
2296 LOAD_FUNCPTR(FT_Load_Glyph)
2297 LOAD_FUNCPTR(FT_Matrix_Multiply)
2298 LOAD_FUNCPTR(FT_MulFix)
2299 LOAD_FUNCPTR(FT_New_Face)
2300 LOAD_FUNCPTR(FT_New_Memory_Face)
2301 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2302 LOAD_FUNCPTR(FT_Outline_Transform)
2303 LOAD_FUNCPTR(FT_Outline_Translate)
2304 LOAD_FUNCPTR(FT_Select_Charmap)
2305 LOAD_FUNCPTR(FT_Set_Charmap)
2306 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2307 LOAD_FUNCPTR(FT_Vector_Transform)
2310 /* Don't warn if these ones are missing */
2311 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2312 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2313 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2314 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2315 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2316 #ifdef HAVE_FREETYPE_FTWINFNT_H
2317 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2319 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2320 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2321 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2322 <= 2.0.3 has FT_Sqrt64 */
2326 if(pFT_Init_FreeType(&library) != 0) {
2327 ERR("Can't init FreeType library\n");
2328 wine_dlclose(ft_handle, NULL, 0);
2332 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2333 if (pFT_Library_Version)
2334 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2336 if (FT_Version.major<=0)
2342 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2343 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2344 ((FT_Version.minor << 8) & 0x00ff00) |
2345 ((FT_Version.patch ) & 0x0000ff);
2351 "Wine cannot find certain functions that it needs inside the FreeType\n"
2352 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2353 "FreeType to at least version 2.0.5.\n"
2354 "http://www.freetype.org\n");
2355 wine_dlclose(ft_handle, NULL, 0);
2360 /*************************************************************
2363 * Initialize FreeType library and create a list of available faces
2365 BOOL WineEngInit(void)
2367 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2368 static const WCHAR pathW[] = {'P','a','t','h',0};
2370 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2372 WCHAR windowsdir[MAX_PATH];
2375 const char *data_dir;
2379 /* update locale dependent font info in registry */
2382 if(!init_freetype()) return FALSE;
2384 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2385 ERR("Failed to create font mutex\n");
2388 WaitForSingleObject(font_mutex, INFINITE);
2390 delete_external_font_keys();
2392 /* load the system bitmap fonts */
2393 load_system_fonts();
2395 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2396 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2397 strcatW(windowsdir, fontsW);
2398 if((unixname = wine_get_unix_file_name(windowsdir)))
2400 ReadFontDir(unixname, FALSE);
2401 HeapFree(GetProcessHeap(), 0, unixname);
2404 /* load the system truetype fonts */
2405 data_dir = wine_get_data_dir();
2406 if (!data_dir) data_dir = wine_get_build_dir();
2407 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2408 strcpy(unixname, data_dir);
2409 strcat(unixname, "/fonts/");
2410 ReadFontDir(unixname, TRUE);
2411 HeapFree(GetProcessHeap(), 0, unixname);
2414 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2415 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2416 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2418 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2419 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2420 &hkey) == ERROR_SUCCESS) {
2422 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2423 &valuelen, &datalen, NULL, NULL);
2425 valuelen++; /* returned value doesn't include room for '\0' */
2426 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2427 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2430 dlen = datalen * sizeof(WCHAR);
2432 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2433 &dlen) == ERROR_SUCCESS) {
2434 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2436 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2438 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2439 HeapFree(GetProcessHeap(), 0, unixname);
2442 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2444 WCHAR pathW[MAX_PATH];
2445 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2448 sprintfW(pathW, fmtW, windowsdir, data);
2449 if((unixname = wine_get_unix_file_name(pathW)))
2451 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2452 HeapFree(GetProcessHeap(), 0, unixname);
2455 load_font_from_data_dir(data);
2457 /* reset dlen and vlen */
2462 HeapFree(GetProcessHeap(), 0, data);
2463 HeapFree(GetProcessHeap(), 0, valueW);
2467 load_fontconfig_fonts();
2469 /* then look in any directories that we've specified in the config file */
2470 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2471 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2477 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2479 len += sizeof(WCHAR);
2480 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2481 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2483 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2484 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2485 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2486 TRACE( "got font path %s\n", debugstr_a(valueA) );
2490 LPSTR next = strchr( ptr, ':' );
2491 if (next) *next++ = 0;
2492 ReadFontDir( ptr, TRUE );
2495 HeapFree( GetProcessHeap(), 0, valueA );
2497 HeapFree( GetProcessHeap(), 0, valueW );
2506 update_reg_entries();
2508 init_system_links();
2510 ReleaseMutex(font_mutex);
2515 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2518 TT_HoriHeader *pHori;
2522 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2523 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2525 if(height == 0) height = 16;
2527 /* Calc. height of EM square:
2529 * For +ve lfHeight we have
2530 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2531 * Re-arranging gives:
2532 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2534 * For -ve lfHeight we have
2536 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2537 * with il = winAscent + winDescent - units_per_em]
2542 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2543 ppem = ft_face->units_per_EM * height /
2544 (pHori->Ascender - pHori->Descender);
2546 ppem = ft_face->units_per_EM * height /
2547 (pOS2->usWinAscent + pOS2->usWinDescent);
2555 static struct font_mapping *map_font_file( const char *name )
2557 struct font_mapping *mapping;
2561 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2562 if (fstat( fd, &st ) == -1) goto error;
2564 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2566 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2568 mapping->refcount++;
2573 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2576 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2579 if (mapping->data == MAP_FAILED)
2581 HeapFree( GetProcessHeap(), 0, mapping );
2584 mapping->refcount = 1;
2585 mapping->dev = st.st_dev;
2586 mapping->ino = st.st_ino;
2587 mapping->size = st.st_size;
2588 list_add_tail( &mappings_list, &mapping->entry );
2596 static void unmap_font_file( struct font_mapping *mapping )
2598 if (!--mapping->refcount)
2600 list_remove( &mapping->entry );
2601 munmap( mapping->data, mapping->size );
2602 HeapFree( GetProcessHeap(), 0, mapping );
2606 static LONG load_VDMX(GdiFont*, LONG);
2608 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2615 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2619 if (!(font->mapping = map_font_file( face->file )))
2621 WARN("failed to map %s\n", debugstr_a(face->file));
2624 data_ptr = font->mapping->data;
2625 data_size = font->mapping->size;
2629 data_ptr = face->font_data_ptr;
2630 data_size = face->font_data_size;
2633 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2635 ERR("FT_New_Face rets %d\n", err);
2639 /* set it here, as load_VDMX needs it */
2640 font->ft_face = ft_face;
2642 if(FT_IS_SCALABLE(ft_face)) {
2643 /* load the VDMX table if we have one */
2644 font->ppem = load_VDMX(font, height);
2646 font->ppem = calc_ppem_for_height(ft_face, height);
2648 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2649 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2651 font->ppem = height;
2652 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2653 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2659 static int get_nearest_charset(Face *face, int *cp)
2661 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2662 a single face with the requested charset. The idea is to check if
2663 the selected font supports the current ANSI codepage, if it does
2664 return the corresponding charset, else return the first charset */
2667 int acp = GetACP(), i;
2671 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2672 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2673 return csi.ciCharset;
2675 for(i = 0; i < 32; i++) {
2677 if(face->fs.fsCsb[0] & fs0) {
2678 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2680 return csi.ciCharset;
2683 FIXME("TCI failing on %x\n", fs0);
2687 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2688 face->fs.fsCsb[0], face->file);
2690 return DEFAULT_CHARSET;
2693 static GdiFont *alloc_font(void)
2695 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2697 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2698 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2700 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2701 ret->total_kern_pairs = (DWORD)-1;
2702 ret->kern_pairs = NULL;
2703 list_init(&ret->hfontlist);
2704 list_init(&ret->child_fonts);
2708 static void free_font(GdiFont *font)
2710 struct list *cursor, *cursor2;
2713 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2715 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2716 struct list *first_hfont;
2717 HFONTLIST *hfontlist;
2718 list_remove(cursor);
2721 first_hfont = list_head(&child->font->hfontlist);
2722 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2723 DeleteObject(hfontlist->hfont);
2724 HeapFree(GetProcessHeap(), 0, hfontlist);
2725 free_font(child->font);
2727 HeapFree(GetProcessHeap(), 0, child);
2730 if (font->ft_face) pFT_Done_Face(font->ft_face);
2731 if (font->mapping) unmap_font_file( font->mapping );
2732 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2733 HeapFree(GetProcessHeap(), 0, font->potm);
2734 HeapFree(GetProcessHeap(), 0, font->name);
2735 for (i = 0; i < font->gmsize; i++)
2736 HeapFree(GetProcessHeap(),0,font->gm[i]);
2737 HeapFree(GetProcessHeap(), 0, font->gm);
2738 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2739 HeapFree(GetProcessHeap(), 0, font);
2743 /*************************************************************
2746 * load the vdmx entry for the specified height
2749 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2750 ( ( (FT_ULong)_x4 << 24 ) | \
2751 ( (FT_ULong)_x3 << 16 ) | \
2752 ( (FT_ULong)_x2 << 8 ) | \
2755 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2770 static LONG load_VDMX(GdiFont *font, LONG height)
2774 BYTE devXRatio, devYRatio;
2775 USHORT numRecs, numRatios;
2776 DWORD result, offset = -1;
2780 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2782 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2785 /* FIXME: need the real device aspect ratio */
2789 numRecs = GET_BE_WORD(hdr[1]);
2790 numRatios = GET_BE_WORD(hdr[2]);
2792 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2793 for(i = 0; i < numRatios; i++) {
2796 offset = (3 * 2) + (i * sizeof(Ratios));
2797 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2800 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2802 if((ratio.xRatio == 0 &&
2803 ratio.yStartRatio == 0 &&
2804 ratio.yEndRatio == 0) ||
2805 (devXRatio == ratio.xRatio &&
2806 devYRatio >= ratio.yStartRatio &&
2807 devYRatio <= ratio.yEndRatio))
2809 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2810 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2811 offset = GET_BE_WORD(tmp);
2817 FIXME("No suitable ratio found\n");
2821 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2823 BYTE startsz, endsz;
2826 recs = GET_BE_WORD(group.recs);
2827 startsz = group.startsz;
2828 endsz = group.endsz;
2830 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2832 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2833 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2834 if(result == GDI_ERROR) {
2835 FIXME("Failed to retrieve vTable\n");
2840 for(i = 0; i < recs; i++) {
2841 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2842 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2843 ppem = GET_BE_WORD(vTable[i * 3]);
2845 if(yMax + -yMin == height) {
2848 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2851 if(yMax + -yMin > height) {
2854 goto end; /* failed */
2856 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2857 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2858 ppem = GET_BE_WORD(vTable[i * 3]);
2859 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2865 TRACE("ppem not found for height %d\n", height);
2869 if(ppem < startsz || ppem > endsz)
2872 for(i = 0; i < recs; i++) {
2874 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2876 if(yPelHeight > ppem)
2879 if(yPelHeight == ppem) {
2880 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2881 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2882 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2888 HeapFree(GetProcessHeap(), 0, vTable);
2894 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
2896 if(font->font_desc.hash != fd->hash) return TRUE;
2897 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2898 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2899 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2900 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2903 static void calc_hash(FONT_DESC *pfd)
2905 DWORD hash = 0, *ptr, two_chars;
2909 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2911 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2913 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2915 pwc = (WCHAR *)&two_chars;
2917 *pwc = toupperW(*pwc);
2919 *pwc = toupperW(*pwc);
2923 hash ^= !pfd->can_use_bitmap;
2928 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2933 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2936 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2937 fd.can_use_bitmap = can_use_bitmap;
2940 /* try the in-use list */
2941 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2942 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2943 if(!fontcmp(ret, &fd)) {
2944 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2945 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2946 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2947 if(hflist->hfont == hfont)
2950 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2951 hflist->hfont = hfont;
2952 list_add_head(&ret->hfontlist, &hflist->entry);
2957 /* then the unused list */
2958 font_elem_ptr = list_head(&unused_gdi_font_list);
2959 while(font_elem_ptr) {
2960 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2961 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2962 if(!fontcmp(ret, &fd)) {
2963 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2964 assert(list_empty(&ret->hfontlist));
2965 TRACE("Found %p in unused list\n", ret);
2966 list_remove(&ret->entry);
2967 list_add_head(&gdi_font_list, &ret->entry);
2968 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2969 hflist->hfont = hfont;
2970 list_add_head(&ret->hfontlist, &hflist->entry);
2978 /*************************************************************
2979 * create_child_font_list
2981 static BOOL create_child_font_list(GdiFont *font)
2984 SYSTEM_LINKS *font_link;
2985 CHILD_FONT *font_link_entry, *new_child;
2987 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2989 if(!strcmpW(font_link->font_name, font->name))
2991 TRACE("found entry in system list\n");
2992 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2994 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2995 new_child->face = font_link_entry->face;
2996 new_child->font = NULL;
2997 list_add_tail(&font->child_fonts, &new_child->entry);
2998 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3005 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3006 * Sans Serif. This is how asian windows get default fallbacks for fonts
3008 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3009 font->charset != OEM_CHARSET &&
3010 strcmpW(font->name,szDefaultFallbackLink) != 0)
3011 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3013 if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3015 TRACE("found entry in default fallback list\n");
3016 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3018 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3019 new_child->face = font_link_entry->face;
3020 new_child->font = NULL;
3021 list_add_tail(&font->child_fonts, &new_child->entry);
3022 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3032 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3034 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3036 if (pFT_Set_Charmap)
3039 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3041 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3043 for (i = 0; i < ft_face->num_charmaps; i++)
3045 if (ft_face->charmaps[i]->encoding == encoding)
3047 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3048 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3050 switch (ft_face->charmaps[i]->platform_id)
3053 cmap_def = ft_face->charmaps[i];
3055 case 0: /* Apple Unicode */
3056 cmap0 = ft_face->charmaps[i];
3058 case 1: /* Macintosh */
3059 cmap1 = ft_face->charmaps[i];
3062 cmap2 = ft_face->charmaps[i];
3064 case 3: /* Microsoft */
3065 cmap3 = ft_face->charmaps[i];
3070 if (cmap3) /* prefer Microsoft cmap table */
3071 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3073 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3075 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3077 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3079 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3081 return ft_err == FT_Err_Ok;
3084 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3087 /*************************************************************
3088 * WineEngCreateFontInstance
3091 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3094 Face *face, *best, *best_bitmap;
3095 Family *family, *last_resort_family;
3096 struct list *family_elem_ptr, *face_elem_ptr;
3097 INT height, width = 0;
3098 unsigned int score = 0, new_score;
3099 signed int diff = 0, newdiff;
3100 BOOL bd, it, can_use_bitmap;
3105 EnterCriticalSection( &freetype_cs );
3107 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
3109 struct list *first_hfont = list_head(&ret->hfontlist);
3110 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3111 if(hflist->hfont == hfont)
3113 LeaveCriticalSection( &freetype_cs );
3118 if (!GetObjectW( hfont, sizeof(lf), &lf ))
3120 LeaveCriticalSection( &freetype_cs );
3123 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3125 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3126 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3127 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3130 /* check the cache first */
3131 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
3132 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3133 LeaveCriticalSection( &freetype_cs );
3137 TRACE("not in cache\n");
3138 if(list_empty(&font_list)) /* No fonts installed */
3140 TRACE("No fonts installed\n");
3141 LeaveCriticalSection( &freetype_cs );
3144 if(!have_installed_roman_font)
3146 TRACE("No roman font installed\n");
3147 LeaveCriticalSection( &freetype_cs );
3153 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
3154 ret->font_desc.lf = lf;
3155 ret->font_desc.can_use_bitmap = can_use_bitmap;
3156 calc_hash(&ret->font_desc);
3157 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3158 hflist->hfont = hfont;
3159 list_add_head(&ret->hfontlist, &hflist->entry);
3162 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3163 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3164 original value lfCharSet. Note this is a special case for
3165 Symbol and doesn't happen at least for "Wingdings*" */
3167 if(!strcmpiW(lf.lfFaceName, SymbolW))
3168 lf.lfCharSet = SYMBOL_CHARSET;
3170 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3171 switch(lf.lfCharSet) {
3172 case DEFAULT_CHARSET:
3173 csi.fs.fsCsb[0] = 0;
3176 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3177 csi.fs.fsCsb[0] = 0;
3183 if(lf.lfFaceName[0] != '\0') {
3185 SYSTEM_LINKS *font_link;
3186 CHILD_FONT *font_link_entry;
3187 LPWSTR FaceName = lf.lfFaceName;
3190 * Check for a leading '@' this signals that the font is being
3191 * requested in tategaki mode (vertical writing subtitution) but
3192 * does not affect the fontface that is to be selected.
3194 if (lf.lfFaceName[0]=='@')
3195 FaceName = &lf.lfFaceName[1];
3197 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3200 TRACE("substituting %s -> %s\n", debugstr_w(FaceName),
3201 debugstr_w(psub->to.name));
3202 strcpyW(FaceName, psub->to.name);
3205 /* We want a match on name and charset or just name if
3206 charset was DEFAULT_CHARSET. If the latter then
3207 we fixup the returned charset later in get_nearest_charset
3208 where we'll either use the charset of the current ansi codepage
3209 or if that's unavailable the first charset that the font supports.
3211 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3212 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3213 if(!strcmpiW(family->FamilyName, FaceName)) {
3214 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3215 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3216 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3217 if(face->scalable || can_use_bitmap)
3224 * Try check the SystemLink list first for a replacement font.
3225 * We may find good replacements there.
3227 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3229 if(!strcmpiW(font_link->font_name, FaceName))
3231 TRACE("found entry in system list\n");
3232 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3234 face = font_link_entry->face;
3235 family = face->family;
3236 if(csi.fs.fsCsb[0] &
3237 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3239 if(face->scalable || can_use_bitmap)
3247 /* If requested charset was DEFAULT_CHARSET then try using charset
3248 corresponding to the current ansi codepage */
3249 if(!csi.fs.fsCsb[0]) {
3251 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3252 FIXME("TCI failed on codepage %d\n", acp);
3253 csi.fs.fsCsb[0] = 0;
3255 lf.lfCharSet = csi.ciCharset;
3258 /* Face families are in the top 4 bits of lfPitchAndFamily,
3259 so mask with 0xF0 before testing */
3261 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3262 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3263 strcpyW(lf.lfFaceName, defFixed);
3264 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3265 strcpyW(lf.lfFaceName, defSerif);
3266 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3267 strcpyW(lf.lfFaceName, defSans);
3269 strcpyW(lf.lfFaceName, defSans);
3270 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3271 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3272 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3273 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3274 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3275 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3276 if(face->scalable || can_use_bitmap)
3282 last_resort_family = NULL;
3283 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3284 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3285 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3286 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3287 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3290 if(can_use_bitmap && !last_resort_family)
3291 last_resort_family = family;
3296 if(last_resort_family) {
3297 family = last_resort_family;
3298 csi.fs.fsCsb[0] = 0;
3302 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3303 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3304 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3305 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3306 if(face->scalable) {
3307 csi.fs.fsCsb[0] = 0;
3308 WARN("just using first face for now\n");
3311 if(can_use_bitmap && !last_resort_family)
3312 last_resort_family = family;
3315 if(!last_resort_family) {
3316 FIXME("can't find a single appropriate font - bailing\n");
3318 LeaveCriticalSection( &freetype_cs );
3322 WARN("could only find a bitmap font - this will probably look awful!\n");
3323 family = last_resort_family;
3324 csi.fs.fsCsb[0] = 0;
3327 it = lf.lfItalic ? 1 : 0;
3328 bd = lf.lfWeight > 550 ? 1 : 0;
3330 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
3331 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
3333 face = best = best_bitmap = NULL;
3334 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3336 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3338 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
3339 if(!best || new_score <= score)
3341 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3342 face->Italic, face->Bold, it, bd);
3345 if(best->scalable && score == 0) break;
3349 newdiff = height - (signed int)(best->size.height);
3351 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3352 if(!best_bitmap || new_score < score ||
3353 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3355 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3358 if(score == 0 && diff == 0) break;
3365 face = best->scalable ? best : best_bitmap;
3366 ret->fake_italic = (it && !face->Italic);
3367 ret->fake_bold = (bd && !face->Bold);
3371 if(csi.fs.fsCsb[0]) {
3372 ret->charset = lf.lfCharSet;
3373 ret->codepage = csi.ciACP;
3376 ret->charset = get_nearest_charset(face, &ret->codepage);
3378 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3379 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3381 ret->aveWidth = abs(lf.lfWidth);
3383 if(!face->scalable) {
3384 /* Windows uses integer scaling factors for bitmap fonts */
3385 INT scale, scaled_height;
3387 if (height != 0) height = diff;
3389 height += face->size.height;
3391 scale = (height + face->size.height - 1) / face->size.height;
3392 scaled_height = scale * face->size.height;
3393 /* XP allows not more than 10% deviation */
3394 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3395 ret->scale_y = scale;
3397 width = face->size.x_ppem >> 6;
3398 height = face->size.y_ppem >> 6;
3402 TRACE("font scale y: %f\n", ret->scale_y);
3404 ret->ft_face = OpenFontFace(ret, face, width, height);
3409 LeaveCriticalSection( &freetype_cs );
3413 ret->ntmFlags = face->ntmFlags;
3415 if (ret->charset == SYMBOL_CHARSET &&
3416 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3419 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3423 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3426 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3427 ret->name = strdupW(family->FamilyName);
3428 ret->underline = lf.lfUnderline ? 0xff : 0;
3429 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3430 create_child_font_list(ret);
3432 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3434 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3435 if (length != GDI_ERROR)
3437 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3438 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3439 TRACE("Loaded GSUB table of %i bytes\n",length);
3443 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3445 list_add_head(&gdi_font_list, &ret->entry);
3446 LeaveCriticalSection( &freetype_cs );
3450 static void dump_gdi_font_list(void)
3453 struct list *elem_ptr;
3455 TRACE("---------- gdiFont Cache ----------\n");
3456 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3457 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3458 TRACE("gdiFont=%p %s %d\n",
3459 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3462 TRACE("---------- Unused gdiFont Cache ----------\n");
3463 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3464 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3465 TRACE("gdiFont=%p %s %d\n",
3466 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3470 /*************************************************************
3471 * WineEngDestroyFontInstance
3473 * free the gdiFont associated with this handle
3476 BOOL WineEngDestroyFontInstance(HFONT handle)
3481 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3484 EnterCriticalSection( &freetype_cs );
3486 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3488 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3489 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3490 if(hflist->hfont == handle)
3492 TRACE("removing child font %p from child list\n", gdiFont);
3493 list_remove(&gdiFont->entry);
3494 LeaveCriticalSection( &freetype_cs );
3499 TRACE("destroying hfont=%p\n", handle);
3501 dump_gdi_font_list();
3503 font_elem_ptr = list_head(&gdi_font_list);
3504 while(font_elem_ptr) {
3505 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3506 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3508 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3509 while(hfontlist_elem_ptr) {
3510 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3511 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3512 if(hflist->hfont == handle) {
3513 list_remove(&hflist->entry);
3514 HeapFree(GetProcessHeap(), 0, hflist);
3518 if(list_empty(&gdiFont->hfontlist)) {
3519 TRACE("Moving to Unused list\n");
3520 list_remove(&gdiFont->entry);
3521 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3526 font_elem_ptr = list_head(&unused_gdi_font_list);
3527 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3528 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3529 while(font_elem_ptr) {
3530 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3531 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3532 TRACE("freeing %p\n", gdiFont);
3533 list_remove(&gdiFont->entry);
3536 LeaveCriticalSection( &freetype_cs );
3540 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3541 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3546 if (face->cached_enum_data)
3549 *pelf = face->cached_enum_data->elf;
3550 *pntm = face->cached_enum_data->ntm;
3551 *ptype = face->cached_enum_data->type;
3555 font = alloc_font();
3557 if(face->scalable) {
3561 height = face->size.y_ppem >> 6;
3562 width = face->size.x_ppem >> 6;
3564 font->scale_y = 1.0;
3566 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3572 font->name = strdupW(face->family->FamilyName);
3573 font->ntmFlags = face->ntmFlags;
3575 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3577 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3579 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3581 lstrcpynW(pelf->elfLogFont.lfFaceName,
3582 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3584 lstrcpynW(pelf->elfFullName,
3585 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3587 lstrcpynW(pelf->elfStyle,
3588 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3593 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3595 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3597 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3598 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3599 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3602 pntm->ntmTm.ntmFlags = face->ntmFlags;
3603 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3604 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3605 pntm->ntmFontSig = face->fs;
3607 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3609 pelf->elfLogFont.lfEscapement = 0;
3610 pelf->elfLogFont.lfOrientation = 0;
3611 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3612 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3613 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3614 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3615 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3616 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3617 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3618 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3619 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3620 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3621 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3624 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3625 *ptype |= TRUETYPE_FONTTYPE;
3626 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3627 *ptype |= DEVICE_FONTTYPE;
3628 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3629 *ptype |= RASTER_FONTTYPE;
3631 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3632 if (face->cached_enum_data)
3634 face->cached_enum_data->elf = *pelf;
3635 face->cached_enum_data->ntm = *pntm;
3636 face->cached_enum_data->type = *ptype;
3642 /*************************************************************
3646 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3650 struct list *family_elem_ptr, *face_elem_ptr;
3652 NEWTEXTMETRICEXW ntm;
3661 lf.lfCharSet = DEFAULT_CHARSET;
3662 lf.lfPitchAndFamily = 0;
3663 lf.lfFaceName[0] = 0;
3667 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3669 EnterCriticalSection( &freetype_cs );
3670 if(plf->lfFaceName[0]) {
3672 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3675 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3676 debugstr_w(psub->to.name));
3678 strcpyW(lf.lfFaceName, psub->to.name);
3682 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3683 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3684 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3685 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3686 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3687 GetEnumStructs(face, &elf, &ntm, &type);
3688 for(i = 0; i < 32; i++) {
3689 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3690 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3691 strcpyW(elf.elfScript, OEM_DOSW);
3692 i = 32; /* break out of loop */
3693 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3696 fs.fsCsb[0] = 1L << i;
3698 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3700 csi.ciCharset = DEFAULT_CHARSET;
3701 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3702 if(csi.ciCharset != DEFAULT_CHARSET) {
3703 elf.elfLogFont.lfCharSet =
3704 ntm.ntmTm.tmCharSet = csi.ciCharset;
3706 strcpyW(elf.elfScript, ElfScriptsW[i]);
3708 FIXME("Unknown elfscript for bit %d\n", i);
3711 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3712 debugstr_w(elf.elfLogFont.lfFaceName),
3713 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3714 csi.ciCharset, type, debugstr_w(elf.elfScript),
3715 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3716 ntm.ntmTm.ntmFlags);
3717 /* release section before callback (FIXME) */
3718 LeaveCriticalSection( &freetype_cs );
3719 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3720 EnterCriticalSection( &freetype_cs );
3726 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3727 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3728 face_elem_ptr = list_head(&family->faces);
3729 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3730 GetEnumStructs(face, &elf, &ntm, &type);
3731 for(i = 0; i < 32; i++) {
3732 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3733 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3734 strcpyW(elf.elfScript, OEM_DOSW);
3735 i = 32; /* break out of loop */
3736 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3739 fs.fsCsb[0] = 1L << i;
3741 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3743 csi.ciCharset = DEFAULT_CHARSET;
3744 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3745 if(csi.ciCharset != DEFAULT_CHARSET) {
3746 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3749 strcpyW(elf.elfScript, ElfScriptsW[i]);
3751 FIXME("Unknown elfscript for bit %d\n", i);
3754 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3755 debugstr_w(elf.elfLogFont.lfFaceName),
3756 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3757 csi.ciCharset, type, debugstr_w(elf.elfScript),
3758 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3759 ntm.ntmTm.ntmFlags);
3760 /* release section before callback (FIXME) */
3761 LeaveCriticalSection( &freetype_cs );
3762 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3763 EnterCriticalSection( &freetype_cs );
3767 LeaveCriticalSection( &freetype_cs );
3771 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3773 pt->x.value = vec->x >> 6;
3774 pt->x.fract = (vec->x & 0x3f) << 10;
3775 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3776 pt->y.value = vec->y >> 6;
3777 pt->y.fract = (vec->y & 0x3f) << 10;
3778 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3782 /***************************************************
3783 * According to the MSDN documentation on WideCharToMultiByte,
3784 * certain codepages cannot set the default_used parameter.
3785 * This returns TRUE if the codepage can set that parameter, false else
3786 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3788 static BOOL codepage_sets_default_used(UINT codepage)
3802 * GSUB Table handling functions
3805 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
3807 const GSUB_CoverageFormat1* cf1;
3809 cf1 = (GSUB_CoverageFormat1*)table;
3811 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
3813 int count = GET_BE_WORD(cf1->GlyphCount);
3815 TRACE("Coverage Format 1, %i glyphs\n",count);
3816 for (i = 0; i < count; i++)
3817 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
3821 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
3823 const GSUB_CoverageFormat2* cf2;
3826 cf2 = (GSUB_CoverageFormat2*)cf1;
3828 count = GET_BE_WORD(cf2->RangeCount);
3829 TRACE("Coverage Format 2, %i ranges\n",count);
3830 for (i = 0; i < count; i++)
3832 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
3834 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
3835 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
3837 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
3838 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
3844 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
3849 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
3851 const GSUB_ScriptList *script;
3852 const GSUB_Script *deflt = NULL;
3854 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
3856 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
3857 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
3859 const GSUB_Script *scr;
3862 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
3863 scr = (GSUB_Script*)((LPBYTE)script + offset);
3865 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
3867 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
3873 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
3877 const GSUB_LangSys *Lang;
3879 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
3881 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
3883 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
3884 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
3886 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
3889 offset = GET_BE_WORD(script->DefaultLangSys);
3892 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
3898 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
3901 const GSUB_FeatureList *feature;
3902 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
3904 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
3905 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
3907 int index = GET_BE_WORD(lang->FeatureIndex[i]);
3908 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
3910 const GSUB_Feature *feat;
3911 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
3918 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
3922 const GSUB_LookupList *lookup;
3923 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
3925 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
3926 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
3928 const GSUB_LookupTable *look;
3929 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
3930 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
3931 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
3932 if (GET_BE_WORD(look->LookupType) != 1)
3933 FIXME("We only handle SubType 1\n");
3938 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
3940 const GSUB_SingleSubstFormat1 *ssf1;
3941 offset = GET_BE_WORD(look->SubTable[j]);
3942 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
3943 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
3945 int offset = GET_BE_WORD(ssf1->Coverage);
3946 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
3947 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
3949 TRACE(" Glyph 0x%x ->",glyph);
3950 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
3951 TRACE(" 0x%x\n",glyph);
3956 const GSUB_SingleSubstFormat2 *ssf2;
3960 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
3961 offset = GET_BE_WORD(ssf1->Coverage);
3962 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
3963 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
3964 TRACE(" Coverage index %i\n",index);
3967 TRACE(" Glyph is 0x%x ->",glyph);
3968 glyph = GET_BE_WORD(ssf2->Substitute[index]);
3969 TRACE("0x%x\n",glyph);
3978 static const char* get_opentype_script(const GdiFont *font)
3981 * I am not sure if this is the correct way to generate our script tag
3984 switch (font->charset)
3986 case ANSI_CHARSET: return "latn";
3987 case BALTIC_CHARSET: return "latn"; /* ?? */
3988 case CHINESEBIG5_CHARSET: return "hani";
3989 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
3990 case GB2312_CHARSET: return "hani";
3991 case GREEK_CHARSET: return "grek";
3992 case HANGUL_CHARSET: return "hang";
3993 case RUSSIAN_CHARSET: return "cyrl";
3994 case SHIFTJIS_CHARSET: return "kana";
3995 case TURKISH_CHARSET: return "latn"; /* ?? */
3996 case VIETNAMESE_CHARSET: return "latn";
3997 case JOHAB_CHARSET: return "latn"; /* ?? */
3998 case ARABIC_CHARSET: return "arab";
3999 case HEBREW_CHARSET: return "hebr";
4000 case THAI_CHARSET: return "thai";
4001 default: return "latn";
4005 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4007 const GSUB_Header *header;
4008 const GSUB_Script *script;
4009 const GSUB_LangSys *language;
4010 const GSUB_Feature *feature;
4012 if (!font->GSUB_Table)
4015 header = font->GSUB_Table;
4017 script = GSUB_get_script_table(header, get_opentype_script(font));
4020 TRACE("Script not found\n");
4023 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4026 TRACE("Language not found\n");
4029 feature = GSUB_get_feature(header, language, "vrt2");
4031 feature = GSUB_get_feature(header, language, "vert");
4034 TRACE("vrt2/vert feature not found\n");
4037 return GSUB_apply_feature(header, feature, glyph);
4040 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4044 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4045 WCHAR wc = (WCHAR)glyph;
4047 BOOL *default_used_pointer;
4050 default_used_pointer = NULL;
4051 default_used = FALSE;
4052 if (codepage_sets_default_used(font->codepage))
4053 default_used_pointer = &default_used;
4054 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4057 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4058 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4059 return get_GSUB_vert_glyph(font,ret);
4062 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
4063 glyph = glyph + 0xf000;
4064 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4065 return get_GSUB_vert_glyph(font,glyphId);
4068 /*************************************************************
4069 * WineEngGetGlyphIndices
4071 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
4073 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4074 LPWORD pgi, DWORD flags)
4077 WCHAR default_char = 0;
4080 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
4082 for(i = 0; i < count; i++)
4084 pgi[i] = get_glyph_index(font, lpstr[i]);
4089 WineEngGetTextMetrics(font, &textm);
4090 default_char = textm.tmDefaultChar;
4092 pgi[i] = default_char;
4098 /*************************************************************
4099 * WineEngGetGlyphOutline
4101 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4102 * except that the first parameter is the HWINEENGFONT of the font in
4103 * question rather than an HDC.
4106 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4107 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4110 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4111 FT_Face ft_face = incoming_font->ft_face;
4112 GdiFont *font = incoming_font;
4113 FT_UInt glyph_index;
4114 DWORD width, height, pitch, needed = 0;
4115 FT_Bitmap ft_bitmap;
4117 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4119 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4120 float widthRatio = 1.0;
4121 FT_Matrix transMat = identityMat;
4122 BOOL needsTransform = FALSE;
4123 BOOL tategaki = (font->GSUB_Table != NULL);
4124 UINT original_index;
4127 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4128 buflen, buf, lpmat);
4130 EnterCriticalSection( &freetype_cs );
4132 if(format & GGO_GLYPH_INDEX) {
4133 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4134 original_index = glyph;
4135 format &= ~GGO_GLYPH_INDEX;
4137 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4138 ft_face = font->ft_face;
4139 original_index = glyph_index;
4142 /* tategaki never appears to happen to lower glyph index */
4143 if (glyph_index < TATEGAKI_LOWER_BOUND )
4146 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4147 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4148 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4149 font->gmsize * sizeof(GM*));
4151 if(format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL && FONT_GM(font,original_index)->init ) {
4152 *lpgm = FONT_GM(font,original_index)->gm;
4153 LeaveCriticalSection( &freetype_cs );
4154 return 1; /* FIXME */
4158 if (!font->gm[original_index / GM_BLOCK_SIZE])
4159 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4161 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || lpmat)
4162 load_flags |= FT_LOAD_NO_BITMAP;
4164 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4167 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4168 LeaveCriticalSection( &freetype_cs );
4172 /* Scaling factor */
4173 if (font->aveWidth && font->potm)
4175 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11;
4176 widthRatio /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
4179 widthRatio = font->scale_y;
4181 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
4182 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
4184 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
4186 bbx = (right - left) >> 6;
4188 /* Scaling transform */
4189 if(font->aveWidth) {
4191 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4194 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4196 pFT_Matrix_Multiply(&scaleMat, &transMat);
4197 needsTransform = TRUE;
4200 /* Slant transform */
4201 if (font->fake_italic) {
4204 slantMat.xx = (1 << 16);
4205 slantMat.xy = ((1 << 16) >> 2);
4207 slantMat.yy = (1 << 16);
4208 pFT_Matrix_Multiply(&slantMat, &transMat);
4209 needsTransform = TRUE;
4212 /* Rotation transform */
4213 if(font->orientation && !tategaki) {
4214 FT_Matrix rotationMat;
4216 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
4217 pFT_Vector_Unit(&vecAngle, angle);
4218 rotationMat.xx = vecAngle.x;
4219 rotationMat.xy = -vecAngle.y;
4220 rotationMat.yx = -rotationMat.xy;
4221 rotationMat.yy = rotationMat.xx;
4223 pFT_Matrix_Multiply(&rotationMat, &transMat);
4224 needsTransform = TRUE;
4227 /* Extra transformation specified by caller */
4230 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4231 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
4232 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
4233 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4234 pFT_Matrix_Multiply(&extraMat, &transMat);
4235 needsTransform = TRUE;
4238 if(!needsTransform) {
4239 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4240 bottom = (ft_face->glyph->metrics.horiBearingY -
4241 ft_face->glyph->metrics.height) & -64;
4242 lpgm->gmCellIncX = adv;
4243 lpgm->gmCellIncY = 0;
4247 for(xc = 0; xc < 2; xc++) {
4248 for(yc = 0; yc < 2; yc++) {
4249 vec.x = (ft_face->glyph->metrics.horiBearingX +
4250 xc * ft_face->glyph->metrics.width);
4251 vec.y = ft_face->glyph->metrics.horiBearingY -
4252 yc * ft_face->glyph->metrics.height;
4253 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4254 pFT_Vector_Transform(&vec, &transMat);
4255 if(xc == 0 && yc == 0) {
4256 left = right = vec.x;
4257 top = bottom = vec.y;
4259 if(vec.x < left) left = vec.x;
4260 else if(vec.x > right) right = vec.x;
4261 if(vec.y < bottom) bottom = vec.y;
4262 else if(vec.y > top) top = vec.y;
4267 right = (right + 63) & -64;
4268 bottom = bottom & -64;
4269 top = (top + 63) & -64;
4271 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4272 vec.x = ft_face->glyph->metrics.horiAdvance;
4274 pFT_Vector_Transform(&vec, &transMat);
4275 lpgm->gmCellIncX = (vec.x+63) >> 6;
4276 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4278 lpgm->gmBlackBoxX = (right - left) >> 6;
4279 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4280 lpgm->gmptGlyphOrigin.x = left >> 6;
4281 lpgm->gmptGlyphOrigin.y = top >> 6;
4283 if(format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP)
4285 FONT_GM(font,original_index)->gm = *lpgm;
4286 FONT_GM(font,original_index)->adv = adv;
4287 FONT_GM(font,original_index)->lsb = lsb;
4288 FONT_GM(font,original_index)->bbx = bbx;
4289 FONT_GM(font,original_index)->init = TRUE;
4292 if(format == GGO_METRICS)
4294 LeaveCriticalSection( &freetype_cs );
4295 return 1; /* FIXME */
4298 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
4299 TRACE("loaded a bitmap\n");
4300 LeaveCriticalSection( &freetype_cs );
4306 width = lpgm->gmBlackBoxX;
4307 height = lpgm->gmBlackBoxY;
4308 pitch = ((width + 31) >> 5) << 2;
4309 needed = pitch * height;
4311 if(!buf || !buflen) break;
4313 switch(ft_face->glyph->format) {
4314 case ft_glyph_format_bitmap:
4316 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4317 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4318 INT h = ft_face->glyph->bitmap.rows;
4320 memcpy(dst, src, w);
4321 src += ft_face->glyph->bitmap.pitch;
4327 case ft_glyph_format_outline:
4328 ft_bitmap.width = width;
4329 ft_bitmap.rows = height;
4330 ft_bitmap.pitch = pitch;
4331 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4332 ft_bitmap.buffer = buf;
4334 if(needsTransform) {
4335 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4338 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4340 /* Note: FreeType will only set 'black' bits for us. */
4341 memset(buf, 0, needed);
4342 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4346 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4347 LeaveCriticalSection( &freetype_cs );
4352 case GGO_GRAY2_BITMAP:
4353 case GGO_GRAY4_BITMAP:
4354 case GGO_GRAY8_BITMAP:
4355 case WINE_GGO_GRAY16_BITMAP:
4357 unsigned int mult, row, col;
4360 width = lpgm->gmBlackBoxX;
4361 height = lpgm->gmBlackBoxY;
4362 pitch = (width + 3) / 4 * 4;
4363 needed = pitch * height;
4365 if(!buf || !buflen) break;
4367 switch(ft_face->glyph->format) {
4368 case ft_glyph_format_bitmap:
4370 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4371 INT h = ft_face->glyph->bitmap.rows;
4374 for(x = 0; x < pitch; x++)
4375 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4376 src += ft_face->glyph->bitmap.pitch;
4379 LeaveCriticalSection( &freetype_cs );
4382 case ft_glyph_format_outline:
4384 ft_bitmap.width = width;
4385 ft_bitmap.rows = height;
4386 ft_bitmap.pitch = pitch;
4387 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4388 ft_bitmap.buffer = buf;
4391 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4393 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4395 memset(ft_bitmap.buffer, 0, buflen);
4397 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4399 if(format == GGO_GRAY2_BITMAP)
4401 else if(format == GGO_GRAY4_BITMAP)
4403 else if(format == GGO_GRAY8_BITMAP)
4405 else /* format == WINE_GGO_GRAY16_BITMAP */
4407 LeaveCriticalSection( &freetype_cs );
4413 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4414 LeaveCriticalSection( &freetype_cs );
4419 for(row = 0; row < height; row++) {
4421 for(col = 0; col < width; col++, ptr++) {
4422 *ptr = (((int)*ptr) * mult + 128) / 256;
4431 int contour, point = 0, first_pt;
4432 FT_Outline *outline = &ft_face->glyph->outline;
4433 TTPOLYGONHEADER *pph;
4435 DWORD pph_start, cpfx, type;
4437 if(buflen == 0) buf = NULL;
4439 if (needsTransform && buf) {
4440 pFT_Outline_Transform(outline, &transMat);
4443 for(contour = 0; contour < outline->n_contours; contour++) {
4445 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4448 pph->dwType = TT_POLYGON_TYPE;
4449 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4451 needed += sizeof(*pph);
4453 while(point <= outline->contours[contour]) {
4454 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4455 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4456 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4460 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4463 } while(point <= outline->contours[contour] &&
4464 (outline->tags[point] & FT_Curve_Tag_On) ==
4465 (outline->tags[point-1] & FT_Curve_Tag_On));
4466 /* At the end of a contour Windows adds the start point, but
4468 if(point > outline->contours[contour] &&
4469 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4471 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4473 } else if(point <= outline->contours[contour] &&
4474 outline->tags[point] & FT_Curve_Tag_On) {
4475 /* add closing pt for bezier */
4477 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4485 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4488 pph->cb = needed - pph_start;
4494 /* Convert the quadratic Beziers to cubic Beziers.
4495 The parametric eqn for a cubic Bezier is, from PLRM:
4496 r(t) = at^3 + bt^2 + ct + r0
4497 with the control points:
4502 A quadratic Beizer has the form:
4503 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4505 So equating powers of t leads to:
4506 r1 = 2/3 p1 + 1/3 p0
4507 r2 = 2/3 p1 + 1/3 p2
4508 and of course r0 = p0, r3 = p2
4511 int contour, point = 0, first_pt;
4512 FT_Outline *outline = &ft_face->glyph->outline;
4513 TTPOLYGONHEADER *pph;
4515 DWORD pph_start, cpfx, type;
4516 FT_Vector cubic_control[4];
4517 if(buflen == 0) buf = NULL;
4519 if (needsTransform && buf) {
4520 pFT_Outline_Transform(outline, &transMat);
4523 for(contour = 0; contour < outline->n_contours; contour++) {
4525 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4528 pph->dwType = TT_POLYGON_TYPE;
4529 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4531 needed += sizeof(*pph);
4533 while(point <= outline->contours[contour]) {
4534 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4535 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4536 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4539 if(type == TT_PRIM_LINE) {
4541 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4545 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4548 /* FIXME: Possible optimization in endpoint calculation
4549 if there are two consecutive curves */
4550 cubic_control[0] = outline->points[point-1];
4551 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4552 cubic_control[0].x += outline->points[point].x + 1;
4553 cubic_control[0].y += outline->points[point].y + 1;
4554 cubic_control[0].x >>= 1;
4555 cubic_control[0].y >>= 1;
4557 if(point+1 > outline->contours[contour])
4558 cubic_control[3] = outline->points[first_pt];
4560 cubic_control[3] = outline->points[point+1];
4561 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4562 cubic_control[3].x += outline->points[point].x + 1;
4563 cubic_control[3].y += outline->points[point].y + 1;
4564 cubic_control[3].x >>= 1;
4565 cubic_control[3].y >>= 1;
4568 /* r1 = 1/3 p0 + 2/3 p1
4569 r2 = 1/3 p2 + 2/3 p1 */
4570 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4571 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4572 cubic_control[2] = cubic_control[1];
4573 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4574 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4575 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4576 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4578 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4579 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4580 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4585 } while(point <= outline->contours[contour] &&
4586 (outline->tags[point] & FT_Curve_Tag_On) ==
4587 (outline->tags[point-1] & FT_Curve_Tag_On));
4588 /* At the end of a contour Windows adds the start point,
4589 but only for Beziers and we've already done that.
4591 if(point <= outline->contours[contour] &&
4592 outline->tags[point] & FT_Curve_Tag_On) {
4593 /* This is the closing pt of a bezier, but we've already
4594 added it, so just inc point and carry on */
4601 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4604 pph->cb = needed - pph_start;
4610 FIXME("Unsupported format %d\n", format);
4611 LeaveCriticalSection( &freetype_cs );
4614 LeaveCriticalSection( &freetype_cs );
4618 static BOOL get_bitmap_text_metrics(GdiFont *font)
4620 FT_Face ft_face = font->ft_face;
4621 #ifdef HAVE_FREETYPE_FTWINFNT_H
4622 FT_WinFNT_HeaderRec winfnt_header;
4624 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4625 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4626 font->potm->otmSize = size;
4628 #define TM font->potm->otmTextMetrics
4629 #ifdef HAVE_FREETYPE_FTWINFNT_H
4630 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4632 TM.tmHeight = winfnt_header.pixel_height;
4633 TM.tmAscent = winfnt_header.ascent;
4634 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4635 TM.tmInternalLeading = winfnt_header.internal_leading;
4636 TM.tmExternalLeading = winfnt_header.external_leading;
4637 TM.tmAveCharWidth = winfnt_header.avg_width;
4638 TM.tmMaxCharWidth = winfnt_header.max_width;
4639 TM.tmWeight = winfnt_header.weight;
4641 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4642 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4643 TM.tmFirstChar = winfnt_header.first_char;
4644 TM.tmLastChar = winfnt_header.last_char;
4645 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4646 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4647 TM.tmItalic = winfnt_header.italic;
4648 TM.tmUnderlined = font->underline;
4649 TM.tmStruckOut = font->strikeout;
4650 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4651 TM.tmCharSet = winfnt_header.charset;
4656 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4657 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4658 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4659 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4660 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4661 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4662 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4663 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4665 TM.tmDigitizedAspectX = 96; /* FIXME */
4666 TM.tmDigitizedAspectY = 96; /* FIXME */
4668 TM.tmLastChar = 255;
4669 TM.tmDefaultChar = 32;
4670 TM.tmBreakChar = 32;
4671 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4672 TM.tmUnderlined = font->underline;
4673 TM.tmStruckOut = font->strikeout;
4674 /* NB inverted meaning of TMPF_FIXED_PITCH */
4675 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4676 TM.tmCharSet = font->charset;
4684 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
4690 scale_x = (float)font->aveWidth * font->font_desc.matrix.eM11;
4691 scale_x /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
4694 scale_x = font->scale_y;
4696 ptm->tmHeight = (float)ptm->tmHeight * font->scale_y;
4697 ptm->tmAscent = (float)ptm->tmAscent * font->scale_y;
4698 ptm->tmDescent = (float)ptm->tmDescent * font->scale_y;
4699 ptm->tmInternalLeading = (float)ptm->tmInternalLeading * font->scale_y;
4700 ptm->tmExternalLeading = (float)ptm->tmExternalLeading * font->scale_y;
4702 ptm->tmAveCharWidth = (float)ptm->tmAveCharWidth * scale_x;
4703 ptm->tmMaxCharWidth = (float)ptm->tmMaxCharWidth * scale_x;
4706 /*************************************************************
4707 * WineEngGetTextMetrics
4710 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4712 EnterCriticalSection( &freetype_cs );
4714 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
4715 if(!get_bitmap_text_metrics(font))
4717 LeaveCriticalSection( &freetype_cs );
4723 LeaveCriticalSection( &freetype_cs );
4726 *ptm = font->potm->otmTextMetrics;
4727 scale_font_metrics(font, ptm);
4728 LeaveCriticalSection( &freetype_cs );
4733 /*************************************************************
4734 * WineEngGetOutlineTextMetrics
4737 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4738 OUTLINETEXTMETRICW *potm)
4740 FT_Face ft_face = font->ft_face;
4741 UINT needed, lenfam, lensty, ret;
4743 TT_HoriHeader *pHori;
4744 TT_Postscript *pPost;
4745 FT_Fixed x_scale, y_scale;
4746 WCHAR *family_nameW, *style_nameW;
4747 static const WCHAR spaceW[] = {' ', '\0'};
4749 INT ascent, descent;
4751 TRACE("font=%p\n", font);
4753 if(!FT_IS_SCALABLE(ft_face))
4756 EnterCriticalSection( &freetype_cs );
4759 if(cbSize >= font->potm->otmSize)
4761 memcpy(potm, font->potm, font->potm->otmSize);
4762 scale_font_metrics(font, &potm->otmTextMetrics);
4764 LeaveCriticalSection( &freetype_cs );
4765 return font->potm->otmSize;
4769 needed = sizeof(*potm);
4771 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
4772 family_nameW = strdupW(font->name);
4774 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
4776 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
4777 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
4778 style_nameW, lensty/sizeof(WCHAR));
4780 /* These names should be read from the TT name table */
4782 /* length of otmpFamilyName */
4785 /* length of otmpFaceName */
4786 if(!strcasecmp(ft_face->style_name, "regular")) {
4787 needed += lenfam; /* just the family name */
4789 needed += lenfam + lensty; /* family + " " + style */
4792 /* length of otmpStyleName */
4795 /* length of otmpFullName */
4796 needed += lenfam + lensty;
4799 x_scale = ft_face->size->metrics.x_scale;
4800 y_scale = ft_face->size->metrics.y_scale;
4802 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4804 FIXME("Can't find OS/2 table - not TT font?\n");
4809 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4811 FIXME("Can't find HHEA table - not TT font?\n");
4816 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
4818 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",
4819 pOS2->usWinAscent, pOS2->usWinDescent,
4820 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
4821 ft_face->ascender, ft_face->descender, ft_face->height,
4822 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
4823 ft_face->bbox.yMax, ft_face->bbox.yMin);
4825 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
4826 font->potm->otmSize = needed;
4828 #define TM font->potm->otmTextMetrics
4830 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
4831 ascent = pHori->Ascender;
4832 descent = -pHori->Descender;
4834 ascent = pOS2->usWinAscent;
4835 descent = pOS2->usWinDescent;
4839 TM.tmAscent = font->yMax;
4840 TM.tmDescent = -font->yMin;
4841 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
4843 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
4844 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
4845 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
4846 - ft_face->units_per_EM, y_scale) + 32) >> 6;
4849 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4852 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4854 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
4855 ((ascent + descent) -
4856 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
4858 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
4859 if (TM.tmAveCharWidth == 0) {
4860 TM.tmAveCharWidth = 1;
4862 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
4863 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
4865 TM.tmDigitizedAspectX = 300;
4866 TM.tmDigitizedAspectY = 300;
4867 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4868 * symbol range to 0 - f0ff
4870 if (font->charset == SYMBOL_CHARSET)
4873 TM.tmFirstChar = pOS2->usFirstCharIndex;
4874 TM.tmLastChar = pOS2->usLastCharIndex;
4875 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4876 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
4877 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4878 TM.tmUnderlined = font->underline;
4879 TM.tmStruckOut = font->strikeout;
4881 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4882 if(!FT_IS_FIXED_WIDTH(ft_face) &&
4883 (pOS2->version == 0xFFFFU ||
4884 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4885 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
4887 TM.tmPitchAndFamily = 0;
4889 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
4890 case PAN_FAMILY_SCRIPT:
4891 TM.tmPitchAndFamily |= FF_SCRIPT;
4893 case PAN_FAMILY_DECORATIVE:
4894 case PAN_FAMILY_PICTORIAL:
4895 TM.tmPitchAndFamily |= FF_DECORATIVE;
4897 case PAN_FAMILY_TEXT_DISPLAY:
4898 if(TM.tmPitchAndFamily == 0) /* fixed */
4899 TM.tmPitchAndFamily = FF_MODERN;
4901 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
4902 case PAN_SERIF_NORMAL_SANS:
4903 case PAN_SERIF_OBTUSE_SANS:
4904 case PAN_SERIF_PERP_SANS:
4905 TM.tmPitchAndFamily |= FF_SWISS;
4908 TM.tmPitchAndFamily |= FF_ROMAN;
4913 TM.tmPitchAndFamily |= FF_DONTCARE;
4916 if(FT_IS_SCALABLE(ft_face))
4917 TM.tmPitchAndFamily |= TMPF_VECTOR;
4919 if(FT_IS_SFNT(ft_face))
4921 if (font->ntmFlags & NTM_PS_OPENTYPE)
4922 TM.tmPitchAndFamily |= TMPF_DEVICE;
4924 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
4927 TM.tmCharSet = font->charset;
4930 font->potm->otmFiller = 0;
4931 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
4932 font->potm->otmfsSelection = pOS2->fsSelection;
4933 font->potm->otmfsType = pOS2->fsType;
4934 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
4935 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
4936 font->potm->otmItalicAngle = 0; /* POST table */
4937 font->potm->otmEMSquare = ft_face->units_per_EM;
4938 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
4939 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4940 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4941 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
4942 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4943 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
4944 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
4945 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
4946 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4947 font->potm->otmMacAscent = 0; /* where do these come from ? */
4948 font->potm->otmMacDescent = 0;
4949 font->potm->otmMacLineGap = 0;
4950 font->potm->otmusMinimumPPEM = 0; /* TT Header */
4951 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
4952 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
4953 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
4954 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
4955 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
4956 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
4957 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
4958 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
4959 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
4960 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4962 font->potm->otmsUnderscoreSize = 0;
4963 font->potm->otmsUnderscorePosition = 0;
4965 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
4966 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
4969 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4970 cp = (char*)font->potm + sizeof(*font->potm);
4971 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4972 strcpyW((WCHAR*)cp, family_nameW);
4974 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4975 strcpyW((WCHAR*)cp, style_nameW);
4977 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4978 strcpyW((WCHAR*)cp, family_nameW);
4979 if(strcasecmp(ft_face->style_name, "regular")) {
4980 strcatW((WCHAR*)cp, spaceW);
4981 strcatW((WCHAR*)cp, style_nameW);
4982 cp += lenfam + lensty;
4985 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
4986 strcpyW((WCHAR*)cp, family_nameW);
4987 strcatW((WCHAR*)cp, spaceW);
4988 strcatW((WCHAR*)cp, style_nameW);
4991 if(potm && needed <= cbSize)
4993 memcpy(potm, font->potm, font->potm->otmSize);
4994 scale_font_metrics(font, &potm->otmTextMetrics);
4998 HeapFree(GetProcessHeap(), 0, style_nameW);
4999 HeapFree(GetProcessHeap(), 0, family_nameW);
5001 LeaveCriticalSection( &freetype_cs );
5005 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5007 HFONTLIST *hfontlist;
5008 child->font = alloc_font();
5009 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5010 if(!child->font->ft_face)
5012 free_font(child->font);
5017 child->font->ntmFlags = child->face->ntmFlags;
5018 child->font->orientation = font->orientation;
5019 child->font->scale_y = font->scale_y;
5020 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5021 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5022 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5023 child->font->base_font = font;
5024 list_add_head(&child_font_list, &child->font->entry);
5025 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5029 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5032 CHILD_FONT *child_font;
5035 font = font->base_font;
5037 *linked_font = font;
5039 if((*glyph = get_glyph_index(font, c)))
5042 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5044 if(!child_font->font)
5045 if(!load_child_font(font, child_font))
5048 if(!child_font->font->ft_face)
5050 g = get_glyph_index(child_font->font, c);
5054 *linked_font = child_font->font;
5061 /*************************************************************
5062 * WineEngGetCharWidth
5065 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5070 FT_UInt glyph_index;
5071 GdiFont *linked_font;
5073 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5075 EnterCriticalSection( &freetype_cs );
5076 for(c = firstChar; c <= lastChar; c++) {
5077 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5078 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5079 &gm, 0, NULL, NULL);
5080 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5082 LeaveCriticalSection( &freetype_cs );
5086 /*************************************************************
5087 * WineEngGetCharABCWidths
5090 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5095 FT_UInt glyph_index;
5096 GdiFont *linked_font;
5098 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5100 if(!FT_IS_SCALABLE(font->ft_face))
5103 EnterCriticalSection( &freetype_cs );
5105 for(c = firstChar; c <= lastChar; c++) {
5106 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5107 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5108 &gm, 0, NULL, NULL);
5109 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5110 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5111 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5112 FONT_GM(linked_font,glyph_index)->bbx;
5114 LeaveCriticalSection( &freetype_cs );
5118 /*************************************************************
5119 * WineEngGetCharABCWidthsI
5122 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5127 FT_UInt glyph_index;
5128 GdiFont *linked_font;
5130 if(!FT_HAS_HORIZONTAL(font->ft_face))
5133 EnterCriticalSection( &freetype_cs );
5135 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5137 for(c = firstChar; c < firstChar+count; c++) {
5138 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5139 &gm, 0, NULL, NULL);
5140 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5141 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5142 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5143 - FONT_GM(linked_font,c)->bbx;
5146 for(c = 0; c < count; c++) {
5147 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5148 &gm, 0, NULL, NULL);
5149 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5150 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5151 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5152 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5155 LeaveCriticalSection( &freetype_cs );
5159 /*************************************************************
5160 * WineEngGetTextExtentExPoint
5163 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5164 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5170 FT_UInt glyph_index;
5171 GdiFont *linked_font;
5173 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5176 EnterCriticalSection( &freetype_cs );
5179 WineEngGetTextMetrics(font, &tm);
5180 size->cy = tm.tmHeight;
5182 for(idx = 0; idx < count; idx++) {
5183 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5184 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5185 &gm, 0, NULL, NULL);
5186 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5188 if (! pnfit || ext <= max_ext) {
5198 LeaveCriticalSection( &freetype_cs );
5199 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5203 /*************************************************************
5204 * WineEngGetTextExtentExPointI
5207 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5208 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5215 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5217 EnterCriticalSection( &freetype_cs );
5220 WineEngGetTextMetrics(font, &tm);
5221 size->cy = tm.tmHeight;
5223 for(idx = 0; idx < count; idx++) {
5224 WineEngGetGlyphOutline(font, indices[idx],
5225 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
5227 size->cx += FONT_GM(font,indices[idx])->adv;
5229 if (! pnfit || ext <= max_ext) {
5239 LeaveCriticalSection( &freetype_cs );
5240 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5244 /*************************************************************
5245 * WineEngGetFontData
5248 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5251 FT_Face ft_face = font->ft_face;
5255 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5256 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
5257 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
5259 if(!FT_IS_SFNT(ft_face))
5267 if(table) { /* MS tags differ in endidness from FT ones */
5268 table = table >> 24 | table << 24 |
5269 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
5272 /* make sure value of len is the value freetype says it needs */
5275 FT_ULong needed = 0;
5276 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
5277 if( !err && needed < len) len = needed;
5279 err = load_sfnt_table(ft_face, table, offset, buf, &len);
5282 TRACE("Can't find table %c%c%c%c\n",
5283 /* bytes were reversed */
5284 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
5285 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
5291 /*************************************************************
5292 * WineEngGetTextFace
5295 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5298 lstrcpynW(str, font->name, count);
5299 return strlenW(font->name);
5301 return strlenW(font->name) + 1;
5304 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5306 if (fs) *fs = font->fs;
5307 return font->charset;
5310 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5312 GdiFont *font = dc->gdiFont, *linked_font;
5313 struct list *first_hfont;
5316 EnterCriticalSection( &freetype_cs );
5317 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
5318 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
5319 if(font == linked_font)
5320 *new_hfont = dc->hFont;
5323 first_hfont = list_head(&linked_font->hfontlist);
5324 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
5326 LeaveCriticalSection( &freetype_cs );
5330 /* Retrieve a list of supported Unicode ranges for a given font.
5331 * Can be called with NULL gs to calculate the buffer size. Returns
5332 * the number of ranges found.
5334 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
5336 DWORD num_ranges = 0;
5338 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5341 FT_ULong char_code, char_code_prev;
5344 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
5346 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5347 face->num_glyphs, glyph_code, char_code);
5349 if (!glyph_code) return 0;
5353 gs->ranges[0].wcLow = (USHORT)char_code;
5354 gs->ranges[0].cGlyphs = 0;
5355 gs->cGlyphsSupported = 0;
5361 if (char_code < char_code_prev)
5363 ERR("expected increasing char code from FT_Get_Next_Char\n");
5366 if (char_code - char_code_prev > 1)
5371 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5372 gs->ranges[num_ranges - 1].cGlyphs = 1;
5373 gs->cGlyphsSupported++;
5378 gs->ranges[num_ranges - 1].cGlyphs++;
5379 gs->cGlyphsSupported++;
5381 char_code_prev = char_code;
5382 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5386 FIXME("encoding %u not supported\n", face->charmap->encoding);
5391 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5394 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
5396 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5399 glyphset->cbThis = size;
5400 glyphset->cRanges = num_ranges;
5405 /*************************************************************
5408 BOOL WineEngFontIsLinked(GdiFont *font)
5411 EnterCriticalSection( &freetype_cs );
5412 ret = !list_empty(&font->child_fonts);
5413 LeaveCriticalSection( &freetype_cs );
5417 static BOOL is_hinting_enabled(void)
5419 /* Use the >= 2.2.0 function if available */
5420 if(pFT_Get_TrueType_Engine_Type)
5422 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
5423 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
5425 #ifdef FT_DRIVER_HAS_HINTER
5430 /* otherwise if we've been compiled with < 2.2.0 headers
5431 use the internal macro */
5432 mod = pFT_Get_Module(library, "truetype");
5433 if(mod && FT_DRIVER_HAS_HINTER(mod))
5441 /*************************************************************************
5442 * GetRasterizerCaps (GDI32.@)
5444 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5446 static int hinting = -1;
5450 hinting = is_hinting_enabled();
5451 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
5454 lprs->nSize = sizeof(RASTERIZER_STATUS);
5455 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
5456 lprs->nLanguageID = 0;
5460 /*************************************************************************
5461 * Kerning support for TrueType fonts
5463 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5465 struct TT_kern_table
5471 struct TT_kern_subtable
5480 USHORT horizontal : 1;
5482 USHORT cross_stream: 1;
5483 USHORT override : 1;
5484 USHORT reserved1 : 4;
5490 struct TT_format0_kern_subtable
5494 USHORT entrySelector;
5505 static DWORD parse_format0_kern_subtable(GdiFont *font,
5506 const struct TT_format0_kern_subtable *tt_f0_ks,
5507 const USHORT *glyph_to_char,
5508 KERNINGPAIR *kern_pair, DWORD cPairs)
5511 const struct TT_kern_pair *tt_kern_pair;
5513 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
5515 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
5517 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5518 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
5519 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
5521 if (!kern_pair || !cPairs)
5524 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
5526 nPairs = min(nPairs, cPairs);
5528 for (i = 0; i < nPairs; i++)
5530 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
5531 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
5532 /* this algorithm appears to better match what Windows does */
5533 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
5534 if (kern_pair->iKernAmount < 0)
5536 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
5537 kern_pair->iKernAmount -= font->ppem;
5539 else if (kern_pair->iKernAmount > 0)
5541 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
5542 kern_pair->iKernAmount += font->ppem;
5544 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
5546 TRACE("left %u right %u value %d\n",
5547 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
5551 TRACE("copied %u entries\n", nPairs);
5555 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5559 const struct TT_kern_table *tt_kern_table;
5560 const struct TT_kern_subtable *tt_kern_subtable;
5562 USHORT *glyph_to_char;
5564 EnterCriticalSection( &freetype_cs );
5565 if (font->total_kern_pairs != (DWORD)-1)
5567 if (cPairs && kern_pair)
5569 cPairs = min(cPairs, font->total_kern_pairs);
5570 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5571 LeaveCriticalSection( &freetype_cs );
5574 LeaveCriticalSection( &freetype_cs );
5575 return font->total_kern_pairs;
5578 font->total_kern_pairs = 0;
5580 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5582 if (length == GDI_ERROR)
5584 TRACE("no kerning data in the font\n");
5585 LeaveCriticalSection( &freetype_cs );
5589 buf = HeapAlloc(GetProcessHeap(), 0, length);
5592 WARN("Out of memory\n");
5593 LeaveCriticalSection( &freetype_cs );
5597 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5599 /* build a glyph index to char code map */
5600 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5603 WARN("Out of memory allocating a glyph index to char code map\n");
5604 HeapFree(GetProcessHeap(), 0, buf);
5605 LeaveCriticalSection( &freetype_cs );
5609 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5615 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5617 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5618 font->ft_face->num_glyphs, glyph_code, char_code);
5622 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5624 /* FIXME: This doesn't match what Windows does: it does some fancy
5625 * things with duplicate glyph index to char code mappings, while
5626 * we just avoid overriding existing entries.
5628 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5629 glyph_to_char[glyph_code] = (USHORT)char_code;
5631 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5638 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5639 for (n = 0; n <= 65535; n++)
5640 glyph_to_char[n] = (USHORT)n;
5643 tt_kern_table = buf;
5644 nTables = GET_BE_WORD(tt_kern_table->nTables);
5645 TRACE("version %u, nTables %u\n",
5646 GET_BE_WORD(tt_kern_table->version), nTables);
5648 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5650 for (i = 0; i < nTables; i++)
5652 struct TT_kern_subtable tt_kern_subtable_copy;
5654 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5655 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5656 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5658 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5659 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
5660 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
5662 /* According to the TrueType specification this is the only format
5663 * that will be properly interpreted by Windows and OS/2
5665 if (tt_kern_subtable_copy.coverage.bits.format == 0)
5667 DWORD new_chunk, old_total = font->total_kern_pairs;
5669 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5670 glyph_to_char, NULL, 0);
5671 font->total_kern_pairs += new_chunk;
5673 if (!font->kern_pairs)
5674 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
5675 font->total_kern_pairs * sizeof(*font->kern_pairs));
5677 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
5678 font->total_kern_pairs * sizeof(*font->kern_pairs));
5680 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5681 glyph_to_char, font->kern_pairs + old_total, new_chunk);
5684 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
5686 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
5689 HeapFree(GetProcessHeap(), 0, glyph_to_char);
5690 HeapFree(GetProcessHeap(), 0, buf);
5692 if (cPairs && kern_pair)
5694 cPairs = min(cPairs, font->total_kern_pairs);
5695 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5696 LeaveCriticalSection( &freetype_cs );
5699 LeaveCriticalSection( &freetype_cs );
5700 return font->total_kern_pairs;
5703 #else /* HAVE_FREETYPE */
5705 /*************************************************************************/
5707 BOOL WineEngInit(void)
5711 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
5715 BOOL WineEngDestroyFontInstance(HFONT hfont)
5720 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
5725 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
5726 LPWORD pgi, DWORD flags)
5731 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
5732 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5735 ERR("called but we don't have FreeType\n");
5739 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5741 ERR("called but we don't have FreeType\n");
5745 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5746 OUTLINETEXTMETRICW *potm)
5748 ERR("called but we don't have FreeType\n");
5752 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5755 ERR("called but we don't have FreeType\n");
5759 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5762 ERR("called but we don't have FreeType\n");
5766 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5769 ERR("called but we don't have FreeType\n");
5773 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5774 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5776 ERR("called but we don't have FreeType\n");
5780 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5781 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5783 ERR("called but we don't have FreeType\n");
5787 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5790 ERR("called but we don't have FreeType\n");
5794 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5796 ERR("called but we don't have FreeType\n");
5800 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5806 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5812 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
5818 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5821 return DEFAULT_CHARSET;
5824 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5829 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5831 FIXME("(%p, %p): stub\n", font, glyphset);
5835 BOOL WineEngFontIsLinked(GdiFont *font)
5840 /*************************************************************************
5841 * GetRasterizerCaps (GDI32.@)
5843 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5845 lprs->nSize = sizeof(RASTERIZER_STATUS);
5847 lprs->nLanguageID = 0;
5851 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5853 ERR("called but we don't have FreeType\n");
5857 #endif /* HAVE_FREETYPE */