2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
40 #ifdef HAVE_CARBON_CARBON_H
41 #define LoadResource __carbon_LoadResource
42 #define CompareString __carbon_CompareString
43 #define GetCurrentThread __carbon_GetCurrentThread
44 #define GetCurrentProcess __carbon_GetCurrentProcess
45 #define AnimatePalette __carbon_AnimatePalette
46 #define EqualRgn __carbon_EqualRgn
47 #define FillRgn __carbon_FillRgn
48 #define FrameRgn __carbon_FrameRgn
49 #define GetPixel __carbon_GetPixel
50 #define InvertRgn __carbon_InvertRgn
51 #define LineTo __carbon_LineTo
52 #define OffsetRgn __carbon_OffsetRgn
53 #define PaintRgn __carbon_PaintRgn
54 #define Polygon __carbon_Polygon
55 #define ResizePalette __carbon_ResizePalette
56 #define SetRectRgn __carbon_SetRectRgn
57 #include <Carbon/Carbon.h>
60 #undef GetCurrentThread
63 #undef GetCurrentProcess
76 #endif /* HAVE_CARBON_CARBON_H */
84 #include "gdi_private.h"
85 #include "wine/unicode.h"
86 #include "wine/debug.h"
87 #include "wine/list.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(font);
93 #ifdef HAVE_FT2BUILD_H
96 #ifdef HAVE_FREETYPE_FREETYPE_H
97 #include <freetype/freetype.h>
99 #ifdef HAVE_FREETYPE_FTGLYPH_H
100 #include <freetype/ftglyph.h>
102 #ifdef HAVE_FREETYPE_TTTABLES_H
103 #include <freetype/tttables.h>
105 #ifdef HAVE_FREETYPE_FTTYPES_H
106 #include <freetype/fttypes.h>
108 #ifdef HAVE_FREETYPE_FTSNAMES_H
109 #include <freetype/ftsnames.h>
111 # ifdef HAVE_FREETYPE_FTNAMES_H
112 # include <freetype/ftnames.h>
115 #ifdef HAVE_FREETYPE_TTNAMEID_H
116 #include <freetype/ttnameid.h>
118 #ifdef HAVE_FREETYPE_FTOUTLN_H
119 #include <freetype/ftoutln.h>
121 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
122 #include <freetype/internal/sfnt.h>
124 #ifdef HAVE_FREETYPE_FTTRIGON_H
125 #include <freetype/fttrigon.h>
127 #ifdef HAVE_FREETYPE_FTWINFNT_H
128 #include <freetype/ftwinfnt.h>
130 #ifdef HAVE_FREETYPE_FTMODAPI_H
131 #include <freetype/ftmodapi.h>
134 #ifndef HAVE_FT_TRUETYPEENGINETYPE
137 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
138 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
139 FT_TRUETYPE_ENGINE_TYPE_PATENTED
140 } FT_TrueTypeEngineType;
143 static FT_Library library = 0;
150 static FT_Version_t FT_Version;
151 static DWORD FT_SimpleVersion;
153 static void *ft_handle = NULL;
155 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
156 MAKE_FUNCPTR(FT_Vector_Unit);
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_Module);
160 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
163 MAKE_FUNCPTR(FT_Init_FreeType);
164 MAKE_FUNCPTR(FT_Load_Glyph);
165 MAKE_FUNCPTR(FT_Matrix_Multiply);
166 MAKE_FUNCPTR(FT_MulFix);
167 MAKE_FUNCPTR(FT_New_Face);
168 MAKE_FUNCPTR(FT_New_Memory_Face);
169 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
170 MAKE_FUNCPTR(FT_Outline_Transform);
171 MAKE_FUNCPTR(FT_Outline_Translate);
172 MAKE_FUNCPTR(FT_Select_Charmap);
173 MAKE_FUNCPTR(FT_Set_Charmap);
174 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
175 MAKE_FUNCPTR(FT_Vector_Transform);
176 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
177 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
178 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
179 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
180 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
181 #ifdef HAVE_FREETYPE_FTWINFNT_H
182 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
185 #ifdef SONAME_LIBFONTCONFIG
186 #include <fontconfig/fontconfig.h>
187 MAKE_FUNCPTR(FcConfigGetCurrent);
188 MAKE_FUNCPTR(FcFontList);
189 MAKE_FUNCPTR(FcFontSetDestroy);
190 MAKE_FUNCPTR(FcInit);
191 MAKE_FUNCPTR(FcObjectSetAdd);
192 MAKE_FUNCPTR(FcObjectSetCreate);
193 MAKE_FUNCPTR(FcObjectSetDestroy);
194 MAKE_FUNCPTR(FcPatternCreate);
195 MAKE_FUNCPTR(FcPatternDestroy);
196 MAKE_FUNCPTR(FcPatternGetBool);
197 MAKE_FUNCPTR(FcPatternGetString);
203 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
204 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
205 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
208 #ifndef ft_encoding_none
209 #define FT_ENCODING_NONE ft_encoding_none
211 #ifndef ft_encoding_ms_symbol
212 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
214 #ifndef ft_encoding_unicode
215 #define FT_ENCODING_UNICODE ft_encoding_unicode
217 #ifndef ft_encoding_apple_roman
218 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
221 #ifdef WORDS_BIGENDIAN
222 #define GET_BE_WORD(x) (x)
224 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
227 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
234 FT_Short internal_leading;
237 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
238 So to let this compile on older versions of FreeType we'll define the
239 new structure here. */
241 FT_Short height, width;
242 FT_Pos size, x_ppem, y_ppem;
248 NEWTEXTMETRICEXW ntm;
252 typedef struct tagFace {
257 DWORD font_data_size;
260 FONTSIGNATURE fs_links;
262 FT_Fixed font_version;
264 Bitmap_Size size; /* set if face is a bitmap */
265 BOOL external; /* TRUE if we should manually add this font to the registry */
266 struct tagFamily *family;
267 /* Cached data for Enum */
268 struct enum_data *cached_enum_data;
271 typedef struct tagFamily {
273 const WCHAR *FamilyName;
279 INT adv; /* These three hold to widths of the unrotated chars */
297 typedef struct tagHFONTLIST {
312 struct list hfontlist;
313 OUTLINETEXTMETRICW *potm;
314 DWORD total_kern_pairs;
315 KERNINGPAIR *kern_pairs;
316 struct list child_fonts;
318 /* the following members can be accessed without locking, they are never modified after creation */
320 struct font_mapping *mapping;
342 const WCHAR *font_name;
346 #define GM_BLOCK_SIZE 128
347 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
349 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
350 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
351 #define UNUSED_CACHE_SIZE 10
352 static struct list child_font_list = LIST_INIT(child_font_list);
353 static struct list system_links = LIST_INIT(system_links);
355 static struct list font_subst_list = LIST_INIT(font_subst_list);
357 static struct list font_list = LIST_INIT(font_list);
359 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
360 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
361 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
363 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
365 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
366 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
367 'W','i','n','d','o','w','s','\\',
368 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
369 'F','o','n','t','s','\0'};
371 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
372 'W','i','n','d','o','w','s',' ','N','T','\\',
373 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
374 'F','o','n','t','s','\0'};
376 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
377 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
378 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
379 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
381 static const WCHAR * const SystemFontValues[4] = {
388 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
389 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
391 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
392 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
393 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
394 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
395 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
396 'E','u','r','o','p','e','a','n','\0'};
397 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
398 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
399 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
400 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
401 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
402 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
403 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
404 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
405 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
406 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
407 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
408 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
410 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
420 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
428 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
437 typedef struct tagFontSubst {
453 static struct list mappings_list = LIST_INIT( mappings_list );
455 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
457 static CRITICAL_SECTION freetype_cs;
458 static CRITICAL_SECTION_DEBUG critsect_debug =
461 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
462 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
464 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
466 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
468 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
469 static BOOL use_default_fallback = FALSE;
471 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
473 /****************************************
474 * Notes on .fon files
476 * The fonts System, FixedSys and Terminal are special. There are typically multiple
477 * versions installed for different resolutions and codepages. Windows stores which one to use
478 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
480 * FIXEDFON.FON FixedSys
482 * OEMFONT.FON Terminal
483 * LogPixels Current dpi set by the display control panel applet
484 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
485 * also has a LogPixels value that appears to mirror this)
487 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
488 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
489 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
490 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
491 * so that makes sense.
493 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
494 * to be mapped into the registry on Windows 2000 at least).
497 * ega80woa.fon=ega80850.fon
498 * ega40woa.fon=ega40850.fon
499 * cga80woa.fon=cga80850.fon
500 * cga40woa.fon=cga40850.fon
503 /* These are all structures needed for the GSUB table */
505 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
506 #define TATEGAKI_LOWER_BOUND 0x02F1
522 GSUB_ScriptRecord ScriptRecord[1];
528 } GSUB_LangSysRecord;
533 GSUB_LangSysRecord LangSysRecord[1];
537 WORD LookupOrder; /* Reserved */
538 WORD ReqFeatureIndex;
540 WORD FeatureIndex[1];
546 } GSUB_FeatureRecord;
550 GSUB_FeatureRecord FeatureRecord[1];
554 WORD FeatureParams; /* Reserved */
556 WORD LookupListIndex[1];
575 } GSUB_CoverageFormat1;
580 WORD StartCoverageIndex;
586 GSUB_RangeRecord RangeRecord[1];
587 } GSUB_CoverageFormat2;
590 WORD SubstFormat; /* = 1 */
593 } GSUB_SingleSubstFormat1;
596 WORD SubstFormat; /* = 2 */
600 }GSUB_SingleSubstFormat2;
602 #ifdef HAVE_CARBON_CARBON_H
603 static char *find_cache_dir(void)
607 static char cached_path[MAX_PATH];
608 static const char *wine = "/Wine", *fonts = "/Fonts";
610 if(*cached_path) return cached_path;
612 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
615 WARN("can't create cached data folder\n");
618 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
621 WARN("can't create cached data path\n");
625 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
627 ERR("Could not create full path\n");
631 strcat(cached_path, wine);
633 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
635 WARN("Couldn't mkdir %s\n", cached_path);
639 strcat(cached_path, fonts);
640 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
642 WARN("Couldn't mkdir %s\n", cached_path);
649 /******************************************************************
652 * Extracts individual TrueType font files from a Mac suitcase font
653 * and saves them into the user's caches directory (see
655 * Returns a NULL terminated array of filenames.
657 * We do this because they are apps that try to read ttf files
658 * themselves and they don't like Mac suitcase files.
660 static char **expand_mac_font(const char *path)
667 const char *filename;
671 unsigned int size, max_size;
674 TRACE("path %s\n", path);
676 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
679 WARN("failed to get ref\n");
683 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
686 TRACE("no data fork, so trying resource fork\n");
687 res_ref = FSOpenResFile(&ref, fsRdPerm);
690 TRACE("unable to open resource fork\n");
697 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
700 CloseResFile(res_ref);
704 out_dir = find_cache_dir();
706 filename = strrchr(path, '/');
707 if(!filename) filename = path;
710 /* output filename has the form out_dir/filename_%04x.ttf */
711 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
718 unsigned short *num_faces_ptr, num_faces, face;
721 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
723 fond = Get1IndResource(fond_res, idx);
725 TRACE("got fond resource %d\n", idx);
728 fam_rec = *(FamRec**)fond;
729 num_faces_ptr = (unsigned short *)(fam_rec + 1);
730 num_faces = GET_BE_WORD(*num_faces_ptr);
732 assoc = (AsscEntry*)(num_faces_ptr + 1);
733 TRACE("num faces %04x\n", num_faces);
734 for(face = 0; face < num_faces; face++, assoc++)
737 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
738 unsigned short size, font_id;
741 size = GET_BE_WORD(assoc->fontSize);
742 font_id = GET_BE_WORD(assoc->fontID);
745 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
749 TRACE("trying to load sfnt id %04x\n", font_id);
750 sfnt = GetResource(sfnt_res, font_id);
753 TRACE("can't get sfnt resource %04x\n", font_id);
757 output = HeapAlloc(GetProcessHeap(), 0, output_len);
762 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
764 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
765 if(fd != -1 || errno == EEXIST)
769 unsigned char *sfnt_data;
772 sfnt_data = *(unsigned char**)sfnt;
773 write(fd, sfnt_data, GetHandleSize(sfnt));
777 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
780 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
782 ret.array[ret.size++] = output;
786 WARN("unable to create %s\n", output);
787 HeapFree(GetProcessHeap(), 0, output);
790 ReleaseResource(sfnt);
793 ReleaseResource(fond);
796 CloseResFile(res_ref);
801 #endif /* HAVE_CARBON_CARBON_H */
803 static inline BOOL is_win9x(void)
805 return GetVersion() & 0x80000000;
808 This function builds an FT_Fixed from a float. It puts the integer part
809 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
810 It fails if the integer part of the float number is greater than SHORT_MAX.
812 static inline FT_Fixed FT_FixedFromFloat(float f)
815 unsigned short fract = (f - value) * 0xFFFF;
816 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
820 This function builds an FT_Fixed from a FIXED. It simply put f.value
821 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
823 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
825 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
829 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
834 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
835 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
837 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
838 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
840 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
842 if(face_name && strcmpiW(face_name, family->FamilyName))
844 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
848 file = strrchr(face->file, '/');
853 if(!strcasecmp(file, file_nameA))
855 HeapFree(GetProcessHeap(), 0, file_nameA);
860 HeapFree(GetProcessHeap(), 0, file_nameA);
864 static Family *find_family_from_name(const WCHAR *name)
868 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
870 if(!strcmpiW(family->FamilyName, name))
877 static void DumpSubstList(void)
881 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
883 if(psub->from.charset != -1 || psub->to.charset != -1)
884 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
885 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
887 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
888 debugstr_w(psub->to.name));
893 static LPWSTR strdupW(LPCWSTR p)
896 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
897 ret = HeapAlloc(GetProcessHeap(), 0, len);
902 static LPSTR strdupA(LPCSTR p)
905 DWORD len = (strlen(p) + 1);
906 ret = HeapAlloc(GetProcessHeap(), 0, len);
911 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
916 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
918 if(!strcmpiW(element->from.name, from_name) &&
919 (element->from.charset == from_charset ||
920 element->from.charset == -1))
927 #define ADD_FONT_SUBST_FORCE 1
929 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
931 FontSubst *from_exist, *to_exist;
933 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
935 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
937 list_remove(&from_exist->entry);
938 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
939 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
940 HeapFree(GetProcessHeap(), 0, from_exist);
946 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
950 HeapFree(GetProcessHeap(), 0, subst->to.name);
951 subst->to.name = strdupW(to_exist->to.name);
954 list_add_tail(subst_list, &subst->entry);
959 HeapFree(GetProcessHeap(), 0, subst->from.name);
960 HeapFree(GetProcessHeap(), 0, subst->to.name);
961 HeapFree(GetProcessHeap(), 0, subst);
965 static void split_subst_info(NameCs *nc, LPSTR str)
967 CHAR *p = strrchr(str, ',');
972 nc->charset = strtol(p+1, NULL, 10);
975 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
976 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
977 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
980 static void LoadSubstList(void)
984 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
988 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
989 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
990 &hkey) == ERROR_SUCCESS) {
992 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
993 &valuelen, &datalen, NULL, NULL);
995 valuelen++; /* returned value doesn't include room for '\0' */
996 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
997 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1001 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1002 &dlen) == ERROR_SUCCESS) {
1003 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1005 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1006 split_subst_info(&psub->from, value);
1007 split_subst_info(&psub->to, data);
1009 /* Win 2000 doesn't allow mapping between different charsets
1010 or mapping of DEFAULT_CHARSET */
1011 if((psub->to.charset != psub->from.charset) ||
1012 psub->to.charset == DEFAULT_CHARSET) {
1013 HeapFree(GetProcessHeap(), 0, psub->to.name);
1014 HeapFree(GetProcessHeap(), 0, psub->from.name);
1015 HeapFree(GetProcessHeap(), 0, psub);
1017 add_font_subst(&font_subst_list, psub, 0);
1019 /* reset dlen and vlen */
1023 HeapFree(GetProcessHeap(), 0, data);
1024 HeapFree(GetProcessHeap(), 0, value);
1029 static WCHAR *get_familyname(FT_Face ft_face)
1031 WCHAR *family = NULL;
1033 FT_UInt num_names, name_index, i;
1035 if(FT_IS_SFNT(ft_face))
1037 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1039 for(name_index = 0; name_index < num_names; name_index++)
1041 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1043 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
1044 (name.language_id == GetUserDefaultLCID()) &&
1045 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
1046 (name.encoding_id == TT_MS_ID_UNICODE_CS))
1048 /* String is not nul terminated and string_len is a byte length. */
1049 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1050 for(i = 0; i < name.string_len / 2; i++)
1052 WORD *tmp = (WORD *)&name.string[i * 2];
1053 family[i] = GET_BE_WORD(*tmp);
1057 TRACE("Got localised name %s\n", debugstr_w(family));
1068 /*****************************************************************
1071 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1072 * of FreeType that don't export this function.
1075 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1080 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1081 if(pFT_Load_Sfnt_Table)
1083 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1085 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1086 else /* Do it the hard way */
1088 TT_Face tt_face = (TT_Face) ft_face;
1089 SFNT_Interface *sfnt;
1090 if (FT_Version.major==2 && FT_Version.minor==0)
1093 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1097 /* A field was added in the middle of the structure in 2.1.x */
1098 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1100 err = sfnt->load_any(tt_face, table, offset, buf, len);
1108 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1109 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1110 "Please upgrade your freetype library.\n");
1113 err = FT_Err_Unimplemented_Feature;
1120 #define ADDFONT_EXTERNAL_FONT 0x01
1121 #define ADDFONT_FORCE_BITMAP 0x02
1122 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1126 TT_Header *pHeader = NULL;
1127 WCHAR *english_family, *localised_family, *StyleW;
1131 struct list *family_elem_ptr, *face_elem_ptr;
1133 FT_Long face_index = 0, num_faces;
1134 #ifdef HAVE_FREETYPE_FTWINFNT_H
1135 FT_WinFNT_HeaderRec winfnt_header;
1137 int i, bitmap_num, internal_leading;
1140 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1141 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1143 #ifdef HAVE_CARBON_CARBON_H
1144 if(file && !fake_family)
1146 char **mac_list = expand_mac_font(file);
1149 BOOL had_one = FALSE;
1151 for(cursor = mac_list; *cursor; cursor++)
1154 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1155 HeapFree(GetProcessHeap(), 0, *cursor);
1157 HeapFree(GetProcessHeap(), 0, mac_list);
1162 #endif /* HAVE_CARBON_CARBON_H */
1165 char *family_name = fake_family;
1169 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1170 err = pFT_New_Face(library, file, face_index, &ft_face);
1173 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1174 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1178 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1182 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*/
1183 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1184 pFT_Done_Face(ft_face);
1188 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1189 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1190 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1191 pFT_Done_Face(ft_face);
1195 if(FT_IS_SFNT(ft_face))
1197 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1198 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1199 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1201 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1202 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1203 pFT_Done_Face(ft_face);
1207 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1208 we don't want to load these. */
1209 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1213 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1215 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1216 pFT_Done_Face(ft_face);
1222 if(!ft_face->family_name || !ft_face->style_name) {
1223 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1224 pFT_Done_Face(ft_face);
1228 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1230 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1231 pFT_Done_Face(ft_face);
1237 localised_family = get_familyname(ft_face);
1238 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1240 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1241 HeapFree(GetProcessHeap(), 0, localised_family);
1242 num_faces = ft_face->num_faces;
1243 pFT_Done_Face(ft_face);
1246 HeapFree(GetProcessHeap(), 0, localised_family);
1250 family_name = ft_face->family_name;
1254 My_FT_Bitmap_Size *size = NULL;
1257 if(!FT_IS_SCALABLE(ft_face))
1258 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1260 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1261 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1262 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1264 localised_family = NULL;
1266 localised_family = get_familyname(ft_face);
1267 if(localised_family && !strcmpW(localised_family, english_family)) {
1268 HeapFree(GetProcessHeap(), 0, localised_family);
1269 localised_family = NULL;
1274 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1275 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1276 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1281 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1282 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1283 list_init(&family->faces);
1284 list_add_tail(&font_list, &family->entry);
1286 if(localised_family) {
1287 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1288 subst->from.name = strdupW(english_family);
1289 subst->from.charset = -1;
1290 subst->to.name = strdupW(localised_family);
1291 subst->to.charset = -1;
1292 add_font_subst(&font_subst_list, subst, 0);
1295 HeapFree(GetProcessHeap(), 0, localised_family);
1296 HeapFree(GetProcessHeap(), 0, english_family);
1298 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1299 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1300 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1302 internal_leading = 0;
1303 memset(&fs, 0, sizeof(fs));
1305 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1307 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1308 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1309 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1310 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1311 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1312 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1313 if(pOS2->version == 0) {
1316 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1317 fs.fsCsb[0] |= FS_LATIN1;
1319 fs.fsCsb[0] |= FS_SYMBOL;
1322 #ifdef HAVE_FREETYPE_FTWINFNT_H
1323 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1325 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1326 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1327 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1329 internal_leading = winfnt_header.internal_leading;
1333 face_elem_ptr = list_head(&family->faces);
1334 while(face_elem_ptr) {
1335 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1336 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1337 if(!strcmpW(face->StyleName, StyleW) &&
1338 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1339 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1340 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1341 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1344 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1345 HeapFree(GetProcessHeap(), 0, StyleW);
1346 pFT_Done_Face(ft_face);
1349 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1350 TRACE("Original font is newer so skipping this one\n");
1351 HeapFree(GetProcessHeap(), 0, StyleW);
1352 pFT_Done_Face(ft_face);
1355 TRACE("Replacing original with this one\n");
1356 list_remove(&face->entry);
1357 HeapFree(GetProcessHeap(), 0, face->file);
1358 HeapFree(GetProcessHeap(), 0, face->StyleName);
1359 HeapFree(GetProcessHeap(), 0, face);
1364 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1365 face->cached_enum_data = NULL;
1366 list_add_tail(&family->faces, &face->entry);
1367 face->StyleName = StyleW;
1370 face->file = strdupA(file);
1371 face->font_data_ptr = NULL;
1372 face->font_data_size = 0;
1377 face->font_data_ptr = font_data_ptr;
1378 face->font_data_size = font_data_size;
1380 face->face_index = face_index;
1382 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1383 face->ntmFlags |= NTM_ITALIC;
1384 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1385 face->ntmFlags |= NTM_BOLD;
1386 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1387 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1388 face->family = family;
1389 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1391 memset(&face->fs_links, 0, sizeof(face->fs_links));
1393 if(FT_IS_SCALABLE(ft_face)) {
1394 memset(&face->size, 0, sizeof(face->size));
1395 face->scalable = TRUE;
1397 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1398 size->height, size->width, size->size >> 6,
1399 size->x_ppem >> 6, size->y_ppem >> 6);
1400 face->size.height = size->height;
1401 face->size.width = size->width;
1402 face->size.size = size->size;
1403 face->size.x_ppem = size->x_ppem;
1404 face->size.y_ppem = size->y_ppem;
1405 face->size.internal_leading = internal_leading;
1406 face->scalable = FALSE;
1409 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1411 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1413 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1414 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 Default_Fallback 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 lf.lfWidth = abs(lf.lfWidth);
3125 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3127 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3128 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3129 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3132 /* check the cache first */
3133 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
3134 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3135 LeaveCriticalSection( &freetype_cs );
3139 TRACE("not in cache\n");
3140 if(list_empty(&font_list)) /* No fonts installed */
3142 TRACE("No fonts installed\n");
3143 LeaveCriticalSection( &freetype_cs );
3146 if(!have_installed_roman_font)
3148 TRACE("No roman font installed\n");
3149 LeaveCriticalSection( &freetype_cs );
3155 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
3156 ret->font_desc.lf = lf;
3157 ret->font_desc.can_use_bitmap = can_use_bitmap;
3158 calc_hash(&ret->font_desc);
3159 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3160 hflist->hfont = hfont;
3161 list_add_head(&ret->hfontlist, &hflist->entry);
3164 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3165 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3166 original value lfCharSet. Note this is a special case for
3167 Symbol and doesn't happen at least for "Wingdings*" */
3169 if(!strcmpiW(lf.lfFaceName, SymbolW))
3170 lf.lfCharSet = SYMBOL_CHARSET;
3172 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3173 switch(lf.lfCharSet) {
3174 case DEFAULT_CHARSET:
3175 csi.fs.fsCsb[0] = 0;
3178 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3179 csi.fs.fsCsb[0] = 0;
3185 if(lf.lfFaceName[0] != '\0') {
3187 SYSTEM_LINKS *font_link;
3188 CHILD_FONT *font_link_entry;
3189 LPWSTR FaceName = lf.lfFaceName;
3192 * Check for a leading '@' this signals that the font is being
3193 * requested in tategaki mode (vertical writing substitution) but
3194 * does not affect the fontface that is to be selected.
3196 if (lf.lfFaceName[0]=='@')
3197 FaceName = &lf.lfFaceName[1];
3199 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3202 TRACE("substituting %s -> %s\n", debugstr_w(FaceName),
3203 debugstr_w(psub->to.name));
3204 strcpyW(FaceName, psub->to.name);
3207 /* We want a match on name and charset or just name if
3208 charset was DEFAULT_CHARSET. If the latter then
3209 we fixup the returned charset later in get_nearest_charset
3210 where we'll either use the charset of the current ansi codepage
3211 or if that's unavailable the first charset that the font supports.
3213 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3214 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3215 if(!strcmpiW(family->FamilyName, FaceName)) {
3216 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3217 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3218 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3219 if(face->scalable || can_use_bitmap)
3226 * Try check the SystemLink list first for a replacement font.
3227 * We may find good replacements there.
3229 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3231 if(!strcmpiW(font_link->font_name, FaceName))
3233 TRACE("found entry in system list\n");
3234 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3236 face = font_link_entry->face;
3237 family = face->family;
3238 if(csi.fs.fsCsb[0] &
3239 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3241 if(face->scalable || can_use_bitmap)
3249 /* If requested charset was DEFAULT_CHARSET then try using charset
3250 corresponding to the current ansi codepage */
3251 if(!csi.fs.fsCsb[0]) {
3253 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3254 FIXME("TCI failed on codepage %d\n", acp);
3255 csi.fs.fsCsb[0] = 0;
3257 lf.lfCharSet = csi.ciCharset;
3260 /* Face families are in the top 4 bits of lfPitchAndFamily,
3261 so mask with 0xF0 before testing */
3263 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3264 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3265 strcpyW(lf.lfFaceName, defFixed);
3266 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3267 strcpyW(lf.lfFaceName, defSerif);
3268 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3269 strcpyW(lf.lfFaceName, defSans);
3271 strcpyW(lf.lfFaceName, defSans);
3272 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3273 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3274 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3275 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3276 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3277 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3278 if(face->scalable || can_use_bitmap)
3284 last_resort_family = NULL;
3285 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3286 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3287 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3288 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3289 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3292 if(can_use_bitmap && !last_resort_family)
3293 last_resort_family = family;
3298 if(last_resort_family) {
3299 family = last_resort_family;
3300 csi.fs.fsCsb[0] = 0;
3304 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3305 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3306 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3307 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3308 if(face->scalable) {
3309 csi.fs.fsCsb[0] = 0;
3310 WARN("just using first face for now\n");
3313 if(can_use_bitmap && !last_resort_family)
3314 last_resort_family = family;
3317 if(!last_resort_family) {
3318 FIXME("can't find a single appropriate font - bailing\n");
3320 LeaveCriticalSection( &freetype_cs );
3324 WARN("could only find a bitmap font - this will probably look awful!\n");
3325 family = last_resort_family;
3326 csi.fs.fsCsb[0] = 0;
3329 it = lf.lfItalic ? 1 : 0;
3330 bd = lf.lfWeight > 550 ? 1 : 0;
3332 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
3333 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
3335 face = best = best_bitmap = NULL;
3336 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3338 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3342 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3343 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3344 new_score = (italic ^ it) + (bold ^ bd);
3345 if(!best || new_score <= score)
3347 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3348 italic, bold, it, bd);
3351 if(best->scalable && score == 0) break;
3355 newdiff = height - (signed int)(best->size.height);
3357 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3358 if(!best_bitmap || new_score < score ||
3359 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3361 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3364 if(score == 0 && diff == 0) break;
3371 face = best->scalable ? best : best_bitmap;
3372 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3373 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3377 if(csi.fs.fsCsb[0]) {
3378 ret->charset = lf.lfCharSet;
3379 ret->codepage = csi.ciACP;
3382 ret->charset = get_nearest_charset(face, &ret->codepage);
3384 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3385 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3387 ret->aveWidth = height ? lf.lfWidth : 0;
3389 if(!face->scalable) {
3390 /* Windows uses integer scaling factors for bitmap fonts */
3391 INT scale, scaled_height;
3393 if (height != 0) height = diff;
3394 height += face->size.height;
3396 scale = (height + face->size.height - 1) / face->size.height;
3397 scaled_height = scale * face->size.height;
3398 /* XP allows not more than 10% deviation */
3399 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3400 ret->scale_y = scale;
3402 width = face->size.x_ppem >> 6;
3403 height = face->size.y_ppem >> 6;
3407 TRACE("font scale y: %f\n", ret->scale_y);
3409 ret->ft_face = OpenFontFace(ret, face, width, height);
3414 LeaveCriticalSection( &freetype_cs );
3418 ret->ntmFlags = face->ntmFlags;
3420 if (ret->charset == SYMBOL_CHARSET &&
3421 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3424 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3428 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3431 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3432 ret->name = strdupW(family->FamilyName);
3433 ret->underline = lf.lfUnderline ? 0xff : 0;
3434 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3435 create_child_font_list(ret);
3437 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3439 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3440 if (length != GDI_ERROR)
3442 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3443 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3444 TRACE("Loaded GSUB table of %i bytes\n",length);
3448 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3450 list_add_head(&gdi_font_list, &ret->entry);
3451 LeaveCriticalSection( &freetype_cs );
3455 static void dump_gdi_font_list(void)
3458 struct list *elem_ptr;
3460 TRACE("---------- gdiFont Cache ----------\n");
3461 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3462 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3463 TRACE("gdiFont=%p %s %d\n",
3464 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3467 TRACE("---------- Unused gdiFont Cache ----------\n");
3468 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3469 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3470 TRACE("gdiFont=%p %s %d\n",
3471 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3475 /*************************************************************
3476 * WineEngDestroyFontInstance
3478 * free the gdiFont associated with this handle
3481 BOOL WineEngDestroyFontInstance(HFONT handle)
3486 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3489 EnterCriticalSection( &freetype_cs );
3491 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3493 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3494 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3495 if(hflist->hfont == handle)
3497 TRACE("removing child font %p from child list\n", gdiFont);
3498 list_remove(&gdiFont->entry);
3499 LeaveCriticalSection( &freetype_cs );
3504 TRACE("destroying hfont=%p\n", handle);
3506 dump_gdi_font_list();
3508 font_elem_ptr = list_head(&gdi_font_list);
3509 while(font_elem_ptr) {
3510 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3511 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3513 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3514 while(hfontlist_elem_ptr) {
3515 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3516 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3517 if(hflist->hfont == handle) {
3518 list_remove(&hflist->entry);
3519 HeapFree(GetProcessHeap(), 0, hflist);
3523 if(list_empty(&gdiFont->hfontlist)) {
3524 TRACE("Moving to Unused list\n");
3525 list_remove(&gdiFont->entry);
3526 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3531 font_elem_ptr = list_head(&unused_gdi_font_list);
3532 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3533 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3534 while(font_elem_ptr) {
3535 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3536 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3537 TRACE("freeing %p\n", gdiFont);
3538 list_remove(&gdiFont->entry);
3541 LeaveCriticalSection( &freetype_cs );
3545 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3546 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3551 if (face->cached_enum_data)
3554 *pelf = face->cached_enum_data->elf;
3555 *pntm = face->cached_enum_data->ntm;
3556 *ptype = face->cached_enum_data->type;
3560 font = alloc_font();
3562 if(face->scalable) {
3566 height = face->size.y_ppem >> 6;
3567 width = face->size.x_ppem >> 6;
3569 font->scale_y = 1.0;
3571 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3577 font->name = strdupW(face->family->FamilyName);
3578 font->ntmFlags = face->ntmFlags;
3580 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3582 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3584 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3586 lstrcpynW(pelf->elfLogFont.lfFaceName,
3587 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3589 lstrcpynW(pelf->elfFullName,
3590 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3592 lstrcpynW(pelf->elfStyle,
3593 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3598 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3600 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3602 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3603 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3604 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3607 pntm->ntmTm.ntmFlags = face->ntmFlags;
3608 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3609 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3610 pntm->ntmFontSig = face->fs;
3612 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3614 pelf->elfLogFont.lfEscapement = 0;
3615 pelf->elfLogFont.lfOrientation = 0;
3616 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3617 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3618 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3619 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3620 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3621 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3622 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3623 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3624 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3625 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3626 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3629 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3630 *ptype |= TRUETYPE_FONTTYPE;
3631 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3632 *ptype |= DEVICE_FONTTYPE;
3633 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3634 *ptype |= RASTER_FONTTYPE;
3636 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3637 if (face->cached_enum_data)
3639 face->cached_enum_data->elf = *pelf;
3640 face->cached_enum_data->ntm = *pntm;
3641 face->cached_enum_data->type = *ptype;
3647 /*************************************************************
3651 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3655 struct list *family_elem_ptr, *face_elem_ptr;
3657 NEWTEXTMETRICEXW ntm;
3666 lf.lfCharSet = DEFAULT_CHARSET;
3667 lf.lfPitchAndFamily = 0;
3668 lf.lfFaceName[0] = 0;
3672 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3674 EnterCriticalSection( &freetype_cs );
3675 if(plf->lfFaceName[0]) {
3677 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3680 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3681 debugstr_w(psub->to.name));
3683 strcpyW(lf.lfFaceName, psub->to.name);
3687 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3688 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3689 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3690 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3691 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3692 GetEnumStructs(face, &elf, &ntm, &type);
3693 for(i = 0; i < 32; i++) {
3694 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3695 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3696 strcpyW(elf.elfScript, OEM_DOSW);
3697 i = 32; /* break out of loop */
3698 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3701 fs.fsCsb[0] = 1L << i;
3703 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3705 csi.ciCharset = DEFAULT_CHARSET;
3706 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3707 if(csi.ciCharset != DEFAULT_CHARSET) {
3708 elf.elfLogFont.lfCharSet =
3709 ntm.ntmTm.tmCharSet = csi.ciCharset;
3711 strcpyW(elf.elfScript, ElfScriptsW[i]);
3713 FIXME("Unknown elfscript for bit %d\n", i);
3716 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3717 debugstr_w(elf.elfLogFont.lfFaceName),
3718 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3719 csi.ciCharset, type, debugstr_w(elf.elfScript),
3720 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3721 ntm.ntmTm.ntmFlags);
3722 /* release section before callback (FIXME) */
3723 LeaveCriticalSection( &freetype_cs );
3724 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3725 EnterCriticalSection( &freetype_cs );
3731 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3732 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3733 face_elem_ptr = list_head(&family->faces);
3734 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3735 GetEnumStructs(face, &elf, &ntm, &type);
3736 for(i = 0; i < 32; i++) {
3737 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3738 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3739 strcpyW(elf.elfScript, OEM_DOSW);
3740 i = 32; /* break out of loop */
3741 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3744 fs.fsCsb[0] = 1L << i;
3746 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3748 csi.ciCharset = DEFAULT_CHARSET;
3749 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3750 if(csi.ciCharset != DEFAULT_CHARSET) {
3751 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3754 strcpyW(elf.elfScript, ElfScriptsW[i]);
3756 FIXME("Unknown elfscript for bit %d\n", i);
3759 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3760 debugstr_w(elf.elfLogFont.lfFaceName),
3761 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3762 csi.ciCharset, type, debugstr_w(elf.elfScript),
3763 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3764 ntm.ntmTm.ntmFlags);
3765 /* release section before callback (FIXME) */
3766 LeaveCriticalSection( &freetype_cs );
3767 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3768 EnterCriticalSection( &freetype_cs );
3772 LeaveCriticalSection( &freetype_cs );
3776 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3778 pt->x.value = vec->x >> 6;
3779 pt->x.fract = (vec->x & 0x3f) << 10;
3780 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3781 pt->y.value = vec->y >> 6;
3782 pt->y.fract = (vec->y & 0x3f) << 10;
3783 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3787 /***************************************************
3788 * According to the MSDN documentation on WideCharToMultiByte,
3789 * certain codepages cannot set the default_used parameter.
3790 * This returns TRUE if the codepage can set that parameter, false else
3791 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3793 static BOOL codepage_sets_default_used(UINT codepage)
3807 * GSUB Table handling functions
3810 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
3812 const GSUB_CoverageFormat1* cf1;
3814 cf1 = (GSUB_CoverageFormat1*)table;
3816 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
3818 int count = GET_BE_WORD(cf1->GlyphCount);
3820 TRACE("Coverage Format 1, %i glyphs\n",count);
3821 for (i = 0; i < count; i++)
3822 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
3826 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
3828 const GSUB_CoverageFormat2* cf2;
3831 cf2 = (GSUB_CoverageFormat2*)cf1;
3833 count = GET_BE_WORD(cf2->RangeCount);
3834 TRACE("Coverage Format 2, %i ranges\n",count);
3835 for (i = 0; i < count; i++)
3837 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
3839 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
3840 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
3842 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
3843 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
3849 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
3854 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
3856 const GSUB_ScriptList *script;
3857 const GSUB_Script *deflt = NULL;
3859 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
3861 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
3862 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
3864 const GSUB_Script *scr;
3867 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
3868 scr = (GSUB_Script*)((LPBYTE)script + offset);
3870 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
3872 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
3878 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
3882 const GSUB_LangSys *Lang;
3884 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
3886 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
3888 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
3889 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
3891 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
3894 offset = GET_BE_WORD(script->DefaultLangSys);
3897 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
3903 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
3906 const GSUB_FeatureList *feature;
3907 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
3909 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
3910 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
3912 int index = GET_BE_WORD(lang->FeatureIndex[i]);
3913 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
3915 const GSUB_Feature *feat;
3916 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
3923 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
3927 const GSUB_LookupList *lookup;
3928 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
3930 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
3931 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
3933 const GSUB_LookupTable *look;
3934 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
3935 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
3936 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
3937 if (GET_BE_WORD(look->LookupType) != 1)
3938 FIXME("We only handle SubType 1\n");
3943 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
3945 const GSUB_SingleSubstFormat1 *ssf1;
3946 offset = GET_BE_WORD(look->SubTable[j]);
3947 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
3948 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
3950 int offset = GET_BE_WORD(ssf1->Coverage);
3951 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
3952 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
3954 TRACE(" Glyph 0x%x ->",glyph);
3955 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
3956 TRACE(" 0x%x\n",glyph);
3961 const GSUB_SingleSubstFormat2 *ssf2;
3965 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
3966 offset = GET_BE_WORD(ssf1->Coverage);
3967 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
3968 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
3969 TRACE(" Coverage index %i\n",index);
3972 TRACE(" Glyph is 0x%x ->",glyph);
3973 glyph = GET_BE_WORD(ssf2->Substitute[index]);
3974 TRACE("0x%x\n",glyph);
3983 static const char* get_opentype_script(const GdiFont *font)
3986 * I am not sure if this is the correct way to generate our script tag
3989 switch (font->charset)
3991 case ANSI_CHARSET: return "latn";
3992 case BALTIC_CHARSET: return "latn"; /* ?? */
3993 case CHINESEBIG5_CHARSET: return "hani";
3994 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
3995 case GB2312_CHARSET: return "hani";
3996 case GREEK_CHARSET: return "grek";
3997 case HANGUL_CHARSET: return "hang";
3998 case RUSSIAN_CHARSET: return "cyrl";
3999 case SHIFTJIS_CHARSET: return "kana";
4000 case TURKISH_CHARSET: return "latn"; /* ?? */
4001 case VIETNAMESE_CHARSET: return "latn";
4002 case JOHAB_CHARSET: return "latn"; /* ?? */
4003 case ARABIC_CHARSET: return "arab";
4004 case HEBREW_CHARSET: return "hebr";
4005 case THAI_CHARSET: return "thai";
4006 default: return "latn";
4010 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4012 const GSUB_Header *header;
4013 const GSUB_Script *script;
4014 const GSUB_LangSys *language;
4015 const GSUB_Feature *feature;
4017 if (!font->GSUB_Table)
4020 header = font->GSUB_Table;
4022 script = GSUB_get_script_table(header, get_opentype_script(font));
4025 TRACE("Script not found\n");
4028 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4031 TRACE("Language not found\n");
4034 feature = GSUB_get_feature(header, language, "vrt2");
4036 feature = GSUB_get_feature(header, language, "vert");
4039 TRACE("vrt2/vert feature not found\n");
4042 return GSUB_apply_feature(header, feature, glyph);
4045 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4049 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4050 WCHAR wc = (WCHAR)glyph;
4052 BOOL *default_used_pointer;
4055 default_used_pointer = NULL;
4056 default_used = FALSE;
4057 if (codepage_sets_default_used(font->codepage))
4058 default_used_pointer = &default_used;
4059 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4062 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4063 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4064 return get_GSUB_vert_glyph(font,ret);
4067 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
4068 glyph = glyph + 0xf000;
4069 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4070 return get_GSUB_vert_glyph(font,glyphId);
4073 /*************************************************************
4074 * WineEngGetGlyphIndices
4077 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4078 LPWORD pgi, DWORD flags)
4081 int default_char = -1;
4083 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4085 for(i = 0; i < count; i++)
4087 pgi[i] = get_glyph_index(font, lpstr[i]);
4090 if (default_char == -1)
4092 if (FT_IS_SFNT(font->ft_face))
4094 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4095 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4100 WineEngGetTextMetrics(font, &textm);
4101 default_char = textm.tmDefaultChar;
4104 pgi[i] = default_char;
4110 /*************************************************************
4111 * WineEngGetGlyphOutline
4113 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4114 * except that the first parameter is the HWINEENGFONT of the font in
4115 * question rather than an HDC.
4118 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4119 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4122 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4123 FT_Face ft_face = incoming_font->ft_face;
4124 GdiFont *font = incoming_font;
4125 FT_UInt glyph_index;
4126 DWORD width, height, pitch, needed = 0;
4127 FT_Bitmap ft_bitmap;
4129 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4131 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4132 float widthRatio = 1.0;
4133 FT_Matrix transMat = identityMat;
4134 BOOL needsTransform = FALSE;
4135 BOOL tategaki = (font->GSUB_Table != NULL);
4136 UINT original_index;
4139 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4140 buflen, buf, lpmat);
4142 EnterCriticalSection( &freetype_cs );
4144 if(format & GGO_GLYPH_INDEX) {
4145 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4146 original_index = glyph;
4147 format &= ~GGO_GLYPH_INDEX;
4149 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4150 ft_face = font->ft_face;
4151 original_index = glyph_index;
4154 /* tategaki never appears to happen to lower glyph index */
4155 if (glyph_index < TATEGAKI_LOWER_BOUND )
4158 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4159 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4160 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4161 font->gmsize * sizeof(GM*));
4163 if(format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL && FONT_GM(font,original_index)->init ) {
4164 *lpgm = FONT_GM(font,original_index)->gm;
4165 LeaveCriticalSection( &freetype_cs );
4166 return 1; /* FIXME */
4170 if (!font->gm[original_index / GM_BLOCK_SIZE])
4171 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4173 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || lpmat)
4174 load_flags |= FT_LOAD_NO_BITMAP;
4176 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4179 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4180 LeaveCriticalSection( &freetype_cs );
4184 /* Scaling factor */
4185 if (font->aveWidth && font->potm)
4187 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11;
4188 widthRatio /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
4191 widthRatio = font->scale_y;
4193 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
4194 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
4196 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
4198 bbx = (right - left) >> 6;
4200 /* Scaling transform */
4201 if(font->aveWidth) {
4203 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4206 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4208 pFT_Matrix_Multiply(&scaleMat, &transMat);
4209 needsTransform = TRUE;
4212 /* Slant transform */
4213 if (font->fake_italic) {
4216 slantMat.xx = (1 << 16);
4217 slantMat.xy = ((1 << 16) >> 2);
4219 slantMat.yy = (1 << 16);
4220 pFT_Matrix_Multiply(&slantMat, &transMat);
4221 needsTransform = TRUE;
4224 /* Rotation transform */
4225 if(font->orientation && !tategaki) {
4226 FT_Matrix rotationMat;
4228 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
4229 pFT_Vector_Unit(&vecAngle, angle);
4230 rotationMat.xx = vecAngle.x;
4231 rotationMat.xy = -vecAngle.y;
4232 rotationMat.yx = -rotationMat.xy;
4233 rotationMat.yy = rotationMat.xx;
4235 pFT_Matrix_Multiply(&rotationMat, &transMat);
4236 needsTransform = TRUE;
4239 /* Extra transformation specified by caller */
4242 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4243 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
4244 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
4245 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4246 pFT_Matrix_Multiply(&extraMat, &transMat);
4247 needsTransform = TRUE;
4250 if(!needsTransform) {
4251 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4252 bottom = (ft_face->glyph->metrics.horiBearingY -
4253 ft_face->glyph->metrics.height) & -64;
4254 lpgm->gmCellIncX = adv;
4255 lpgm->gmCellIncY = 0;
4259 for(xc = 0; xc < 2; xc++) {
4260 for(yc = 0; yc < 2; yc++) {
4261 vec.x = (ft_face->glyph->metrics.horiBearingX +
4262 xc * ft_face->glyph->metrics.width);
4263 vec.y = ft_face->glyph->metrics.horiBearingY -
4264 yc * ft_face->glyph->metrics.height;
4265 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4266 pFT_Vector_Transform(&vec, &transMat);
4267 if(xc == 0 && yc == 0) {
4268 left = right = vec.x;
4269 top = bottom = vec.y;
4271 if(vec.x < left) left = vec.x;
4272 else if(vec.x > right) right = vec.x;
4273 if(vec.y < bottom) bottom = vec.y;
4274 else if(vec.y > top) top = vec.y;
4279 right = (right + 63) & -64;
4280 bottom = bottom & -64;
4281 top = (top + 63) & -64;
4283 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4284 vec.x = ft_face->glyph->metrics.horiAdvance;
4286 pFT_Vector_Transform(&vec, &transMat);
4287 lpgm->gmCellIncX = (vec.x+63) >> 6;
4288 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4290 lpgm->gmBlackBoxX = (right - left) >> 6;
4291 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4292 lpgm->gmptGlyphOrigin.x = left >> 6;
4293 lpgm->gmptGlyphOrigin.y = top >> 6;
4295 if(format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP)
4297 FONT_GM(font,original_index)->gm = *lpgm;
4298 FONT_GM(font,original_index)->adv = adv;
4299 FONT_GM(font,original_index)->lsb = lsb;
4300 FONT_GM(font,original_index)->bbx = bbx;
4301 FONT_GM(font,original_index)->init = TRUE;
4304 if(format == GGO_METRICS)
4306 LeaveCriticalSection( &freetype_cs );
4307 return 1; /* FIXME */
4310 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
4311 TRACE("loaded a bitmap\n");
4312 LeaveCriticalSection( &freetype_cs );
4318 width = lpgm->gmBlackBoxX;
4319 height = lpgm->gmBlackBoxY;
4320 pitch = ((width + 31) >> 5) << 2;
4321 needed = pitch * height;
4323 if(!buf || !buflen) break;
4325 switch(ft_face->glyph->format) {
4326 case ft_glyph_format_bitmap:
4328 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4329 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4330 INT h = ft_face->glyph->bitmap.rows;
4332 memcpy(dst, src, w);
4333 src += ft_face->glyph->bitmap.pitch;
4339 case ft_glyph_format_outline:
4340 ft_bitmap.width = width;
4341 ft_bitmap.rows = height;
4342 ft_bitmap.pitch = pitch;
4343 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4344 ft_bitmap.buffer = buf;
4346 if(needsTransform) {
4347 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4350 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4352 /* Note: FreeType will only set 'black' bits for us. */
4353 memset(buf, 0, needed);
4354 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4358 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4359 LeaveCriticalSection( &freetype_cs );
4364 case GGO_GRAY2_BITMAP:
4365 case GGO_GRAY4_BITMAP:
4366 case GGO_GRAY8_BITMAP:
4367 case WINE_GGO_GRAY16_BITMAP:
4369 unsigned int mult, row, col;
4372 width = lpgm->gmBlackBoxX;
4373 height = lpgm->gmBlackBoxY;
4374 pitch = (width + 3) / 4 * 4;
4375 needed = pitch * height;
4377 if(!buf || !buflen) break;
4379 switch(ft_face->glyph->format) {
4380 case ft_glyph_format_bitmap:
4382 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4383 INT h = ft_face->glyph->bitmap.rows;
4386 for(x = 0; x < pitch; x++)
4387 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4388 src += ft_face->glyph->bitmap.pitch;
4391 LeaveCriticalSection( &freetype_cs );
4394 case ft_glyph_format_outline:
4396 ft_bitmap.width = width;
4397 ft_bitmap.rows = height;
4398 ft_bitmap.pitch = pitch;
4399 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4400 ft_bitmap.buffer = buf;
4403 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4405 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4407 memset(ft_bitmap.buffer, 0, buflen);
4409 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4411 if(format == GGO_GRAY2_BITMAP)
4413 else if(format == GGO_GRAY4_BITMAP)
4415 else if(format == GGO_GRAY8_BITMAP)
4417 else /* format == WINE_GGO_GRAY16_BITMAP */
4419 LeaveCriticalSection( &freetype_cs );
4425 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4426 LeaveCriticalSection( &freetype_cs );
4431 for(row = 0; row < height; row++) {
4433 for(col = 0; col < width; col++, ptr++) {
4434 *ptr = (((int)*ptr) * mult + 128) / 256;
4443 int contour, point = 0, first_pt;
4444 FT_Outline *outline = &ft_face->glyph->outline;
4445 TTPOLYGONHEADER *pph;
4447 DWORD pph_start, cpfx, type;
4449 if(buflen == 0) buf = NULL;
4451 if (needsTransform && buf) {
4452 pFT_Outline_Transform(outline, &transMat);
4455 for(contour = 0; contour < outline->n_contours; contour++) {
4457 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4460 pph->dwType = TT_POLYGON_TYPE;
4461 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4463 needed += sizeof(*pph);
4465 while(point <= outline->contours[contour]) {
4466 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4467 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4468 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4472 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4475 } while(point <= outline->contours[contour] &&
4476 (outline->tags[point] & FT_Curve_Tag_On) ==
4477 (outline->tags[point-1] & FT_Curve_Tag_On));
4478 /* At the end of a contour Windows adds the start point, but
4480 if(point > outline->contours[contour] &&
4481 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4483 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4485 } else if(point <= outline->contours[contour] &&
4486 outline->tags[point] & FT_Curve_Tag_On) {
4487 /* add closing pt for bezier */
4489 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4497 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4500 pph->cb = needed - pph_start;
4506 /* Convert the quadratic Beziers to cubic Beziers.
4507 The parametric eqn for a cubic Bezier is, from PLRM:
4508 r(t) = at^3 + bt^2 + ct + r0
4509 with the control points:
4514 A quadratic Beizer has the form:
4515 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4517 So equating powers of t leads to:
4518 r1 = 2/3 p1 + 1/3 p0
4519 r2 = 2/3 p1 + 1/3 p2
4520 and of course r0 = p0, r3 = p2
4523 int contour, point = 0, first_pt;
4524 FT_Outline *outline = &ft_face->glyph->outline;
4525 TTPOLYGONHEADER *pph;
4527 DWORD pph_start, cpfx, type;
4528 FT_Vector cubic_control[4];
4529 if(buflen == 0) buf = NULL;
4531 if (needsTransform && buf) {
4532 pFT_Outline_Transform(outline, &transMat);
4535 for(contour = 0; contour < outline->n_contours; contour++) {
4537 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4540 pph->dwType = TT_POLYGON_TYPE;
4541 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4543 needed += sizeof(*pph);
4545 while(point <= outline->contours[contour]) {
4546 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4547 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4548 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4551 if(type == TT_PRIM_LINE) {
4553 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4557 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4560 /* FIXME: Possible optimization in endpoint calculation
4561 if there are two consecutive curves */
4562 cubic_control[0] = outline->points[point-1];
4563 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4564 cubic_control[0].x += outline->points[point].x + 1;
4565 cubic_control[0].y += outline->points[point].y + 1;
4566 cubic_control[0].x >>= 1;
4567 cubic_control[0].y >>= 1;
4569 if(point+1 > outline->contours[contour])
4570 cubic_control[3] = outline->points[first_pt];
4572 cubic_control[3] = outline->points[point+1];
4573 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4574 cubic_control[3].x += outline->points[point].x + 1;
4575 cubic_control[3].y += outline->points[point].y + 1;
4576 cubic_control[3].x >>= 1;
4577 cubic_control[3].y >>= 1;
4580 /* r1 = 1/3 p0 + 2/3 p1
4581 r2 = 1/3 p2 + 2/3 p1 */
4582 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4583 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4584 cubic_control[2] = cubic_control[1];
4585 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4586 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4587 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4588 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4590 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4591 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4592 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4597 } while(point <= outline->contours[contour] &&
4598 (outline->tags[point] & FT_Curve_Tag_On) ==
4599 (outline->tags[point-1] & FT_Curve_Tag_On));
4600 /* At the end of a contour Windows adds the start point,
4601 but only for Beziers and we've already done that.
4603 if(point <= outline->contours[contour] &&
4604 outline->tags[point] & FT_Curve_Tag_On) {
4605 /* This is the closing pt of a bezier, but we've already
4606 added it, so just inc point and carry on */
4613 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4616 pph->cb = needed - pph_start;
4622 FIXME("Unsupported format %d\n", format);
4623 LeaveCriticalSection( &freetype_cs );
4626 LeaveCriticalSection( &freetype_cs );
4630 static BOOL get_bitmap_text_metrics(GdiFont *font)
4632 FT_Face ft_face = font->ft_face;
4633 #ifdef HAVE_FREETYPE_FTWINFNT_H
4634 FT_WinFNT_HeaderRec winfnt_header;
4636 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4637 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4638 font->potm->otmSize = size;
4640 #define TM font->potm->otmTextMetrics
4641 #ifdef HAVE_FREETYPE_FTWINFNT_H
4642 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4644 TM.tmHeight = winfnt_header.pixel_height;
4645 TM.tmAscent = winfnt_header.ascent;
4646 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4647 TM.tmInternalLeading = winfnt_header.internal_leading;
4648 TM.tmExternalLeading = winfnt_header.external_leading;
4649 TM.tmAveCharWidth = winfnt_header.avg_width;
4650 TM.tmMaxCharWidth = winfnt_header.max_width;
4651 TM.tmWeight = winfnt_header.weight;
4653 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4654 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4655 TM.tmFirstChar = winfnt_header.first_char;
4656 TM.tmLastChar = winfnt_header.last_char;
4657 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4658 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4659 TM.tmItalic = winfnt_header.italic;
4660 TM.tmUnderlined = font->underline;
4661 TM.tmStruckOut = font->strikeout;
4662 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4663 TM.tmCharSet = winfnt_header.charset;
4668 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4669 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4670 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4671 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4672 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4673 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4674 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4675 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4677 TM.tmDigitizedAspectX = 96; /* FIXME */
4678 TM.tmDigitizedAspectY = 96; /* FIXME */
4680 TM.tmLastChar = 255;
4681 TM.tmDefaultChar = 32;
4682 TM.tmBreakChar = 32;
4683 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4684 TM.tmUnderlined = font->underline;
4685 TM.tmStruckOut = font->strikeout;
4686 /* NB inverted meaning of TMPF_FIXED_PITCH */
4687 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4688 TM.tmCharSet = font->charset;
4696 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
4702 scale_x = (float)font->aveWidth * font->font_desc.matrix.eM11;
4703 scale_x /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
4706 scale_x = font->scale_y;
4708 ptm->tmHeight = (float)ptm->tmHeight * font->scale_y;
4709 ptm->tmAscent = (float)ptm->tmAscent * font->scale_y;
4710 ptm->tmDescent = (float)ptm->tmDescent * font->scale_y;
4711 ptm->tmInternalLeading = (float)ptm->tmInternalLeading * font->scale_y;
4712 ptm->tmExternalLeading = (float)ptm->tmExternalLeading * font->scale_y;
4714 ptm->tmAveCharWidth = (float)ptm->tmAveCharWidth * scale_x;
4715 ptm->tmMaxCharWidth = (float)ptm->tmMaxCharWidth * scale_x;
4718 /*************************************************************
4719 * WineEngGetTextMetrics
4722 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4724 EnterCriticalSection( &freetype_cs );
4726 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
4727 if(!get_bitmap_text_metrics(font))
4729 LeaveCriticalSection( &freetype_cs );
4735 LeaveCriticalSection( &freetype_cs );
4738 *ptm = font->potm->otmTextMetrics;
4739 scale_font_metrics(font, ptm);
4740 LeaveCriticalSection( &freetype_cs );
4745 /*************************************************************
4746 * WineEngGetOutlineTextMetrics
4749 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4750 OUTLINETEXTMETRICW *potm)
4752 FT_Face ft_face = font->ft_face;
4753 UINT needed, lenfam, lensty, ret;
4755 TT_HoriHeader *pHori;
4756 TT_Postscript *pPost;
4757 FT_Fixed x_scale, y_scale;
4758 WCHAR *family_nameW, *style_nameW;
4759 static const WCHAR spaceW[] = {' ', '\0'};
4761 INT ascent, descent;
4763 TRACE("font=%p\n", font);
4765 if(!FT_IS_SCALABLE(ft_face))
4768 EnterCriticalSection( &freetype_cs );
4771 if(cbSize >= font->potm->otmSize)
4773 memcpy(potm, font->potm, font->potm->otmSize);
4774 scale_font_metrics(font, &potm->otmTextMetrics);
4776 LeaveCriticalSection( &freetype_cs );
4777 return font->potm->otmSize;
4781 needed = sizeof(*potm);
4783 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
4784 family_nameW = strdupW(font->name);
4786 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
4788 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
4789 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
4790 style_nameW, lensty/sizeof(WCHAR));
4792 /* These names should be read from the TT name table */
4794 /* length of otmpFamilyName */
4797 /* length of otmpFaceName */
4798 if(!strcasecmp(ft_face->style_name, "regular")) {
4799 needed += lenfam; /* just the family name */
4801 needed += lenfam + lensty; /* family + " " + style */
4804 /* length of otmpStyleName */
4807 /* length of otmpFullName */
4808 needed += lenfam + lensty;
4811 x_scale = ft_face->size->metrics.x_scale;
4812 y_scale = ft_face->size->metrics.y_scale;
4814 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4816 FIXME("Can't find OS/2 table - not TT font?\n");
4821 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4823 FIXME("Can't find HHEA table - not TT font?\n");
4828 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
4830 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",
4831 pOS2->usWinAscent, pOS2->usWinDescent,
4832 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
4833 ft_face->ascender, ft_face->descender, ft_face->height,
4834 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
4835 ft_face->bbox.yMax, ft_face->bbox.yMin);
4837 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
4838 font->potm->otmSize = needed;
4840 #define TM font->potm->otmTextMetrics
4842 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
4843 ascent = pHori->Ascender;
4844 descent = -pHori->Descender;
4846 ascent = pOS2->usWinAscent;
4847 descent = pOS2->usWinDescent;
4851 TM.tmAscent = font->yMax;
4852 TM.tmDescent = -font->yMin;
4853 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
4855 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
4856 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
4857 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
4858 - ft_face->units_per_EM, y_scale) + 32) >> 6;
4861 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4864 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4866 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
4867 ((ascent + descent) -
4868 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
4870 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
4871 if (TM.tmAveCharWidth == 0) {
4872 TM.tmAveCharWidth = 1;
4874 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
4875 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
4877 TM.tmDigitizedAspectX = 300;
4878 TM.tmDigitizedAspectY = 300;
4879 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4880 * symbol range to 0 - f0ff
4882 if (font->charset == SYMBOL_CHARSET)
4885 TM.tmFirstChar = pOS2->usFirstCharIndex;
4886 TM.tmLastChar = pOS2->usLastCharIndex;
4887 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4888 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
4889 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4890 TM.tmUnderlined = font->underline;
4891 TM.tmStruckOut = font->strikeout;
4893 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4894 if(!FT_IS_FIXED_WIDTH(ft_face) &&
4895 (pOS2->version == 0xFFFFU ||
4896 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4897 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
4899 TM.tmPitchAndFamily = 0;
4901 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
4902 case PAN_FAMILY_SCRIPT:
4903 TM.tmPitchAndFamily |= FF_SCRIPT;
4905 case PAN_FAMILY_DECORATIVE:
4906 case PAN_FAMILY_PICTORIAL:
4907 TM.tmPitchAndFamily |= FF_DECORATIVE;
4909 case PAN_FAMILY_TEXT_DISPLAY:
4910 if(TM.tmPitchAndFamily == 0) /* fixed */
4911 TM.tmPitchAndFamily = FF_MODERN;
4913 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
4914 case PAN_SERIF_NORMAL_SANS:
4915 case PAN_SERIF_OBTUSE_SANS:
4916 case PAN_SERIF_PERP_SANS:
4917 TM.tmPitchAndFamily |= FF_SWISS;
4920 TM.tmPitchAndFamily |= FF_ROMAN;
4925 TM.tmPitchAndFamily |= FF_DONTCARE;
4928 if(FT_IS_SCALABLE(ft_face))
4929 TM.tmPitchAndFamily |= TMPF_VECTOR;
4931 if(FT_IS_SFNT(ft_face))
4933 if (font->ntmFlags & NTM_PS_OPENTYPE)
4934 TM.tmPitchAndFamily |= TMPF_DEVICE;
4936 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
4939 TM.tmCharSet = font->charset;
4942 font->potm->otmFiller = 0;
4943 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
4944 font->potm->otmfsSelection = pOS2->fsSelection;
4945 font->potm->otmfsType = pOS2->fsType;
4946 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
4947 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
4948 font->potm->otmItalicAngle = 0; /* POST table */
4949 font->potm->otmEMSquare = ft_face->units_per_EM;
4950 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
4951 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4952 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4953 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
4954 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4955 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
4956 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
4957 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
4958 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4959 font->potm->otmMacAscent = 0; /* where do these come from ? */
4960 font->potm->otmMacDescent = 0;
4961 font->potm->otmMacLineGap = 0;
4962 font->potm->otmusMinimumPPEM = 0; /* TT Header */
4963 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
4964 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
4965 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
4966 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
4967 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
4968 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
4969 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
4970 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
4971 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
4972 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4974 font->potm->otmsUnderscoreSize = 0;
4975 font->potm->otmsUnderscorePosition = 0;
4977 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
4978 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
4981 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4982 cp = (char*)font->potm + sizeof(*font->potm);
4983 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4984 strcpyW((WCHAR*)cp, family_nameW);
4986 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4987 strcpyW((WCHAR*)cp, style_nameW);
4989 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4990 strcpyW((WCHAR*)cp, family_nameW);
4991 if(strcasecmp(ft_face->style_name, "regular")) {
4992 strcatW((WCHAR*)cp, spaceW);
4993 strcatW((WCHAR*)cp, style_nameW);
4994 cp += lenfam + lensty;
4997 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
4998 strcpyW((WCHAR*)cp, family_nameW);
4999 strcatW((WCHAR*)cp, spaceW);
5000 strcatW((WCHAR*)cp, style_nameW);
5003 if(potm && needed <= cbSize)
5005 memcpy(potm, font->potm, font->potm->otmSize);
5006 scale_font_metrics(font, &potm->otmTextMetrics);
5010 HeapFree(GetProcessHeap(), 0, style_nameW);
5011 HeapFree(GetProcessHeap(), 0, family_nameW);
5013 LeaveCriticalSection( &freetype_cs );
5017 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5019 HFONTLIST *hfontlist;
5020 child->font = alloc_font();
5021 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5022 if(!child->font->ft_face)
5024 free_font(child->font);
5029 child->font->ntmFlags = child->face->ntmFlags;
5030 child->font->orientation = font->orientation;
5031 child->font->scale_y = font->scale_y;
5032 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5033 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5034 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5035 child->font->base_font = font;
5036 list_add_head(&child_font_list, &child->font->entry);
5037 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5041 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5044 CHILD_FONT *child_font;
5047 font = font->base_font;
5049 *linked_font = font;
5051 if((*glyph = get_glyph_index(font, c)))
5054 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5056 if(!child_font->font)
5057 if(!load_child_font(font, child_font))
5060 if(!child_font->font->ft_face)
5062 g = get_glyph_index(child_font->font, c);
5066 *linked_font = child_font->font;
5073 /*************************************************************
5074 * WineEngGetCharWidth
5077 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5082 FT_UInt glyph_index;
5083 GdiFont *linked_font;
5085 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5087 EnterCriticalSection( &freetype_cs );
5088 for(c = firstChar; c <= lastChar; c++) {
5089 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5090 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5091 &gm, 0, NULL, NULL);
5092 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5094 LeaveCriticalSection( &freetype_cs );
5098 /*************************************************************
5099 * WineEngGetCharABCWidths
5102 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5107 FT_UInt glyph_index;
5108 GdiFont *linked_font;
5110 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5112 if(!FT_IS_SCALABLE(font->ft_face))
5115 EnterCriticalSection( &freetype_cs );
5117 for(c = firstChar; c <= lastChar; c++) {
5118 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5119 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5120 &gm, 0, NULL, NULL);
5121 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5122 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5123 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5124 FONT_GM(linked_font,glyph_index)->bbx;
5126 LeaveCriticalSection( &freetype_cs );
5130 /*************************************************************
5131 * WineEngGetCharABCWidthsI
5134 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5139 FT_UInt glyph_index;
5140 GdiFont *linked_font;
5142 if(!FT_HAS_HORIZONTAL(font->ft_face))
5145 EnterCriticalSection( &freetype_cs );
5147 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5149 for(c = firstChar; c < firstChar+count; c++) {
5150 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5151 &gm, 0, NULL, NULL);
5152 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5153 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5154 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5155 - FONT_GM(linked_font,c)->bbx;
5158 for(c = 0; c < count; c++) {
5159 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5160 &gm, 0, NULL, NULL);
5161 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5162 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5163 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5164 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5167 LeaveCriticalSection( &freetype_cs );
5171 /*************************************************************
5172 * WineEngGetTextExtentExPoint
5175 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5176 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5182 FT_UInt glyph_index;
5183 GdiFont *linked_font;
5185 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5188 EnterCriticalSection( &freetype_cs );
5191 WineEngGetTextMetrics(font, &tm);
5192 size->cy = tm.tmHeight;
5194 for(idx = 0; idx < count; idx++) {
5195 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5196 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5197 &gm, 0, NULL, NULL);
5198 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5200 if (! pnfit || ext <= max_ext) {
5210 LeaveCriticalSection( &freetype_cs );
5211 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5215 /*************************************************************
5216 * WineEngGetTextExtentExPointI
5219 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5220 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5227 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5229 EnterCriticalSection( &freetype_cs );
5232 WineEngGetTextMetrics(font, &tm);
5233 size->cy = tm.tmHeight;
5235 for(idx = 0; idx < count; idx++) {
5236 WineEngGetGlyphOutline(font, indices[idx],
5237 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
5239 size->cx += FONT_GM(font,indices[idx])->adv;
5241 if (! pnfit || ext <= max_ext) {
5251 LeaveCriticalSection( &freetype_cs );
5252 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5256 /*************************************************************
5257 * WineEngGetFontData
5260 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5263 FT_Face ft_face = font->ft_face;
5267 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5268 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
5269 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
5271 if(!FT_IS_SFNT(ft_face))
5279 if(table) { /* MS tags differ in endianness from FT ones */
5280 table = table >> 24 | table << 24 |
5281 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
5284 /* make sure value of len is the value freetype says it needs */
5287 FT_ULong needed = 0;
5288 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
5289 if( !err && needed < len) len = needed;
5291 err = load_sfnt_table(ft_face, table, offset, buf, &len);
5294 TRACE("Can't find table %c%c%c%c\n",
5295 /* bytes were reversed */
5296 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
5297 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
5303 /*************************************************************
5304 * WineEngGetTextFace
5307 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5310 lstrcpynW(str, font->name, count);
5311 return strlenW(font->name);
5313 return strlenW(font->name) + 1;
5316 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5318 if (fs) *fs = font->fs;
5319 return font->charset;
5322 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5324 GdiFont *font = dc->gdiFont, *linked_font;
5325 struct list *first_hfont;
5328 EnterCriticalSection( &freetype_cs );
5329 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
5330 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
5331 if(font == linked_font)
5332 *new_hfont = dc->hFont;
5335 first_hfont = list_head(&linked_font->hfontlist);
5336 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
5338 LeaveCriticalSection( &freetype_cs );
5342 /* Retrieve a list of supported Unicode ranges for a given font.
5343 * Can be called with NULL gs to calculate the buffer size. Returns
5344 * the number of ranges found.
5346 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
5348 DWORD num_ranges = 0;
5350 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5353 FT_ULong char_code, char_code_prev;
5356 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
5358 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5359 face->num_glyphs, glyph_code, char_code);
5361 if (!glyph_code) return 0;
5365 gs->ranges[0].wcLow = (USHORT)char_code;
5366 gs->ranges[0].cGlyphs = 0;
5367 gs->cGlyphsSupported = 0;
5373 if (char_code < char_code_prev)
5375 ERR("expected increasing char code from FT_Get_Next_Char\n");
5378 if (char_code - char_code_prev > 1)
5383 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5384 gs->ranges[num_ranges - 1].cGlyphs = 1;
5385 gs->cGlyphsSupported++;
5390 gs->ranges[num_ranges - 1].cGlyphs++;
5391 gs->cGlyphsSupported++;
5393 char_code_prev = char_code;
5394 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5398 FIXME("encoding %u not supported\n", face->charmap->encoding);
5403 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5406 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
5408 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5411 glyphset->cbThis = size;
5412 glyphset->cRanges = num_ranges;
5417 /*************************************************************
5420 BOOL WineEngFontIsLinked(GdiFont *font)
5423 EnterCriticalSection( &freetype_cs );
5424 ret = !list_empty(&font->child_fonts);
5425 LeaveCriticalSection( &freetype_cs );
5429 static BOOL is_hinting_enabled(void)
5431 /* Use the >= 2.2.0 function if available */
5432 if(pFT_Get_TrueType_Engine_Type)
5434 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
5435 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
5437 #ifdef FT_DRIVER_HAS_HINTER
5442 /* otherwise if we've been compiled with < 2.2.0 headers
5443 use the internal macro */
5444 mod = pFT_Get_Module(library, "truetype");
5445 if(mod && FT_DRIVER_HAS_HINTER(mod))
5453 /*************************************************************************
5454 * GetRasterizerCaps (GDI32.@)
5456 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5458 static int hinting = -1;
5462 hinting = is_hinting_enabled();
5463 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
5466 lprs->nSize = sizeof(RASTERIZER_STATUS);
5467 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
5468 lprs->nLanguageID = 0;
5472 /*************************************************************************
5473 * Kerning support for TrueType fonts
5475 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5477 struct TT_kern_table
5483 struct TT_kern_subtable
5492 USHORT horizontal : 1;
5494 USHORT cross_stream: 1;
5495 USHORT override : 1;
5496 USHORT reserved1 : 4;
5502 struct TT_format0_kern_subtable
5506 USHORT entrySelector;
5517 static DWORD parse_format0_kern_subtable(GdiFont *font,
5518 const struct TT_format0_kern_subtable *tt_f0_ks,
5519 const USHORT *glyph_to_char,
5520 KERNINGPAIR *kern_pair, DWORD cPairs)
5523 const struct TT_kern_pair *tt_kern_pair;
5525 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
5527 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
5529 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5530 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
5531 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
5533 if (!kern_pair || !cPairs)
5536 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
5538 nPairs = min(nPairs, cPairs);
5540 for (i = 0; i < nPairs; i++)
5542 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
5543 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
5544 /* this algorithm appears to better match what Windows does */
5545 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
5546 if (kern_pair->iKernAmount < 0)
5548 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
5549 kern_pair->iKernAmount -= font->ppem;
5551 else if (kern_pair->iKernAmount > 0)
5553 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
5554 kern_pair->iKernAmount += font->ppem;
5556 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
5558 TRACE("left %u right %u value %d\n",
5559 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
5563 TRACE("copied %u entries\n", nPairs);
5567 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5571 const struct TT_kern_table *tt_kern_table;
5572 const struct TT_kern_subtable *tt_kern_subtable;
5574 USHORT *glyph_to_char;
5576 EnterCriticalSection( &freetype_cs );
5577 if (font->total_kern_pairs != (DWORD)-1)
5579 if (cPairs && kern_pair)
5581 cPairs = min(cPairs, font->total_kern_pairs);
5582 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5583 LeaveCriticalSection( &freetype_cs );
5586 LeaveCriticalSection( &freetype_cs );
5587 return font->total_kern_pairs;
5590 font->total_kern_pairs = 0;
5592 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5594 if (length == GDI_ERROR)
5596 TRACE("no kerning data in the font\n");
5597 LeaveCriticalSection( &freetype_cs );
5601 buf = HeapAlloc(GetProcessHeap(), 0, length);
5604 WARN("Out of memory\n");
5605 LeaveCriticalSection( &freetype_cs );
5609 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5611 /* build a glyph index to char code map */
5612 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5615 WARN("Out of memory allocating a glyph index to char code map\n");
5616 HeapFree(GetProcessHeap(), 0, buf);
5617 LeaveCriticalSection( &freetype_cs );
5621 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5627 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5629 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5630 font->ft_face->num_glyphs, glyph_code, char_code);
5634 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5636 /* FIXME: This doesn't match what Windows does: it does some fancy
5637 * things with duplicate glyph index to char code mappings, while
5638 * we just avoid overriding existing entries.
5640 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5641 glyph_to_char[glyph_code] = (USHORT)char_code;
5643 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5650 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5651 for (n = 0; n <= 65535; n++)
5652 glyph_to_char[n] = (USHORT)n;
5655 tt_kern_table = buf;
5656 nTables = GET_BE_WORD(tt_kern_table->nTables);
5657 TRACE("version %u, nTables %u\n",
5658 GET_BE_WORD(tt_kern_table->version), nTables);
5660 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5662 for (i = 0; i < nTables; i++)
5664 struct TT_kern_subtable tt_kern_subtable_copy;
5666 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5667 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5668 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5670 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5671 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
5672 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
5674 /* According to the TrueType specification this is the only format
5675 * that will be properly interpreted by Windows and OS/2
5677 if (tt_kern_subtable_copy.coverage.bits.format == 0)
5679 DWORD new_chunk, old_total = font->total_kern_pairs;
5681 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5682 glyph_to_char, NULL, 0);
5683 font->total_kern_pairs += new_chunk;
5685 if (!font->kern_pairs)
5686 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
5687 font->total_kern_pairs * sizeof(*font->kern_pairs));
5689 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
5690 font->total_kern_pairs * sizeof(*font->kern_pairs));
5692 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5693 glyph_to_char, font->kern_pairs + old_total, new_chunk);
5696 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
5698 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
5701 HeapFree(GetProcessHeap(), 0, glyph_to_char);
5702 HeapFree(GetProcessHeap(), 0, buf);
5704 if (cPairs && kern_pair)
5706 cPairs = min(cPairs, font->total_kern_pairs);
5707 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5708 LeaveCriticalSection( &freetype_cs );
5711 LeaveCriticalSection( &freetype_cs );
5712 return font->total_kern_pairs;
5715 #else /* HAVE_FREETYPE */
5717 /*************************************************************************/
5719 BOOL WineEngInit(void)
5723 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
5727 BOOL WineEngDestroyFontInstance(HFONT hfont)
5732 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
5737 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
5738 LPWORD pgi, DWORD flags)
5743 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
5744 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5747 ERR("called but we don't have FreeType\n");
5751 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5753 ERR("called but we don't have FreeType\n");
5757 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5758 OUTLINETEXTMETRICW *potm)
5760 ERR("called but we don't have FreeType\n");
5764 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5767 ERR("called but we don't have FreeType\n");
5771 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5774 ERR("called but we don't have FreeType\n");
5778 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5781 ERR("called but we don't have FreeType\n");
5785 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5786 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5788 ERR("called but we don't have FreeType\n");
5792 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5793 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5795 ERR("called but we don't have FreeType\n");
5799 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5802 ERR("called but we don't have FreeType\n");
5806 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5808 ERR("called but we don't have FreeType\n");
5812 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5818 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5824 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
5830 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5833 return DEFAULT_CHARSET;
5836 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5841 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5843 FIXME("(%p, %p): stub\n", font, glyphset);
5847 BOOL WineEngFontIsLinked(GdiFont *font)
5852 /*************************************************************************
5853 * GetRasterizerCaps (GDI32.@)
5855 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5857 lprs->nSize = sizeof(RASTERIZER_STATUS);
5859 lprs->nLanguageID = 0;
5863 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5865 ERR("called but we don't have FreeType\n");
5869 #endif /* HAVE_FREETYPE */