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;
1119 static inline int TestStyles(DWORD flags, DWORD styles)
1121 return (flags & styles) == styles;
1124 static int StyleOrdering(Face *face)
1126 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1128 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1130 if (TestStyles(face->ntmFlags, NTM_BOLD))
1132 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1135 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1136 debugstr_w(face->family->FamilyName),
1137 debugstr_w(face->StyleName),
1143 /* Add a style of face to a font family using an ordering of the list such
1144 that regular fonts come before bold and italic, and single styles come
1145 before compound styles. */
1146 static void AddFaceToFamily(Face *face, Family *family)
1150 LIST_FOR_EACH( entry, &family->faces )
1152 Face *ent = LIST_ENTRY(entry, Face, entry);
1153 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1155 list_add_before( entry, &face->entry );
1158 #define ADDFONT_EXTERNAL_FONT 0x01
1159 #define ADDFONT_FORCE_BITMAP 0x02
1160 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1164 TT_Header *pHeader = NULL;
1165 WCHAR *english_family, *localised_family, *StyleW;
1169 struct list *family_elem_ptr, *face_elem_ptr;
1171 FT_Long face_index = 0, num_faces;
1172 #ifdef HAVE_FREETYPE_FTWINFNT_H
1173 FT_WinFNT_HeaderRec winfnt_header;
1175 int i, bitmap_num, internal_leading;
1178 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1179 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1181 #ifdef HAVE_CARBON_CARBON_H
1182 if(file && !fake_family)
1184 char **mac_list = expand_mac_font(file);
1187 BOOL had_one = FALSE;
1189 for(cursor = mac_list; *cursor; cursor++)
1192 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1193 HeapFree(GetProcessHeap(), 0, *cursor);
1195 HeapFree(GetProcessHeap(), 0, mac_list);
1200 #endif /* HAVE_CARBON_CARBON_H */
1203 char *family_name = fake_family;
1207 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1208 err = pFT_New_Face(library, file, face_index, &ft_face);
1211 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1212 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1216 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1220 if(!FT_IS_SFNT(ft_face) && (FT_IS_SCALABLE(ft_face) || !(flags & ADDFONT_FORCE_BITMAP))) { /* for now we'll accept TT/OT or bitmap fonts*/
1221 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1222 pFT_Done_Face(ft_face);
1226 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1227 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1228 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1229 pFT_Done_Face(ft_face);
1233 if(FT_IS_SFNT(ft_face))
1235 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1236 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1237 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1239 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1240 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1241 pFT_Done_Face(ft_face);
1245 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1246 we don't want to load these. */
1247 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1251 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1253 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1254 pFT_Done_Face(ft_face);
1260 if(!ft_face->family_name || !ft_face->style_name) {
1261 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1262 pFT_Done_Face(ft_face);
1266 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1268 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1269 pFT_Done_Face(ft_face);
1275 localised_family = get_familyname(ft_face);
1276 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1278 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1279 HeapFree(GetProcessHeap(), 0, localised_family);
1280 num_faces = ft_face->num_faces;
1281 pFT_Done_Face(ft_face);
1284 HeapFree(GetProcessHeap(), 0, localised_family);
1288 family_name = ft_face->family_name;
1292 My_FT_Bitmap_Size *size = NULL;
1295 if(!FT_IS_SCALABLE(ft_face))
1296 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1298 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1299 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1300 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1302 localised_family = NULL;
1304 localised_family = get_familyname(ft_face);
1305 if(localised_family && !strcmpW(localised_family, english_family)) {
1306 HeapFree(GetProcessHeap(), 0, localised_family);
1307 localised_family = NULL;
1312 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1313 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1314 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1319 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1320 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1321 list_init(&family->faces);
1322 list_add_tail(&font_list, &family->entry);
1324 if(localised_family) {
1325 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1326 subst->from.name = strdupW(english_family);
1327 subst->from.charset = -1;
1328 subst->to.name = strdupW(localised_family);
1329 subst->to.charset = -1;
1330 add_font_subst(&font_subst_list, subst, 0);
1333 HeapFree(GetProcessHeap(), 0, localised_family);
1334 HeapFree(GetProcessHeap(), 0, english_family);
1336 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1337 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1338 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1340 internal_leading = 0;
1341 memset(&fs, 0, sizeof(fs));
1343 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1345 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1346 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1347 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1348 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1349 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1350 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1351 if(pOS2->version == 0) {
1354 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1355 fs.fsCsb[0] |= FS_LATIN1;
1357 fs.fsCsb[0] |= FS_SYMBOL;
1360 #ifdef HAVE_FREETYPE_FTWINFNT_H
1361 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1363 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1364 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1365 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1367 internal_leading = winfnt_header.internal_leading;
1371 face_elem_ptr = list_head(&family->faces);
1372 while(face_elem_ptr) {
1373 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1374 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1375 if(!strcmpW(face->StyleName, StyleW) &&
1376 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1377 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1378 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1379 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1382 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1383 HeapFree(GetProcessHeap(), 0, StyleW);
1384 pFT_Done_Face(ft_face);
1387 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1388 TRACE("Original font is newer so skipping this one\n");
1389 HeapFree(GetProcessHeap(), 0, StyleW);
1390 pFT_Done_Face(ft_face);
1393 TRACE("Replacing original with this one\n");
1394 list_remove(&face->entry);
1395 HeapFree(GetProcessHeap(), 0, face->file);
1396 HeapFree(GetProcessHeap(), 0, face->StyleName);
1397 HeapFree(GetProcessHeap(), 0, face);
1402 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1403 face->cached_enum_data = NULL;
1404 face->StyleName = StyleW;
1407 face->file = strdupA(file);
1408 face->font_data_ptr = NULL;
1409 face->font_data_size = 0;
1414 face->font_data_ptr = font_data_ptr;
1415 face->font_data_size = font_data_size;
1417 face->face_index = face_index;
1419 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1420 face->ntmFlags |= NTM_ITALIC;
1421 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1422 face->ntmFlags |= NTM_BOLD;
1423 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1424 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1425 face->family = family;
1426 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1428 memset(&face->fs_links, 0, sizeof(face->fs_links));
1430 if(FT_IS_SCALABLE(ft_face)) {
1431 memset(&face->size, 0, sizeof(face->size));
1432 face->scalable = TRUE;
1434 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1435 size->height, size->width, size->size >> 6,
1436 size->x_ppem >> 6, size->y_ppem >> 6);
1437 face->size.height = size->height;
1438 face->size.width = size->width;
1439 face->size.size = size->size;
1440 face->size.x_ppem = size->x_ppem;
1441 face->size.y_ppem = size->y_ppem;
1442 face->size.internal_leading = internal_leading;
1443 face->scalable = FALSE;
1446 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1448 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1450 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1451 face->ntmFlags |= NTM_PS_OPENTYPE;
1454 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1455 face->fs.fsCsb[0], face->fs.fsCsb[1],
1456 face->fs.fsUsb[0], face->fs.fsUsb[1],
1457 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1460 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1461 for(i = 0; i < ft_face->num_charmaps; i++) {
1462 switch(ft_face->charmaps[i]->encoding) {
1463 case FT_ENCODING_UNICODE:
1464 case FT_ENCODING_APPLE_ROMAN:
1465 face->fs.fsCsb[0] |= FS_LATIN1;
1467 case FT_ENCODING_MS_SYMBOL:
1468 face->fs.fsCsb[0] |= FS_SYMBOL;
1476 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1477 have_installed_roman_font = TRUE;
1479 AddFaceToFamily(face, family);
1481 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1483 num_faces = ft_face->num_faces;
1484 pFT_Done_Face(ft_face);
1485 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1486 debugstr_w(StyleW));
1487 } while(num_faces > ++face_index);
1491 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1493 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1496 static void DumpFontList(void)
1500 struct list *family_elem_ptr, *face_elem_ptr;
1502 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1503 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1504 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1505 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1506 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1507 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1509 TRACE(" %d", face->size.height);
1516 /***********************************************************
1517 * The replacement list is a way to map an entire font
1518 * family onto another family. For example adding
1520 * [HKCU\Software\Wine\Fonts\Replacements]
1521 * "Wingdings"="Winedings"
1523 * would enumerate the Winedings font both as Winedings and
1524 * Wingdings. However if a real Wingdings font is present the
1525 * replacement does not take place.
1528 static void LoadReplaceList(void)
1531 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1536 struct list *family_elem_ptr, *face_elem_ptr;
1539 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1540 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1542 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1543 &valuelen, &datalen, NULL, NULL);
1545 valuelen++; /* returned value doesn't include room for '\0' */
1546 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1547 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1551 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1552 &dlen) == ERROR_SUCCESS) {
1553 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1554 /* "NewName"="Oldname" */
1555 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1557 /* Find the old family and hence all of the font files
1559 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1560 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1561 if(!strcmpiW(family->FamilyName, data)) {
1562 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1563 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1564 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1565 debugstr_w(face->StyleName), familyA);
1566 /* Now add a new entry with the new family name */
1567 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1572 /* reset dlen and vlen */
1576 HeapFree(GetProcessHeap(), 0, data);
1577 HeapFree(GetProcessHeap(), 0, value);
1582 /*************************************************************
1585 static BOOL init_system_links(void)
1587 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1588 'W','i','n','d','o','w','s',' ','N','T','\\',
1589 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1590 'S','y','s','t','e','m','L','i','n','k',0};
1593 DWORD type, max_val, max_data, val_len, data_len, index;
1594 WCHAR *value, *data;
1595 WCHAR *entry, *next;
1596 SYSTEM_LINKS *font_link, *system_font_link;
1597 CHILD_FONT *child_font;
1598 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1599 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1600 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1606 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1608 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1609 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1610 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1611 val_len = max_val + 1;
1612 data_len = max_data;
1614 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1616 TRACE("%s:\n", debugstr_w(value));
1618 memset(&fs, 0, sizeof(fs));
1619 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1620 psub = get_font_subst(&font_subst_list, value, -1);
1621 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1622 list_init(&font_link->links);
1623 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1626 CHILD_FONT *child_font;
1628 TRACE("\t%s\n", debugstr_w(entry));
1630 next = entry + strlenW(entry) + 1;
1632 face_name = strchrW(entry, ',');
1636 while(isspaceW(*face_name))
1639 psub = get_font_subst(&font_subst_list, face_name, -1);
1641 face_name = psub->to.name;
1643 face = find_face_from_filename(entry, face_name);
1646 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1650 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1651 child_font->face = face;
1652 child_font->font = NULL;
1653 fs.fsCsb[0] |= face->fs.fsCsb[0];
1654 fs.fsCsb[1] |= face->fs.fsCsb[1];
1655 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1656 list_add_tail(&font_link->links, &child_font->entry);
1658 family = find_family_from_name(font_link->font_name);
1661 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1663 face->fs_links = fs;
1666 list_add_tail(&system_links, &font_link->entry);
1667 val_len = max_val + 1;
1668 data_len = max_data;
1671 HeapFree(GetProcessHeap(), 0, value);
1672 HeapFree(GetProcessHeap(), 0, data);
1676 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1679 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1680 system_font_link->font_name = strdupW(System);
1681 list_init(&system_font_link->links);
1683 face = find_face_from_filename(tahoma_ttf, Tahoma);
1686 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1687 child_font->face = face;
1688 child_font->font = NULL;
1689 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1690 list_add_tail(&system_font_link->links, &child_font->entry);
1692 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1694 if(!strcmpiW(font_link->font_name, Tahoma))
1696 CHILD_FONT *font_link_entry;
1697 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1699 CHILD_FONT *new_child;
1700 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1701 new_child->face = font_link_entry->face;
1702 new_child->font = NULL;
1703 list_add_tail(&system_font_link->links, &new_child->entry);
1708 list_add_tail(&system_links, &system_font_link->entry);
1712 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1715 struct dirent *dent;
1716 char path[MAX_PATH];
1718 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1720 dir = opendir(dirname);
1722 WARN("Can't open directory %s\n", debugstr_a(dirname));
1725 while((dent = readdir(dir)) != NULL) {
1726 struct stat statbuf;
1728 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1731 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1733 sprintf(path, "%s/%s", dirname, dent->d_name);
1735 if(stat(path, &statbuf) == -1)
1737 WARN("Can't stat %s\n", debugstr_a(path));
1740 if(S_ISDIR(statbuf.st_mode))
1741 ReadFontDir(path, external_fonts);
1743 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1749 static void load_fontconfig_fonts(void)
1751 #ifdef SONAME_LIBFONTCONFIG
1752 void *fc_handle = NULL;
1761 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1763 TRACE("Wine cannot find the fontconfig library (%s).\n",
1764 SONAME_LIBFONTCONFIG);
1767 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1768 LOAD_FUNCPTR(FcConfigGetCurrent);
1769 LOAD_FUNCPTR(FcFontList);
1770 LOAD_FUNCPTR(FcFontSetDestroy);
1771 LOAD_FUNCPTR(FcInit);
1772 LOAD_FUNCPTR(FcObjectSetAdd);
1773 LOAD_FUNCPTR(FcObjectSetCreate);
1774 LOAD_FUNCPTR(FcObjectSetDestroy);
1775 LOAD_FUNCPTR(FcPatternCreate);
1776 LOAD_FUNCPTR(FcPatternDestroy);
1777 LOAD_FUNCPTR(FcPatternGetBool);
1778 LOAD_FUNCPTR(FcPatternGetString);
1781 if(!pFcInit()) return;
1783 config = pFcConfigGetCurrent();
1784 pat = pFcPatternCreate();
1785 os = pFcObjectSetCreate();
1786 pFcObjectSetAdd(os, FC_FILE);
1787 pFcObjectSetAdd(os, FC_SCALABLE);
1788 fontset = pFcFontList(config, pat, os);
1789 if(!fontset) return;
1790 for(i = 0; i < fontset->nfont; i++) {
1793 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1795 TRACE("fontconfig: %s\n", file);
1797 /* We're just interested in OT/TT fonts for now, so this hack just
1798 picks up the scalable fonts without extensions .pf[ab] to save time
1799 loading every other font */
1801 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1803 TRACE("not scalable\n");
1807 len = strlen( file );
1808 if(len < 4) continue;
1809 ext = &file[ len - 3 ];
1810 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1811 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1813 pFcFontSetDestroy(fontset);
1814 pFcObjectSetDestroy(os);
1815 pFcPatternDestroy(pat);
1821 static BOOL load_font_from_data_dir(LPCWSTR file)
1824 const char *data_dir = wine_get_data_dir();
1826 if (!data_dir) data_dir = wine_get_build_dir();
1833 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1835 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1837 strcpy(unix_name, data_dir);
1838 strcat(unix_name, "/fonts/");
1840 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1842 EnterCriticalSection( &freetype_cs );
1843 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1844 LeaveCriticalSection( &freetype_cs );
1845 HeapFree(GetProcessHeap(), 0, unix_name);
1850 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1852 static const WCHAR slashW[] = {'\\','\0'};
1854 WCHAR windowsdir[MAX_PATH];
1857 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1858 strcatW(windowsdir, fontsW);
1859 strcatW(windowsdir, slashW);
1860 strcatW(windowsdir, file);
1861 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1862 EnterCriticalSection( &freetype_cs );
1863 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1864 LeaveCriticalSection( &freetype_cs );
1865 HeapFree(GetProcessHeap(), 0, unixname);
1870 static void load_system_fonts(void)
1873 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1874 const WCHAR * const *value;
1876 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1879 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1880 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1881 strcatW(windowsdir, fontsW);
1882 for(value = SystemFontValues; *value; value++) {
1883 dlen = sizeof(data);
1884 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1888 sprintfW(pathW, fmtW, windowsdir, data);
1889 if((unixname = wine_get_unix_file_name(pathW))) {
1890 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1891 HeapFree(GetProcessHeap(), 0, unixname);
1894 load_font_from_data_dir(data);
1901 /*************************************************************
1903 * This adds registry entries for any externally loaded fonts
1904 * (fonts from fontconfig or FontDirs). It also deletes entries
1905 * of no longer existing fonts.
1908 static void update_reg_entries(void)
1910 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1915 struct list *family_elem_ptr, *face_elem_ptr;
1917 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1918 static const WCHAR spaceW[] = {' ', '\0'};
1921 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1922 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1923 ERR("Can't create Windows font reg key\n");
1927 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1928 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1929 ERR("Can't create Windows font reg key\n");
1933 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1934 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1935 ERR("Can't create external font reg key\n");
1939 /* enumerate the fonts and add external ones to the two keys */
1941 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1942 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1943 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1944 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1945 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1946 if(!face->external) continue;
1948 if(strcmpiW(face->StyleName, RegularW))
1949 len = len_fam + strlenW(face->StyleName) + 1;
1950 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1951 strcpyW(valueW, family->FamilyName);
1952 if(len != len_fam) {
1953 strcatW(valueW, spaceW);
1954 strcatW(valueW, face->StyleName);
1956 strcatW(valueW, TrueType);
1958 file = wine_get_dos_file_name(face->file);
1960 len = strlenW(file) + 1;
1963 if((path = strrchr(face->file, '/')) == NULL)
1967 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1969 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1970 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1972 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1973 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1974 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1976 HeapFree(GetProcessHeap(), 0, file);
1977 HeapFree(GetProcessHeap(), 0, valueW);
1981 if(external_key) RegCloseKey(external_key);
1982 if(win9x_key) RegCloseKey(win9x_key);
1983 if(winnt_key) RegCloseKey(winnt_key);
1987 static void delete_external_font_keys(void)
1989 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1990 DWORD dlen, vlen, datalen, valuelen, i, type;
1994 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1995 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1996 ERR("Can't create Windows font reg key\n");
2000 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2001 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2002 ERR("Can't create Windows font reg key\n");
2006 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2007 ERR("Can't create external font reg key\n");
2011 /* Delete all external fonts added last time */
2013 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2014 &valuelen, &datalen, NULL, NULL);
2015 valuelen++; /* returned value doesn't include room for '\0' */
2016 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2017 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2019 dlen = datalen * sizeof(WCHAR);
2022 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2023 &dlen) == ERROR_SUCCESS) {
2025 RegDeleteValueW(winnt_key, valueW);
2026 RegDeleteValueW(win9x_key, valueW);
2027 /* reset dlen and vlen */
2031 HeapFree(GetProcessHeap(), 0, data);
2032 HeapFree(GetProcessHeap(), 0, valueW);
2034 /* Delete the old external fonts key */
2035 RegCloseKey(external_key);
2036 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2039 if(win9x_key) RegCloseKey(win9x_key);
2040 if(winnt_key) RegCloseKey(winnt_key);
2043 /*************************************************************
2044 * WineEngAddFontResourceEx
2047 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2050 if (ft_handle) /* do it only if we have freetype up and running */
2055 FIXME("Ignoring flags %x\n", flags);
2057 if((unixname = wine_get_unix_file_name(file)))
2059 EnterCriticalSection( &freetype_cs );
2060 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2061 LeaveCriticalSection( &freetype_cs );
2062 HeapFree(GetProcessHeap(), 0, unixname);
2064 if (!ret && !strchrW(file, '\\')) {
2065 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2066 ret = load_font_from_winfonts_dir(file);
2068 /* Try in datadir/fonts (or builddir/fonts),
2069 * needed for Magic the Gathering Online
2071 ret = load_font_from_data_dir(file);
2078 /*************************************************************
2079 * WineEngAddFontMemResourceEx
2082 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2084 if (ft_handle) /* do it only if we have freetype up and running */
2086 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2088 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2089 memcpy(pFontCopy, pbFont, cbFont);
2091 EnterCriticalSection( &freetype_cs );
2092 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2093 LeaveCriticalSection( &freetype_cs );
2097 TRACE("AddFontToList failed\n");
2098 HeapFree(GetProcessHeap(), 0, pFontCopy);
2101 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2102 * For now return something unique but quite random
2104 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2105 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2112 /*************************************************************
2113 * WineEngRemoveFontResourceEx
2116 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2122 static const struct nls_update_font_list
2124 UINT ansi_cp, oem_cp;
2125 const char *oem, *fixed, *system;
2126 const char *courier, *serif, *small, *sserif;
2127 /* these are for font substitute */
2128 const char *shelldlg, *tmsrmn;
2129 } nls_update_font_list[] =
2131 /* Latin 1 (United States) */
2132 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2133 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2134 "Tahoma","Times New Roman",
2136 /* Latin 1 (Multilingual) */
2137 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2138 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2139 "Tahoma","Times New Roman", /* FIXME unverified */
2141 /* Eastern Europe */
2142 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2143 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2144 "Tahoma","Times New Roman", /* FIXME unverified */
2147 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2148 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2149 "Tahoma","Times New Roman", /* FIXME unverified */
2152 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2153 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2154 "Tahoma","Times New Roman", /* FIXME unverified */
2157 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2158 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2159 "Tahoma","Times New Roman", /* FIXME unverified */
2162 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2163 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2164 "Tahoma","Times New Roman", /* FIXME unverified */
2167 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2168 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2169 "Tahoma","Times New Roman", /* FIXME unverified */
2172 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2173 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2174 "Tahoma","Times New Roman", /* FIXME unverified */
2177 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2178 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2179 "Tahoma","Times New Roman", /* FIXME unverified */
2182 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2183 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2184 "Tahoma","Times New Roman", /* FIXME unverified */
2187 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2188 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2189 "MS UI Gothic","MS Serif",
2191 /* Chinese Simplified */
2192 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2193 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2194 "Tahoma", "Times New Roman", /* FIXME unverified */
2197 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2198 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2201 /* Chinese Traditional */
2202 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2203 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2204 "PMingLiU", "MingLiU",
2208 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2210 return ( ansi_cp == 932 /* CP932 for Japanese */
2211 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2212 || ansi_cp == 949 /* CP949 for Korean */
2213 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2216 static inline HKEY create_fonts_NT_registry_key(void)
2220 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2221 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2225 static inline HKEY create_fonts_9x_registry_key(void)
2229 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2230 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2234 static inline HKEY create_config_fonts_registry_key(void)
2238 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2239 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2243 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2245 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2246 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2247 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2248 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2251 static void update_font_info(void)
2253 char buf[40], cpbuf[40];
2256 UINT i, ansi_cp = 0, oem_cp = 0;
2258 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2261 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2262 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2263 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2264 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2265 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2267 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2268 if (is_dbcs_ansi_cp(ansi_cp))
2269 use_default_fallback = TRUE;
2272 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2274 if (!strcmp( buf, cpbuf )) /* already set correctly */
2279 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2281 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2283 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2286 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2288 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2289 nls_update_font_list[i].oem_cp == oem_cp)
2293 hkey = create_config_fonts_registry_key();
2294 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2295 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2296 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2299 hkey = create_fonts_NT_registry_key();
2300 add_font_list(hkey, &nls_update_font_list[i]);
2303 hkey = create_fonts_9x_registry_key();
2304 add_font_list(hkey, &nls_update_font_list[i]);
2307 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2309 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2310 strlen(nls_update_font_list[i].shelldlg)+1);
2311 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2312 strlen(nls_update_font_list[i].tmsrmn)+1);
2318 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2322 static BOOL init_freetype(void)
2324 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2327 "Wine cannot find the FreeType font library. To enable Wine to\n"
2328 "use TrueType fonts please install a version of FreeType greater than\n"
2329 "or equal to 2.0.5.\n"
2330 "http://www.freetype.org\n");
2334 #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;}
2336 LOAD_FUNCPTR(FT_Vector_Unit)
2337 LOAD_FUNCPTR(FT_Done_Face)
2338 LOAD_FUNCPTR(FT_Get_Char_Index)
2339 LOAD_FUNCPTR(FT_Get_Module)
2340 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2341 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2342 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2343 LOAD_FUNCPTR(FT_Init_FreeType)
2344 LOAD_FUNCPTR(FT_Load_Glyph)
2345 LOAD_FUNCPTR(FT_Matrix_Multiply)
2346 LOAD_FUNCPTR(FT_MulFix)
2347 LOAD_FUNCPTR(FT_New_Face)
2348 LOAD_FUNCPTR(FT_New_Memory_Face)
2349 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2350 LOAD_FUNCPTR(FT_Outline_Transform)
2351 LOAD_FUNCPTR(FT_Outline_Translate)
2352 LOAD_FUNCPTR(FT_Select_Charmap)
2353 LOAD_FUNCPTR(FT_Set_Charmap)
2354 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2355 LOAD_FUNCPTR(FT_Vector_Transform)
2358 /* Don't warn if these ones are missing */
2359 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2360 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2361 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2362 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2363 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2364 #ifdef HAVE_FREETYPE_FTWINFNT_H
2365 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2367 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2368 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2369 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2370 <= 2.0.3 has FT_Sqrt64 */
2374 if(pFT_Init_FreeType(&library) != 0) {
2375 ERR("Can't init FreeType library\n");
2376 wine_dlclose(ft_handle, NULL, 0);
2380 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2381 if (pFT_Library_Version)
2382 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2384 if (FT_Version.major<=0)
2390 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2391 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2392 ((FT_Version.minor << 8) & 0x00ff00) |
2393 ((FT_Version.patch ) & 0x0000ff);
2399 "Wine cannot find certain functions that it needs inside the FreeType\n"
2400 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2401 "FreeType to at least version 2.0.5.\n"
2402 "http://www.freetype.org\n");
2403 wine_dlclose(ft_handle, NULL, 0);
2408 /*************************************************************
2411 * Initialize FreeType library and create a list of available faces
2413 BOOL WineEngInit(void)
2415 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2416 static const WCHAR pathW[] = {'P','a','t','h',0};
2418 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2420 WCHAR windowsdir[MAX_PATH];
2423 const char *data_dir;
2427 /* update locale dependent font info in registry */
2430 if(!init_freetype()) return FALSE;
2432 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2433 ERR("Failed to create font mutex\n");
2436 WaitForSingleObject(font_mutex, INFINITE);
2438 delete_external_font_keys();
2440 /* load the system bitmap fonts */
2441 load_system_fonts();
2443 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2444 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2445 strcatW(windowsdir, fontsW);
2446 if((unixname = wine_get_unix_file_name(windowsdir)))
2448 ReadFontDir(unixname, FALSE);
2449 HeapFree(GetProcessHeap(), 0, unixname);
2452 /* load the system truetype fonts */
2453 data_dir = wine_get_data_dir();
2454 if (!data_dir) data_dir = wine_get_build_dir();
2455 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2456 strcpy(unixname, data_dir);
2457 strcat(unixname, "/fonts/");
2458 ReadFontDir(unixname, TRUE);
2459 HeapFree(GetProcessHeap(), 0, unixname);
2462 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2463 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2464 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2466 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2467 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2468 &hkey) == ERROR_SUCCESS) {
2470 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2471 &valuelen, &datalen, NULL, NULL);
2473 valuelen++; /* returned value doesn't include room for '\0' */
2474 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2475 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2478 dlen = datalen * sizeof(WCHAR);
2480 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2481 &dlen) == ERROR_SUCCESS) {
2482 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2484 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2486 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2487 HeapFree(GetProcessHeap(), 0, unixname);
2490 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2492 WCHAR pathW[MAX_PATH];
2493 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2496 sprintfW(pathW, fmtW, windowsdir, data);
2497 if((unixname = wine_get_unix_file_name(pathW)))
2499 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2500 HeapFree(GetProcessHeap(), 0, unixname);
2503 load_font_from_data_dir(data);
2505 /* reset dlen and vlen */
2510 HeapFree(GetProcessHeap(), 0, data);
2511 HeapFree(GetProcessHeap(), 0, valueW);
2515 load_fontconfig_fonts();
2517 /* then look in any directories that we've specified in the config file */
2518 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2519 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2525 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2527 len += sizeof(WCHAR);
2528 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2529 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2531 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2532 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2533 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2534 TRACE( "got font path %s\n", debugstr_a(valueA) );
2538 LPSTR next = strchr( ptr, ':' );
2539 if (next) *next++ = 0;
2540 ReadFontDir( ptr, TRUE );
2543 HeapFree( GetProcessHeap(), 0, valueA );
2545 HeapFree( GetProcessHeap(), 0, valueW );
2554 update_reg_entries();
2556 init_system_links();
2558 ReleaseMutex(font_mutex);
2563 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2566 TT_HoriHeader *pHori;
2570 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2571 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2573 if(height == 0) height = 16;
2575 /* Calc. height of EM square:
2577 * For +ve lfHeight we have
2578 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2579 * Re-arranging gives:
2580 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2582 * For -ve lfHeight we have
2584 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2585 * with il = winAscent + winDescent - units_per_em]
2590 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2591 ppem = ft_face->units_per_EM * height /
2592 (pHori->Ascender - pHori->Descender);
2594 ppem = ft_face->units_per_EM * height /
2595 (pOS2->usWinAscent + pOS2->usWinDescent);
2603 static struct font_mapping *map_font_file( const char *name )
2605 struct font_mapping *mapping;
2609 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2610 if (fstat( fd, &st ) == -1) goto error;
2612 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2614 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2616 mapping->refcount++;
2621 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2624 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2627 if (mapping->data == MAP_FAILED)
2629 HeapFree( GetProcessHeap(), 0, mapping );
2632 mapping->refcount = 1;
2633 mapping->dev = st.st_dev;
2634 mapping->ino = st.st_ino;
2635 mapping->size = st.st_size;
2636 list_add_tail( &mappings_list, &mapping->entry );
2644 static void unmap_font_file( struct font_mapping *mapping )
2646 if (!--mapping->refcount)
2648 list_remove( &mapping->entry );
2649 munmap( mapping->data, mapping->size );
2650 HeapFree( GetProcessHeap(), 0, mapping );
2654 static LONG load_VDMX(GdiFont*, LONG);
2656 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2663 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2667 if (!(font->mapping = map_font_file( face->file )))
2669 WARN("failed to map %s\n", debugstr_a(face->file));
2672 data_ptr = font->mapping->data;
2673 data_size = font->mapping->size;
2677 data_ptr = face->font_data_ptr;
2678 data_size = face->font_data_size;
2681 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2683 ERR("FT_New_Face rets %d\n", err);
2687 /* set it here, as load_VDMX needs it */
2688 font->ft_face = ft_face;
2690 if(FT_IS_SCALABLE(ft_face)) {
2691 /* load the VDMX table if we have one */
2692 font->ppem = load_VDMX(font, height);
2694 font->ppem = calc_ppem_for_height(ft_face, height);
2696 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2697 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2699 font->ppem = height;
2700 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2701 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2707 static int get_nearest_charset(Face *face, int *cp)
2709 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2710 a single face with the requested charset. The idea is to check if
2711 the selected font supports the current ANSI codepage, if it does
2712 return the corresponding charset, else return the first charset */
2715 int acp = GetACP(), i;
2719 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2720 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2721 return csi.ciCharset;
2723 for(i = 0; i < 32; i++) {
2725 if(face->fs.fsCsb[0] & fs0) {
2726 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2728 return csi.ciCharset;
2731 FIXME("TCI failing on %x\n", fs0);
2735 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2736 face->fs.fsCsb[0], face->file);
2738 return DEFAULT_CHARSET;
2741 static GdiFont *alloc_font(void)
2743 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2745 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2746 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2748 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2749 ret->total_kern_pairs = (DWORD)-1;
2750 ret->kern_pairs = NULL;
2751 list_init(&ret->hfontlist);
2752 list_init(&ret->child_fonts);
2756 static void free_font(GdiFont *font)
2758 struct list *cursor, *cursor2;
2761 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2763 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2764 struct list *first_hfont;
2765 HFONTLIST *hfontlist;
2766 list_remove(cursor);
2769 first_hfont = list_head(&child->font->hfontlist);
2770 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2771 DeleteObject(hfontlist->hfont);
2772 HeapFree(GetProcessHeap(), 0, hfontlist);
2773 free_font(child->font);
2775 HeapFree(GetProcessHeap(), 0, child);
2778 if (font->ft_face) pFT_Done_Face(font->ft_face);
2779 if (font->mapping) unmap_font_file( font->mapping );
2780 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2781 HeapFree(GetProcessHeap(), 0, font->potm);
2782 HeapFree(GetProcessHeap(), 0, font->name);
2783 for (i = 0; i < font->gmsize; i++)
2784 HeapFree(GetProcessHeap(),0,font->gm[i]);
2785 HeapFree(GetProcessHeap(), 0, font->gm);
2786 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2787 HeapFree(GetProcessHeap(), 0, font);
2791 /*************************************************************
2794 * load the vdmx entry for the specified height
2797 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2798 ( ( (FT_ULong)_x4 << 24 ) | \
2799 ( (FT_ULong)_x3 << 16 ) | \
2800 ( (FT_ULong)_x2 << 8 ) | \
2803 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2818 static LONG load_VDMX(GdiFont *font, LONG height)
2822 BYTE devXRatio, devYRatio;
2823 USHORT numRecs, numRatios;
2824 DWORD result, offset = -1;
2828 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2830 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2833 /* FIXME: need the real device aspect ratio */
2837 numRecs = GET_BE_WORD(hdr[1]);
2838 numRatios = GET_BE_WORD(hdr[2]);
2840 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2841 for(i = 0; i < numRatios; i++) {
2844 offset = (3 * 2) + (i * sizeof(Ratios));
2845 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2848 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2850 if((ratio.xRatio == 0 &&
2851 ratio.yStartRatio == 0 &&
2852 ratio.yEndRatio == 0) ||
2853 (devXRatio == ratio.xRatio &&
2854 devYRatio >= ratio.yStartRatio &&
2855 devYRatio <= ratio.yEndRatio))
2857 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2858 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2859 offset = GET_BE_WORD(tmp);
2865 FIXME("No suitable ratio found\n");
2869 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2871 BYTE startsz, endsz;
2874 recs = GET_BE_WORD(group.recs);
2875 startsz = group.startsz;
2876 endsz = group.endsz;
2878 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2880 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2881 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2882 if(result == GDI_ERROR) {
2883 FIXME("Failed to retrieve vTable\n");
2888 for(i = 0; i < recs; i++) {
2889 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2890 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2891 ppem = GET_BE_WORD(vTable[i * 3]);
2893 if(yMax + -yMin == height) {
2896 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2899 if(yMax + -yMin > height) {
2902 goto end; /* failed */
2904 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2905 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2906 ppem = GET_BE_WORD(vTable[i * 3]);
2907 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2913 TRACE("ppem not found for height %d\n", height);
2917 if(ppem < startsz || ppem > endsz)
2920 for(i = 0; i < recs; i++) {
2922 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2924 if(yPelHeight > ppem)
2927 if(yPelHeight == ppem) {
2928 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2929 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2930 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2936 HeapFree(GetProcessHeap(), 0, vTable);
2942 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
2944 if(font->font_desc.hash != fd->hash) return TRUE;
2945 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2946 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2947 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2948 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2951 static void calc_hash(FONT_DESC *pfd)
2953 DWORD hash = 0, *ptr, two_chars;
2957 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2959 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2961 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2963 pwc = (WCHAR *)&two_chars;
2965 *pwc = toupperW(*pwc);
2967 *pwc = toupperW(*pwc);
2971 hash ^= !pfd->can_use_bitmap;
2976 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const XFORM *pxf, BOOL can_use_bitmap)
2981 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2984 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2985 fd.can_use_bitmap = can_use_bitmap;
2988 /* try the in-use list */
2989 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2990 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2991 if(!fontcmp(ret, &fd)) {
2992 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2993 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2994 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2995 if(hflist->hfont == hfont)
2998 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2999 hflist->hfont = hfont;
3000 list_add_head(&ret->hfontlist, &hflist->entry);
3005 /* then the unused list */
3006 font_elem_ptr = list_head(&unused_gdi_font_list);
3007 while(font_elem_ptr) {
3008 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3009 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3010 if(!fontcmp(ret, &fd)) {
3011 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3012 assert(list_empty(&ret->hfontlist));
3013 TRACE("Found %p in unused list\n", ret);
3014 list_remove(&ret->entry);
3015 list_add_head(&gdi_font_list, &ret->entry);
3016 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3017 hflist->hfont = hfont;
3018 list_add_head(&ret->hfontlist, &hflist->entry);
3026 /*************************************************************
3027 * create_child_font_list
3029 static BOOL create_child_font_list(GdiFont *font)
3032 SYSTEM_LINKS *font_link;
3033 CHILD_FONT *font_link_entry, *new_child;
3035 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3037 if(!strcmpW(font_link->font_name, font->name))
3039 TRACE("found entry in system list\n");
3040 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3042 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3043 new_child->face = font_link_entry->face;
3044 new_child->font = NULL;
3045 list_add_tail(&font->child_fonts, &new_child->entry);
3046 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3053 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3054 * Sans Serif. This is how asian windows get default fallbacks for fonts
3056 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3057 font->charset != OEM_CHARSET &&
3058 strcmpW(font->name,szDefaultFallbackLink) != 0)
3059 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3061 if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3063 TRACE("found entry in default fallback list\n");
3064 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3066 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3067 new_child->face = font_link_entry->face;
3068 new_child->font = NULL;
3069 list_add_tail(&font->child_fonts, &new_child->entry);
3070 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3080 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3082 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3084 if (pFT_Set_Charmap)
3087 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3089 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3091 for (i = 0; i < ft_face->num_charmaps; i++)
3093 if (ft_face->charmaps[i]->encoding == encoding)
3095 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3096 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3098 switch (ft_face->charmaps[i]->platform_id)
3101 cmap_def = ft_face->charmaps[i];
3103 case 0: /* Apple Unicode */
3104 cmap0 = ft_face->charmaps[i];
3106 case 1: /* Macintosh */
3107 cmap1 = ft_face->charmaps[i];
3110 cmap2 = ft_face->charmaps[i];
3112 case 3: /* Microsoft */
3113 cmap3 = ft_face->charmaps[i];
3118 if (cmap3) /* prefer Microsoft cmap table */
3119 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3121 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3123 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3125 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3127 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3129 return ft_err == FT_Err_Ok;
3132 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3135 /*************************************************************
3136 * WineEngCreateFontInstance
3139 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3142 Face *face, *best, *best_bitmap;
3143 Family *family, *last_resort_family;
3144 struct list *family_elem_ptr, *face_elem_ptr;
3145 INT height, width = 0;
3146 unsigned int score = 0, new_score;
3147 signed int diff = 0, newdiff;
3148 BOOL bd, it, can_use_bitmap;
3153 EnterCriticalSection( &freetype_cs );
3155 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
3157 struct list *first_hfont = list_head(&ret->hfontlist);
3158 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3159 if(hflist->hfont == hfont)
3161 LeaveCriticalSection( &freetype_cs );
3166 if (!GetObjectW( hfont, sizeof(lf), &lf ))
3168 LeaveCriticalSection( &freetype_cs );
3171 lf.lfWidth = abs(lf.lfWidth);
3173 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3175 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3176 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3177 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3180 /* check the cache first */
3181 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
3182 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3183 LeaveCriticalSection( &freetype_cs );
3187 TRACE("not in cache\n");
3188 if(list_empty(&font_list)) /* No fonts installed */
3190 TRACE("No fonts installed\n");
3191 LeaveCriticalSection( &freetype_cs );
3194 if(!have_installed_roman_font)
3196 TRACE("No roman font installed\n");
3197 LeaveCriticalSection( &freetype_cs );
3203 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
3204 ret->font_desc.lf = lf;
3205 ret->font_desc.can_use_bitmap = can_use_bitmap;
3206 calc_hash(&ret->font_desc);
3207 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3208 hflist->hfont = hfont;
3209 list_add_head(&ret->hfontlist, &hflist->entry);
3212 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3213 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3214 original value lfCharSet. Note this is a special case for
3215 Symbol and doesn't happen at least for "Wingdings*" */
3217 if(!strcmpiW(lf.lfFaceName, SymbolW))
3218 lf.lfCharSet = SYMBOL_CHARSET;
3220 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3221 switch(lf.lfCharSet) {
3222 case DEFAULT_CHARSET:
3223 csi.fs.fsCsb[0] = 0;
3226 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3227 csi.fs.fsCsb[0] = 0;
3233 if(lf.lfFaceName[0] != '\0') {
3235 SYSTEM_LINKS *font_link;
3236 CHILD_FONT *font_link_entry;
3237 LPWSTR FaceName = lf.lfFaceName;
3240 * Check for a leading '@' this signals that the font is being
3241 * requested in tategaki mode (vertical writing substitution) but
3242 * does not affect the fontface that is to be selected.
3244 if (lf.lfFaceName[0]=='@')
3245 FaceName = &lf.lfFaceName[1];
3247 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3250 TRACE("substituting %s -> %s\n", debugstr_w(FaceName),
3251 debugstr_w(psub->to.name));
3252 strcpyW(FaceName, psub->to.name);
3255 /* We want a match on name and charset or just name if
3256 charset was DEFAULT_CHARSET. If the latter then
3257 we fixup the returned charset later in get_nearest_charset
3258 where we'll either use the charset of the current ansi codepage
3259 or if that's unavailable the first charset that the font supports.
3261 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3262 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3263 if(!strcmpiW(family->FamilyName, FaceName)) {
3264 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3265 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3266 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3267 if(face->scalable || can_use_bitmap)
3274 * Try check the SystemLink list first for a replacement font.
3275 * We may find good replacements there.
3277 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3279 if(!strcmpiW(font_link->font_name, FaceName))
3281 TRACE("found entry in system list\n");
3282 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3284 face = font_link_entry->face;
3285 family = face->family;
3286 if(csi.fs.fsCsb[0] &
3287 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3289 if(face->scalable || can_use_bitmap)
3297 /* If requested charset was DEFAULT_CHARSET then try using charset
3298 corresponding to the current ansi codepage */
3299 if (!csi.fs.fsCsb[0] || lf.lfWeight == FW_DONTCARE)
3302 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3303 FIXME("TCI failed on codepage %d\n", acp);
3304 csi.fs.fsCsb[0] = 0;
3306 lf.lfCharSet = csi.ciCharset;
3309 /* Face families are in the top 4 bits of lfPitchAndFamily,
3310 so mask with 0xF0 before testing */
3312 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3313 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3314 strcpyW(lf.lfFaceName, defFixed);
3315 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3316 strcpyW(lf.lfFaceName, defSerif);
3317 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3318 strcpyW(lf.lfFaceName, defSans);
3320 strcpyW(lf.lfFaceName, defSans);
3321 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3322 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3323 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3324 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3325 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3326 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3327 if(face->scalable || can_use_bitmap)
3333 last_resort_family = NULL;
3334 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3335 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3336 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3337 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3338 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3341 if(can_use_bitmap && !last_resort_family)
3342 last_resort_family = family;
3347 if(last_resort_family) {
3348 family = last_resort_family;
3349 csi.fs.fsCsb[0] = 0;
3353 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3354 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3355 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3356 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3357 if(face->scalable) {
3358 csi.fs.fsCsb[0] = 0;
3359 WARN("just using first face for now\n");
3362 if(can_use_bitmap && !last_resort_family)
3363 last_resort_family = family;
3366 if(!last_resort_family) {
3367 FIXME("can't find a single appropriate font - bailing\n");
3369 LeaveCriticalSection( &freetype_cs );
3373 WARN("could only find a bitmap font - this will probably look awful!\n");
3374 family = last_resort_family;
3375 csi.fs.fsCsb[0] = 0;
3378 it = lf.lfItalic ? 1 : 0;
3379 bd = lf.lfWeight > 550 ? 1 : 0;
3381 height = GDI_ROUND( (double)lf.lfHeight * dc->xformWorld2Vport.eM22 );
3382 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
3384 face = best = best_bitmap = NULL;
3385 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3387 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3391 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3392 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3393 new_score = (italic ^ it) + (bold ^ bd);
3394 if(!best || new_score <= score)
3396 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3397 italic, bold, it, bd);
3400 if(best->scalable && score == 0) break;
3404 newdiff = height - (signed int)(best->size.height);
3406 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3407 if(!best_bitmap || new_score < score ||
3408 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3410 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3413 if(score == 0 && diff == 0) break;
3420 face = best->scalable ? best : best_bitmap;
3421 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3422 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3426 if(csi.fs.fsCsb[0]) {
3427 ret->charset = lf.lfCharSet;
3428 ret->codepage = csi.ciACP;
3431 ret->charset = get_nearest_charset(face, &ret->codepage);
3433 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3434 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3436 ret->aveWidth = height ? lf.lfWidth : 0;
3438 if(!face->scalable) {
3439 /* Windows uses integer scaling factors for bitmap fonts */
3440 INT scale, scaled_height;
3442 if (height != 0) height = diff;
3443 height += face->size.height;
3445 scale = (height + face->size.height - 1) / face->size.height;
3446 scaled_height = scale * face->size.height;
3447 /* XP allows not more than 10% deviation */
3448 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3449 ret->scale_y = scale;
3451 width = face->size.x_ppem >> 6;
3452 height = face->size.y_ppem >> 6;
3456 TRACE("font scale y: %f\n", ret->scale_y);
3458 ret->ft_face = OpenFontFace(ret, face, width, height);
3463 LeaveCriticalSection( &freetype_cs );
3467 ret->ntmFlags = face->ntmFlags;
3469 if (ret->charset == SYMBOL_CHARSET &&
3470 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3473 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3477 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3480 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3481 ret->name = strdupW(family->FamilyName);
3482 ret->underline = lf.lfUnderline ? 0xff : 0;
3483 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3484 create_child_font_list(ret);
3486 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3488 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3489 if (length != GDI_ERROR)
3491 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3492 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3493 TRACE("Loaded GSUB table of %i bytes\n",length);
3497 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3499 list_add_head(&gdi_font_list, &ret->entry);
3500 LeaveCriticalSection( &freetype_cs );
3504 static void dump_gdi_font_list(void)
3507 struct list *elem_ptr;
3509 TRACE("---------- gdiFont Cache ----------\n");
3510 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3511 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3512 TRACE("gdiFont=%p %s %d\n",
3513 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3516 TRACE("---------- Unused gdiFont Cache ----------\n");
3517 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3518 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3519 TRACE("gdiFont=%p %s %d\n",
3520 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3524 /*************************************************************
3525 * WineEngDestroyFontInstance
3527 * free the gdiFont associated with this handle
3530 BOOL WineEngDestroyFontInstance(HFONT handle)
3535 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3538 EnterCriticalSection( &freetype_cs );
3540 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3542 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3543 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3544 if(hflist->hfont == handle)
3546 TRACE("removing child font %p from child list\n", gdiFont);
3547 list_remove(&gdiFont->entry);
3548 LeaveCriticalSection( &freetype_cs );
3553 TRACE("destroying hfont=%p\n", handle);
3555 dump_gdi_font_list();
3557 font_elem_ptr = list_head(&gdi_font_list);
3558 while(font_elem_ptr) {
3559 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3560 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3562 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3563 while(hfontlist_elem_ptr) {
3564 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3565 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3566 if(hflist->hfont == handle) {
3567 list_remove(&hflist->entry);
3568 HeapFree(GetProcessHeap(), 0, hflist);
3572 if(list_empty(&gdiFont->hfontlist)) {
3573 TRACE("Moving to Unused list\n");
3574 list_remove(&gdiFont->entry);
3575 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3580 font_elem_ptr = list_head(&unused_gdi_font_list);
3581 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3582 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3583 while(font_elem_ptr) {
3584 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3585 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3586 TRACE("freeing %p\n", gdiFont);
3587 list_remove(&gdiFont->entry);
3590 LeaveCriticalSection( &freetype_cs );
3594 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3595 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3600 if (face->cached_enum_data)
3603 *pelf = face->cached_enum_data->elf;
3604 *pntm = face->cached_enum_data->ntm;
3605 *ptype = face->cached_enum_data->type;
3609 font = alloc_font();
3611 if(face->scalable) {
3612 height = -2048; /* 2048 is the most common em size */
3615 height = face->size.y_ppem >> 6;
3616 width = face->size.x_ppem >> 6;
3618 font->scale_y = 1.0;
3620 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3626 font->name = strdupW(face->family->FamilyName);
3627 font->ntmFlags = face->ntmFlags;
3629 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3631 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3633 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3635 lstrcpynW(pelf->elfLogFont.lfFaceName,
3636 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3638 lstrcpynW(pelf->elfFullName,
3639 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3641 lstrcpynW(pelf->elfStyle,
3642 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3647 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3649 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3651 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3652 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3653 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3656 pntm->ntmTm.ntmFlags = face->ntmFlags;
3657 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3658 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3659 pntm->ntmFontSig = face->fs;
3661 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3663 pelf->elfLogFont.lfEscapement = 0;
3664 pelf->elfLogFont.lfOrientation = 0;
3665 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3666 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3667 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3668 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3669 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3670 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3671 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3672 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3673 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3674 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3675 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3678 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3679 *ptype |= TRUETYPE_FONTTYPE;
3680 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3681 *ptype |= DEVICE_FONTTYPE;
3682 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3683 *ptype |= RASTER_FONTTYPE;
3685 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3686 if (face->cached_enum_data)
3688 face->cached_enum_data->elf = *pelf;
3689 face->cached_enum_data->ntm = *pntm;
3690 face->cached_enum_data->type = *ptype;
3696 /*************************************************************
3700 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3704 struct list *family_elem_ptr, *face_elem_ptr;
3706 NEWTEXTMETRICEXW ntm;
3715 lf.lfCharSet = DEFAULT_CHARSET;
3716 lf.lfPitchAndFamily = 0;
3717 lf.lfFaceName[0] = 0;
3721 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3723 EnterCriticalSection( &freetype_cs );
3724 if(plf->lfFaceName[0]) {
3726 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3729 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3730 debugstr_w(psub->to.name));
3732 strcpyW(lf.lfFaceName, psub->to.name);
3736 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3737 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3738 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3739 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3740 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3741 GetEnumStructs(face, &elf, &ntm, &type);
3742 for(i = 0; i < 32; i++) {
3743 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3744 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3745 strcpyW(elf.elfScript, OEM_DOSW);
3746 i = 32; /* break out of loop */
3747 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3750 fs.fsCsb[0] = 1L << i;
3752 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3754 csi.ciCharset = DEFAULT_CHARSET;
3755 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3756 if(csi.ciCharset != DEFAULT_CHARSET) {
3757 elf.elfLogFont.lfCharSet =
3758 ntm.ntmTm.tmCharSet = csi.ciCharset;
3760 strcpyW(elf.elfScript, ElfScriptsW[i]);
3762 FIXME("Unknown elfscript for bit %d\n", i);
3765 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3766 debugstr_w(elf.elfLogFont.lfFaceName),
3767 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3768 csi.ciCharset, type, debugstr_w(elf.elfScript),
3769 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3770 ntm.ntmTm.ntmFlags);
3771 /* release section before callback (FIXME) */
3772 LeaveCriticalSection( &freetype_cs );
3773 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3774 EnterCriticalSection( &freetype_cs );
3780 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3781 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3782 face_elem_ptr = list_head(&family->faces);
3783 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3784 GetEnumStructs(face, &elf, &ntm, &type);
3785 for(i = 0; i < 32; i++) {
3786 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3787 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3788 strcpyW(elf.elfScript, OEM_DOSW);
3789 i = 32; /* break out of loop */
3790 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3793 fs.fsCsb[0] = 1L << i;
3795 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3797 csi.ciCharset = DEFAULT_CHARSET;
3798 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3799 if(csi.ciCharset != DEFAULT_CHARSET) {
3800 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3803 strcpyW(elf.elfScript, ElfScriptsW[i]);
3805 FIXME("Unknown elfscript for bit %d\n", i);
3808 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3809 debugstr_w(elf.elfLogFont.lfFaceName),
3810 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3811 csi.ciCharset, type, debugstr_w(elf.elfScript),
3812 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3813 ntm.ntmTm.ntmFlags);
3814 /* release section before callback (FIXME) */
3815 LeaveCriticalSection( &freetype_cs );
3816 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3817 EnterCriticalSection( &freetype_cs );
3821 LeaveCriticalSection( &freetype_cs );
3825 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3827 pt->x.value = vec->x >> 6;
3828 pt->x.fract = (vec->x & 0x3f) << 10;
3829 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3830 pt->y.value = vec->y >> 6;
3831 pt->y.fract = (vec->y & 0x3f) << 10;
3832 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3836 /***************************************************
3837 * According to the MSDN documentation on WideCharToMultiByte,
3838 * certain codepages cannot set the default_used parameter.
3839 * This returns TRUE if the codepage can set that parameter, false else
3840 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3842 static BOOL codepage_sets_default_used(UINT codepage)
3856 * GSUB Table handling functions
3859 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
3861 const GSUB_CoverageFormat1* cf1;
3863 cf1 = (GSUB_CoverageFormat1*)table;
3865 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
3867 int count = GET_BE_WORD(cf1->GlyphCount);
3869 TRACE("Coverage Format 1, %i glyphs\n",count);
3870 for (i = 0; i < count; i++)
3871 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
3875 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
3877 const GSUB_CoverageFormat2* cf2;
3880 cf2 = (GSUB_CoverageFormat2*)cf1;
3882 count = GET_BE_WORD(cf2->RangeCount);
3883 TRACE("Coverage Format 2, %i ranges\n",count);
3884 for (i = 0; i < count; i++)
3886 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
3888 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
3889 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
3891 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
3892 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
3898 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
3903 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
3905 const GSUB_ScriptList *script;
3906 const GSUB_Script *deflt = NULL;
3908 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
3910 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
3911 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
3913 const GSUB_Script *scr;
3916 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
3917 scr = (GSUB_Script*)((LPBYTE)script + offset);
3919 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
3921 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
3927 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
3931 const GSUB_LangSys *Lang;
3933 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
3935 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
3937 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
3938 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
3940 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
3943 offset = GET_BE_WORD(script->DefaultLangSys);
3946 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
3952 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
3955 const GSUB_FeatureList *feature;
3956 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
3958 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
3959 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
3961 int index = GET_BE_WORD(lang->FeatureIndex[i]);
3962 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
3964 const GSUB_Feature *feat;
3965 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
3972 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
3976 const GSUB_LookupList *lookup;
3977 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
3979 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
3980 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
3982 const GSUB_LookupTable *look;
3983 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
3984 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
3985 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
3986 if (GET_BE_WORD(look->LookupType) != 1)
3987 FIXME("We only handle SubType 1\n");
3992 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
3994 const GSUB_SingleSubstFormat1 *ssf1;
3995 offset = GET_BE_WORD(look->SubTable[j]);
3996 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
3997 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
3999 int offset = GET_BE_WORD(ssf1->Coverage);
4000 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4001 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
4003 TRACE(" Glyph 0x%x ->",glyph);
4004 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4005 TRACE(" 0x%x\n",glyph);
4010 const GSUB_SingleSubstFormat2 *ssf2;
4014 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
4015 offset = GET_BE_WORD(ssf1->Coverage);
4016 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4017 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
4018 TRACE(" Coverage index %i\n",index);
4021 TRACE(" Glyph is 0x%x ->",glyph);
4022 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4023 TRACE("0x%x\n",glyph);
4032 static const char* get_opentype_script(const GdiFont *font)
4035 * I am not sure if this is the correct way to generate our script tag
4038 switch (font->charset)
4040 case ANSI_CHARSET: return "latn";
4041 case BALTIC_CHARSET: return "latn"; /* ?? */
4042 case CHINESEBIG5_CHARSET: return "hani";
4043 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4044 case GB2312_CHARSET: return "hani";
4045 case GREEK_CHARSET: return "grek";
4046 case HANGUL_CHARSET: return "hang";
4047 case RUSSIAN_CHARSET: return "cyrl";
4048 case SHIFTJIS_CHARSET: return "kana";
4049 case TURKISH_CHARSET: return "latn"; /* ?? */
4050 case VIETNAMESE_CHARSET: return "latn";
4051 case JOHAB_CHARSET: return "latn"; /* ?? */
4052 case ARABIC_CHARSET: return "arab";
4053 case HEBREW_CHARSET: return "hebr";
4054 case THAI_CHARSET: return "thai";
4055 default: return "latn";
4059 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4061 const GSUB_Header *header;
4062 const GSUB_Script *script;
4063 const GSUB_LangSys *language;
4064 const GSUB_Feature *feature;
4066 if (!font->GSUB_Table)
4069 header = font->GSUB_Table;
4071 script = GSUB_get_script_table(header, get_opentype_script(font));
4074 TRACE("Script not found\n");
4077 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4080 TRACE("Language not found\n");
4083 feature = GSUB_get_feature(header, language, "vrt2");
4085 feature = GSUB_get_feature(header, language, "vert");
4088 TRACE("vrt2/vert feature not found\n");
4091 return GSUB_apply_feature(header, feature, glyph);
4094 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4098 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4099 WCHAR wc = (WCHAR)glyph;
4101 BOOL *default_used_pointer;
4104 default_used_pointer = NULL;
4105 default_used = FALSE;
4106 if (codepage_sets_default_used(font->codepage))
4107 default_used_pointer = &default_used;
4108 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4111 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4112 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4113 return get_GSUB_vert_glyph(font,ret);
4116 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4117 glyph = glyph + 0xf000;
4118 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4119 return get_GSUB_vert_glyph(font,glyphId);
4122 /*************************************************************
4123 * WineEngGetGlyphIndices
4126 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4127 LPWORD pgi, DWORD flags)
4130 int default_char = -1;
4132 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4134 for(i = 0; i < count; i++)
4136 pgi[i] = get_glyph_index(font, lpstr[i]);
4139 if (default_char == -1)
4141 if (FT_IS_SFNT(font->ft_face))
4143 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4144 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4149 WineEngGetTextMetrics(font, &textm);
4150 default_char = textm.tmDefaultChar;
4153 pgi[i] = default_char;
4159 /*************************************************************
4160 * WineEngGetGlyphOutline
4162 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4163 * except that the first parameter is the HWINEENGFONT of the font in
4164 * question rather than an HDC.
4167 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4168 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4171 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4172 FT_Face ft_face = incoming_font->ft_face;
4173 GdiFont *font = incoming_font;
4174 FT_UInt glyph_index;
4175 DWORD width, height, pitch, needed = 0;
4176 FT_Bitmap ft_bitmap;
4178 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4180 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4181 float widthRatio = 1.0;
4182 FT_Matrix transMat = identityMat;
4183 BOOL needsTransform = FALSE;
4184 BOOL tategaki = (font->GSUB_Table != NULL);
4185 UINT original_index;
4188 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4189 buflen, buf, lpmat);
4191 EnterCriticalSection( &freetype_cs );
4193 if(format & GGO_GLYPH_INDEX) {
4194 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4195 original_index = glyph;
4196 format &= ~GGO_GLYPH_INDEX;
4198 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4199 ft_face = font->ft_face;
4200 original_index = glyph_index;
4203 /* tategaki never appears to happen to lower glyph index */
4204 if (glyph_index < TATEGAKI_LOWER_BOUND )
4207 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4208 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4209 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4210 font->gmsize * sizeof(GM*));
4212 if(format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL && FONT_GM(font,original_index)->init ) {
4213 *lpgm = FONT_GM(font,original_index)->gm;
4214 LeaveCriticalSection( &freetype_cs );
4215 return 1; /* FIXME */
4219 if (!font->gm[original_index / GM_BLOCK_SIZE])
4220 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4222 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || lpmat)
4223 load_flags |= FT_LOAD_NO_BITMAP;
4225 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4228 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4229 LeaveCriticalSection( &freetype_cs );
4233 /* Scaling factor */
4234 if (font->aveWidth && font->potm)
4236 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11;
4237 widthRatio /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
4240 widthRatio = font->scale_y;
4242 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
4243 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
4245 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
4247 bbx = (right - left) >> 6;
4249 /* Scaling transform */
4250 if(font->aveWidth) {
4252 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4255 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4257 pFT_Matrix_Multiply(&scaleMat, &transMat);
4258 needsTransform = TRUE;
4261 /* Slant transform */
4262 if (font->fake_italic) {
4265 slantMat.xx = (1 << 16);
4266 slantMat.xy = ((1 << 16) >> 2);
4268 slantMat.yy = (1 << 16);
4269 pFT_Matrix_Multiply(&slantMat, &transMat);
4270 needsTransform = TRUE;
4273 /* Rotation transform */
4274 if(font->orientation && !tategaki) {
4275 FT_Matrix rotationMat;
4277 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
4278 pFT_Vector_Unit(&vecAngle, angle);
4279 rotationMat.xx = vecAngle.x;
4280 rotationMat.xy = -vecAngle.y;
4281 rotationMat.yx = -rotationMat.xy;
4282 rotationMat.yy = rotationMat.xx;
4284 pFT_Matrix_Multiply(&rotationMat, &transMat);
4285 needsTransform = TRUE;
4288 /* Extra transformation specified by caller */
4291 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4292 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
4293 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
4294 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4295 pFT_Matrix_Multiply(&extraMat, &transMat);
4296 needsTransform = TRUE;
4299 if(!needsTransform) {
4300 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4301 bottom = (ft_face->glyph->metrics.horiBearingY -
4302 ft_face->glyph->metrics.height) & -64;
4303 lpgm->gmCellIncX = adv;
4304 lpgm->gmCellIncY = 0;
4308 for(xc = 0; xc < 2; xc++) {
4309 for(yc = 0; yc < 2; yc++) {
4310 vec.x = (ft_face->glyph->metrics.horiBearingX +
4311 xc * ft_face->glyph->metrics.width);
4312 vec.y = ft_face->glyph->metrics.horiBearingY -
4313 yc * ft_face->glyph->metrics.height;
4314 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4315 pFT_Vector_Transform(&vec, &transMat);
4316 if(xc == 0 && yc == 0) {
4317 left = right = vec.x;
4318 top = bottom = vec.y;
4320 if(vec.x < left) left = vec.x;
4321 else if(vec.x > right) right = vec.x;
4322 if(vec.y < bottom) bottom = vec.y;
4323 else if(vec.y > top) top = vec.y;
4328 right = (right + 63) & -64;
4329 bottom = bottom & -64;
4330 top = (top + 63) & -64;
4332 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4333 vec.x = ft_face->glyph->metrics.horiAdvance;
4335 pFT_Vector_Transform(&vec, &transMat);
4336 lpgm->gmCellIncX = (vec.x+63) >> 6;
4337 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4339 lpgm->gmBlackBoxX = (right - left) >> 6;
4340 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4341 lpgm->gmptGlyphOrigin.x = left >> 6;
4342 lpgm->gmptGlyphOrigin.y = top >> 6;
4344 if(format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP)
4346 FONT_GM(font,original_index)->gm = *lpgm;
4347 FONT_GM(font,original_index)->adv = adv;
4348 FONT_GM(font,original_index)->lsb = lsb;
4349 FONT_GM(font,original_index)->bbx = bbx;
4350 FONT_GM(font,original_index)->init = TRUE;
4353 if(format == GGO_METRICS)
4355 LeaveCriticalSection( &freetype_cs );
4356 return 1; /* FIXME */
4359 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
4360 TRACE("loaded a bitmap\n");
4361 LeaveCriticalSection( &freetype_cs );
4367 width = lpgm->gmBlackBoxX;
4368 height = lpgm->gmBlackBoxY;
4369 pitch = ((width + 31) >> 5) << 2;
4370 needed = pitch * height;
4372 if(!buf || !buflen) break;
4374 switch(ft_face->glyph->format) {
4375 case ft_glyph_format_bitmap:
4377 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4378 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4379 INT h = ft_face->glyph->bitmap.rows;
4381 memcpy(dst, src, w);
4382 src += ft_face->glyph->bitmap.pitch;
4388 case ft_glyph_format_outline:
4389 ft_bitmap.width = width;
4390 ft_bitmap.rows = height;
4391 ft_bitmap.pitch = pitch;
4392 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4393 ft_bitmap.buffer = buf;
4395 if(needsTransform) {
4396 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4399 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4401 /* Note: FreeType will only set 'black' bits for us. */
4402 memset(buf, 0, needed);
4403 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4407 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4408 LeaveCriticalSection( &freetype_cs );
4413 case GGO_GRAY2_BITMAP:
4414 case GGO_GRAY4_BITMAP:
4415 case GGO_GRAY8_BITMAP:
4416 case WINE_GGO_GRAY16_BITMAP:
4418 unsigned int mult, row, col;
4421 width = lpgm->gmBlackBoxX;
4422 height = lpgm->gmBlackBoxY;
4423 pitch = (width + 3) / 4 * 4;
4424 needed = pitch * height;
4426 if(!buf || !buflen) break;
4428 switch(ft_face->glyph->format) {
4429 case ft_glyph_format_bitmap:
4431 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4432 INT h = ft_face->glyph->bitmap.rows;
4435 for(x = 0; x < pitch; x++)
4437 if(x < ft_face->glyph->bitmap.width)
4438 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4442 src += ft_face->glyph->bitmap.pitch;
4445 LeaveCriticalSection( &freetype_cs );
4448 case ft_glyph_format_outline:
4450 ft_bitmap.width = width;
4451 ft_bitmap.rows = height;
4452 ft_bitmap.pitch = pitch;
4453 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4454 ft_bitmap.buffer = buf;
4457 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4459 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4461 memset(ft_bitmap.buffer, 0, buflen);
4463 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4465 if(format == GGO_GRAY2_BITMAP)
4467 else if(format == GGO_GRAY4_BITMAP)
4469 else if(format == GGO_GRAY8_BITMAP)
4471 else /* format == WINE_GGO_GRAY16_BITMAP */
4473 LeaveCriticalSection( &freetype_cs );
4479 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4480 LeaveCriticalSection( &freetype_cs );
4485 for(row = 0; row < height; row++) {
4487 for(col = 0; col < width; col++, ptr++) {
4488 *ptr = (((int)*ptr) * mult + 128) / 256;
4497 int contour, point = 0, first_pt;
4498 FT_Outline *outline = &ft_face->glyph->outline;
4499 TTPOLYGONHEADER *pph;
4501 DWORD pph_start, cpfx, type;
4503 if(buflen == 0) buf = NULL;
4505 if (needsTransform && buf) {
4506 pFT_Outline_Transform(outline, &transMat);
4509 for(contour = 0; contour < outline->n_contours; contour++) {
4511 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4514 pph->dwType = TT_POLYGON_TYPE;
4515 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4517 needed += sizeof(*pph);
4519 while(point <= outline->contours[contour]) {
4520 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4521 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4522 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4526 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4529 } while(point <= outline->contours[contour] &&
4530 (outline->tags[point] & FT_Curve_Tag_On) ==
4531 (outline->tags[point-1] & FT_Curve_Tag_On));
4532 /* At the end of a contour Windows adds the start point, but
4534 if(point > outline->contours[contour] &&
4535 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4537 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4539 } else if(point <= outline->contours[contour] &&
4540 outline->tags[point] & FT_Curve_Tag_On) {
4541 /* add closing pt for bezier */
4543 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4551 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4554 pph->cb = needed - pph_start;
4560 /* Convert the quadratic Beziers to cubic Beziers.
4561 The parametric eqn for a cubic Bezier is, from PLRM:
4562 r(t) = at^3 + bt^2 + ct + r0
4563 with the control points:
4568 A quadratic Beizer has the form:
4569 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4571 So equating powers of t leads to:
4572 r1 = 2/3 p1 + 1/3 p0
4573 r2 = 2/3 p1 + 1/3 p2
4574 and of course r0 = p0, r3 = p2
4577 int contour, point = 0, first_pt;
4578 FT_Outline *outline = &ft_face->glyph->outline;
4579 TTPOLYGONHEADER *pph;
4581 DWORD pph_start, cpfx, type;
4582 FT_Vector cubic_control[4];
4583 if(buflen == 0) buf = NULL;
4585 if (needsTransform && buf) {
4586 pFT_Outline_Transform(outline, &transMat);
4589 for(contour = 0; contour < outline->n_contours; contour++) {
4591 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4594 pph->dwType = TT_POLYGON_TYPE;
4595 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4597 needed += sizeof(*pph);
4599 while(point <= outline->contours[contour]) {
4600 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4601 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4602 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4605 if(type == TT_PRIM_LINE) {
4607 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4611 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4614 /* FIXME: Possible optimization in endpoint calculation
4615 if there are two consecutive curves */
4616 cubic_control[0] = outline->points[point-1];
4617 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4618 cubic_control[0].x += outline->points[point].x + 1;
4619 cubic_control[0].y += outline->points[point].y + 1;
4620 cubic_control[0].x >>= 1;
4621 cubic_control[0].y >>= 1;
4623 if(point+1 > outline->contours[contour])
4624 cubic_control[3] = outline->points[first_pt];
4626 cubic_control[3] = outline->points[point+1];
4627 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4628 cubic_control[3].x += outline->points[point].x + 1;
4629 cubic_control[3].y += outline->points[point].y + 1;
4630 cubic_control[3].x >>= 1;
4631 cubic_control[3].y >>= 1;
4634 /* r1 = 1/3 p0 + 2/3 p1
4635 r2 = 1/3 p2 + 2/3 p1 */
4636 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4637 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4638 cubic_control[2] = cubic_control[1];
4639 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4640 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4641 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4642 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4644 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4645 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4646 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4651 } while(point <= outline->contours[contour] &&
4652 (outline->tags[point] & FT_Curve_Tag_On) ==
4653 (outline->tags[point-1] & FT_Curve_Tag_On));
4654 /* At the end of a contour Windows adds the start point,
4655 but only for Beziers and we've already done that.
4657 if(point <= outline->contours[contour] &&
4658 outline->tags[point] & FT_Curve_Tag_On) {
4659 /* This is the closing pt of a bezier, but we've already
4660 added it, so just inc point and carry on */
4667 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4670 pph->cb = needed - pph_start;
4676 FIXME("Unsupported format %d\n", format);
4677 LeaveCriticalSection( &freetype_cs );
4680 LeaveCriticalSection( &freetype_cs );
4684 static BOOL get_bitmap_text_metrics(GdiFont *font)
4686 FT_Face ft_face = font->ft_face;
4687 #ifdef HAVE_FREETYPE_FTWINFNT_H
4688 FT_WinFNT_HeaderRec winfnt_header;
4690 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4691 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4692 font->potm->otmSize = size;
4694 #define TM font->potm->otmTextMetrics
4695 #ifdef HAVE_FREETYPE_FTWINFNT_H
4696 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4698 TM.tmHeight = winfnt_header.pixel_height;
4699 TM.tmAscent = winfnt_header.ascent;
4700 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4701 TM.tmInternalLeading = winfnt_header.internal_leading;
4702 TM.tmExternalLeading = winfnt_header.external_leading;
4703 TM.tmAveCharWidth = winfnt_header.avg_width;
4704 TM.tmMaxCharWidth = winfnt_header.max_width;
4705 TM.tmWeight = winfnt_header.weight;
4707 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4708 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4709 TM.tmFirstChar = winfnt_header.first_char;
4710 TM.tmLastChar = winfnt_header.last_char;
4711 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4712 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4713 TM.tmItalic = winfnt_header.italic;
4714 TM.tmUnderlined = font->underline;
4715 TM.tmStruckOut = font->strikeout;
4716 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4717 TM.tmCharSet = winfnt_header.charset;
4722 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4723 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4724 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4725 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4726 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4727 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4728 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4729 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4731 TM.tmDigitizedAspectX = 96; /* FIXME */
4732 TM.tmDigitizedAspectY = 96; /* FIXME */
4734 TM.tmLastChar = 255;
4735 TM.tmDefaultChar = 32;
4736 TM.tmBreakChar = 32;
4737 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4738 TM.tmUnderlined = font->underline;
4739 TM.tmStruckOut = font->strikeout;
4740 /* NB inverted meaning of TMPF_FIXED_PITCH */
4741 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4742 TM.tmCharSet = font->charset;
4750 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
4756 scale_x = (float)font->aveWidth * font->font_desc.matrix.eM11;
4757 scale_x /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
4760 scale_x = font->scale_y;
4762 ptm->tmHeight = (float)ptm->tmHeight * font->scale_y;
4763 ptm->tmAscent = (float)ptm->tmAscent * font->scale_y;
4764 ptm->tmDescent = (float)ptm->tmDescent * font->scale_y;
4765 ptm->tmInternalLeading = (float)ptm->tmInternalLeading * font->scale_y;
4766 ptm->tmExternalLeading = (float)ptm->tmExternalLeading * font->scale_y;
4768 ptm->tmAveCharWidth = (float)ptm->tmAveCharWidth * scale_x;
4769 ptm->tmMaxCharWidth = (float)ptm->tmMaxCharWidth * scale_x;
4772 /*************************************************************
4773 * WineEngGetTextMetrics
4776 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4778 EnterCriticalSection( &freetype_cs );
4780 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
4781 if(!get_bitmap_text_metrics(font))
4783 LeaveCriticalSection( &freetype_cs );
4789 LeaveCriticalSection( &freetype_cs );
4792 *ptm = font->potm->otmTextMetrics;
4793 scale_font_metrics(font, ptm);
4794 LeaveCriticalSection( &freetype_cs );
4799 /*************************************************************
4800 * WineEngGetOutlineTextMetrics
4803 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4804 OUTLINETEXTMETRICW *potm)
4806 FT_Face ft_face = font->ft_face;
4807 UINT needed, lenfam, lensty, ret;
4809 TT_HoriHeader *pHori;
4810 TT_Postscript *pPost;
4811 FT_Fixed x_scale, y_scale;
4812 WCHAR *family_nameW, *style_nameW;
4813 static const WCHAR spaceW[] = {' ', '\0'};
4815 INT ascent, descent;
4817 TRACE("font=%p\n", font);
4819 if(!FT_IS_SCALABLE(ft_face))
4822 EnterCriticalSection( &freetype_cs );
4825 if(cbSize >= font->potm->otmSize)
4827 memcpy(potm, font->potm, font->potm->otmSize);
4828 scale_font_metrics(font, &potm->otmTextMetrics);
4830 LeaveCriticalSection( &freetype_cs );
4831 return font->potm->otmSize;
4835 needed = sizeof(*potm);
4837 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
4838 family_nameW = strdupW(font->name);
4840 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
4842 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
4843 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
4844 style_nameW, lensty/sizeof(WCHAR));
4846 /* These names should be read from the TT name table */
4848 /* length of otmpFamilyName */
4851 /* length of otmpFaceName */
4852 if(!strcasecmp(ft_face->style_name, "regular")) {
4853 needed += lenfam; /* just the family name */
4855 needed += lenfam + lensty; /* family + " " + style */
4858 /* length of otmpStyleName */
4861 /* length of otmpFullName */
4862 needed += lenfam + lensty;
4865 x_scale = ft_face->size->metrics.x_scale;
4866 y_scale = ft_face->size->metrics.y_scale;
4868 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4870 FIXME("Can't find OS/2 table - not TT font?\n");
4875 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4877 FIXME("Can't find HHEA table - not TT font?\n");
4882 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
4884 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",
4885 pOS2->usWinAscent, pOS2->usWinDescent,
4886 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
4887 ft_face->ascender, ft_face->descender, ft_face->height,
4888 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
4889 ft_face->bbox.yMax, ft_face->bbox.yMin);
4891 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
4892 font->potm->otmSize = needed;
4894 #define TM font->potm->otmTextMetrics
4896 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
4897 ascent = pHori->Ascender;
4898 descent = -pHori->Descender;
4900 ascent = pOS2->usWinAscent;
4901 descent = pOS2->usWinDescent;
4905 TM.tmAscent = font->yMax;
4906 TM.tmDescent = -font->yMin;
4907 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
4909 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
4910 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
4911 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
4912 - ft_face->units_per_EM, y_scale) + 32) >> 6;
4915 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4918 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4920 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
4921 ((ascent + descent) -
4922 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
4924 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
4925 if (TM.tmAveCharWidth == 0) {
4926 TM.tmAveCharWidth = 1;
4928 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
4929 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
4931 TM.tmDigitizedAspectX = 300;
4932 TM.tmDigitizedAspectY = 300;
4933 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4934 * symbol range to 0 - f0ff
4936 if (font->charset == SYMBOL_CHARSET)
4939 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4943 TM.tmFirstChar = pOS2->usFirstCharIndex;
4944 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0xffff;
4946 TM.tmLastChar = pOS2->usLastCharIndex;
4947 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
4948 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4949 TM.tmUnderlined = font->underline;
4950 TM.tmStruckOut = font->strikeout;
4952 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4953 if(!FT_IS_FIXED_WIDTH(ft_face) &&
4954 (pOS2->version == 0xFFFFU ||
4955 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4956 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
4958 TM.tmPitchAndFamily = 0;
4960 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
4961 case PAN_FAMILY_SCRIPT:
4962 TM.tmPitchAndFamily |= FF_SCRIPT;
4964 case PAN_FAMILY_DECORATIVE:
4965 case PAN_FAMILY_PICTORIAL:
4966 TM.tmPitchAndFamily |= FF_DECORATIVE;
4968 case PAN_FAMILY_TEXT_DISPLAY:
4969 if(TM.tmPitchAndFamily == 0) /* fixed */
4970 TM.tmPitchAndFamily = FF_MODERN;
4972 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
4973 case PAN_SERIF_NORMAL_SANS:
4974 case PAN_SERIF_OBTUSE_SANS:
4975 case PAN_SERIF_PERP_SANS:
4976 TM.tmPitchAndFamily |= FF_SWISS;
4979 TM.tmPitchAndFamily |= FF_ROMAN;
4984 TM.tmPitchAndFamily |= FF_DONTCARE;
4987 if(FT_IS_SCALABLE(ft_face))
4988 TM.tmPitchAndFamily |= TMPF_VECTOR;
4990 if(FT_IS_SFNT(ft_face))
4992 if (font->ntmFlags & NTM_PS_OPENTYPE)
4993 TM.tmPitchAndFamily |= TMPF_DEVICE;
4995 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
4998 TM.tmCharSet = font->charset;
5001 font->potm->otmFiller = 0;
5002 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5003 font->potm->otmfsSelection = pOS2->fsSelection;
5004 font->potm->otmfsType = pOS2->fsType;
5005 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5006 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5007 font->potm->otmItalicAngle = 0; /* POST table */
5008 font->potm->otmEMSquare = ft_face->units_per_EM;
5009 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5010 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5011 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5012 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5013 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5014 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5015 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5016 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5017 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5018 font->potm->otmMacAscent = 0; /* where do these come from ? */
5019 font->potm->otmMacDescent = 0;
5020 font->potm->otmMacLineGap = 0;
5021 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5022 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5023 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5024 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5025 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5026 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5027 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5028 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5029 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5030 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5031 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5033 font->potm->otmsUnderscoreSize = 0;
5034 font->potm->otmsUnderscorePosition = 0;
5036 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5037 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5040 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5041 cp = (char*)font->potm + sizeof(*font->potm);
5042 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5043 strcpyW((WCHAR*)cp, family_nameW);
5045 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5046 strcpyW((WCHAR*)cp, style_nameW);
5048 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5049 strcpyW((WCHAR*)cp, family_nameW);
5050 if(strcasecmp(ft_face->style_name, "regular")) {
5051 strcatW((WCHAR*)cp, spaceW);
5052 strcatW((WCHAR*)cp, style_nameW);
5053 cp += lenfam + lensty;
5056 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5057 strcpyW((WCHAR*)cp, family_nameW);
5058 strcatW((WCHAR*)cp, spaceW);
5059 strcatW((WCHAR*)cp, style_nameW);
5062 if(potm && needed <= cbSize)
5064 memcpy(potm, font->potm, font->potm->otmSize);
5065 scale_font_metrics(font, &potm->otmTextMetrics);
5069 HeapFree(GetProcessHeap(), 0, style_nameW);
5070 HeapFree(GetProcessHeap(), 0, family_nameW);
5072 LeaveCriticalSection( &freetype_cs );
5076 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5078 HFONTLIST *hfontlist;
5079 child->font = alloc_font();
5080 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5081 if(!child->font->ft_face)
5083 free_font(child->font);
5088 child->font->ntmFlags = child->face->ntmFlags;
5089 child->font->orientation = font->orientation;
5090 child->font->scale_y = font->scale_y;
5091 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5092 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5093 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5094 child->font->base_font = font;
5095 list_add_head(&child_font_list, &child->font->entry);
5096 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5100 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5103 CHILD_FONT *child_font;
5106 font = font->base_font;
5108 *linked_font = font;
5110 if((*glyph = get_glyph_index(font, c)))
5113 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5115 if(!child_font->font)
5116 if(!load_child_font(font, child_font))
5119 if(!child_font->font->ft_face)
5121 g = get_glyph_index(child_font->font, c);
5125 *linked_font = child_font->font;
5132 /*************************************************************
5133 * WineEngGetCharWidth
5136 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5141 FT_UInt glyph_index;
5142 GdiFont *linked_font;
5144 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5146 EnterCriticalSection( &freetype_cs );
5147 for(c = firstChar; c <= lastChar; c++) {
5148 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5149 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5150 &gm, 0, NULL, NULL);
5151 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5153 LeaveCriticalSection( &freetype_cs );
5157 /*************************************************************
5158 * WineEngGetCharABCWidths
5161 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5166 FT_UInt glyph_index;
5167 GdiFont *linked_font;
5169 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5171 if(!FT_IS_SCALABLE(font->ft_face))
5174 EnterCriticalSection( &freetype_cs );
5176 for(c = firstChar; c <= lastChar; c++) {
5177 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5178 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5179 &gm, 0, NULL, NULL);
5180 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5181 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5182 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5183 FONT_GM(linked_font,glyph_index)->bbx;
5185 LeaveCriticalSection( &freetype_cs );
5189 /*************************************************************
5190 * WineEngGetCharABCWidthsI
5193 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5198 FT_UInt glyph_index;
5199 GdiFont *linked_font;
5201 if(!FT_HAS_HORIZONTAL(font->ft_face))
5204 EnterCriticalSection( &freetype_cs );
5206 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5208 for(c = firstChar; c < firstChar+count; c++) {
5209 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5210 &gm, 0, NULL, NULL);
5211 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5212 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5213 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5214 - FONT_GM(linked_font,c)->bbx;
5217 for(c = 0; c < count; c++) {
5218 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5219 &gm, 0, NULL, NULL);
5220 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5221 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5222 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5223 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5226 LeaveCriticalSection( &freetype_cs );
5230 /*************************************************************
5231 * WineEngGetTextExtentExPoint
5234 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5235 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5241 FT_UInt glyph_index;
5242 GdiFont *linked_font;
5244 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5247 EnterCriticalSection( &freetype_cs );
5250 WineEngGetTextMetrics(font, &tm);
5251 size->cy = tm.tmHeight;
5253 for(idx = 0; idx < count; idx++) {
5254 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5255 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5256 &gm, 0, NULL, NULL);
5257 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5259 if (! pnfit || ext <= max_ext) {
5269 LeaveCriticalSection( &freetype_cs );
5270 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5274 /*************************************************************
5275 * WineEngGetTextExtentExPointI
5278 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5279 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5286 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5288 EnterCriticalSection( &freetype_cs );
5291 WineEngGetTextMetrics(font, &tm);
5292 size->cy = tm.tmHeight;
5294 for(idx = 0; idx < count; idx++) {
5295 WineEngGetGlyphOutline(font, indices[idx],
5296 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
5298 size->cx += FONT_GM(font,indices[idx])->adv;
5300 if (! pnfit || ext <= max_ext) {
5310 LeaveCriticalSection( &freetype_cs );
5311 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5315 /*************************************************************
5316 * WineEngGetFontData
5319 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5322 FT_Face ft_face = font->ft_face;
5326 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5327 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
5328 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
5330 if(!FT_IS_SFNT(ft_face))
5338 if(table) { /* MS tags differ in endianness from FT ones */
5339 table = table >> 24 | table << 24 |
5340 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
5343 /* make sure value of len is the value freetype says it needs */
5346 FT_ULong needed = 0;
5347 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
5348 if( !err && needed < len) len = needed;
5350 err = load_sfnt_table(ft_face, table, offset, buf, &len);
5353 TRACE("Can't find table %c%c%c%c\n",
5354 /* bytes were reversed */
5355 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
5356 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
5362 /*************************************************************
5363 * WineEngGetTextFace
5366 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5369 lstrcpynW(str, font->name, count);
5370 return strlenW(font->name);
5372 return strlenW(font->name) + 1;
5375 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5377 if (fs) *fs = font->fs;
5378 return font->charset;
5381 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5383 GdiFont *font = dc->gdiFont, *linked_font;
5384 struct list *first_hfont;
5387 EnterCriticalSection( &freetype_cs );
5388 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
5389 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
5390 if(font == linked_font)
5391 *new_hfont = dc->hFont;
5394 first_hfont = list_head(&linked_font->hfontlist);
5395 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
5397 LeaveCriticalSection( &freetype_cs );
5401 /* Retrieve a list of supported Unicode ranges for a given font.
5402 * Can be called with NULL gs to calculate the buffer size. Returns
5403 * the number of ranges found.
5405 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
5407 DWORD num_ranges = 0;
5409 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5412 FT_ULong char_code, char_code_prev;
5415 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
5417 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5418 face->num_glyphs, glyph_code, char_code);
5420 if (!glyph_code) return 0;
5424 gs->ranges[0].wcLow = (USHORT)char_code;
5425 gs->ranges[0].cGlyphs = 0;
5426 gs->cGlyphsSupported = 0;
5432 if (char_code < char_code_prev)
5434 ERR("expected increasing char code from FT_Get_Next_Char\n");
5437 if (char_code - char_code_prev > 1)
5442 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5443 gs->ranges[num_ranges - 1].cGlyphs = 1;
5444 gs->cGlyphsSupported++;
5449 gs->ranges[num_ranges - 1].cGlyphs++;
5450 gs->cGlyphsSupported++;
5452 char_code_prev = char_code;
5453 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5457 FIXME("encoding %u not supported\n", face->charmap->encoding);
5462 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5465 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
5467 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5470 glyphset->cbThis = size;
5471 glyphset->cRanges = num_ranges;
5476 /*************************************************************
5479 BOOL WineEngFontIsLinked(GdiFont *font)
5482 EnterCriticalSection( &freetype_cs );
5483 ret = !list_empty(&font->child_fonts);
5484 LeaveCriticalSection( &freetype_cs );
5488 static BOOL is_hinting_enabled(void)
5490 /* Use the >= 2.2.0 function if available */
5491 if(pFT_Get_TrueType_Engine_Type)
5493 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
5494 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
5496 #ifdef FT_DRIVER_HAS_HINTER
5501 /* otherwise if we've been compiled with < 2.2.0 headers
5502 use the internal macro */
5503 mod = pFT_Get_Module(library, "truetype");
5504 if(mod && FT_DRIVER_HAS_HINTER(mod))
5512 /*************************************************************************
5513 * GetRasterizerCaps (GDI32.@)
5515 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5517 static int hinting = -1;
5521 hinting = is_hinting_enabled();
5522 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
5525 lprs->nSize = sizeof(RASTERIZER_STATUS);
5526 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
5527 lprs->nLanguageID = 0;
5531 /*************************************************************************
5532 * Kerning support for TrueType fonts
5534 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5536 struct TT_kern_table
5542 struct TT_kern_subtable
5551 USHORT horizontal : 1;
5553 USHORT cross_stream: 1;
5554 USHORT override : 1;
5555 USHORT reserved1 : 4;
5561 struct TT_format0_kern_subtable
5565 USHORT entrySelector;
5576 static DWORD parse_format0_kern_subtable(GdiFont *font,
5577 const struct TT_format0_kern_subtable *tt_f0_ks,
5578 const USHORT *glyph_to_char,
5579 KERNINGPAIR *kern_pair, DWORD cPairs)
5582 const struct TT_kern_pair *tt_kern_pair;
5584 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
5586 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
5588 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5589 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
5590 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
5592 if (!kern_pair || !cPairs)
5595 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
5597 nPairs = min(nPairs, cPairs);
5599 for (i = 0; i < nPairs; i++)
5601 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
5602 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
5603 /* this algorithm appears to better match what Windows does */
5604 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
5605 if (kern_pair->iKernAmount < 0)
5607 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
5608 kern_pair->iKernAmount -= font->ppem;
5610 else if (kern_pair->iKernAmount > 0)
5612 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
5613 kern_pair->iKernAmount += font->ppem;
5615 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
5617 TRACE("left %u right %u value %d\n",
5618 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
5622 TRACE("copied %u entries\n", nPairs);
5626 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5630 const struct TT_kern_table *tt_kern_table;
5631 const struct TT_kern_subtable *tt_kern_subtable;
5633 USHORT *glyph_to_char;
5635 EnterCriticalSection( &freetype_cs );
5636 if (font->total_kern_pairs != (DWORD)-1)
5638 if (cPairs && kern_pair)
5640 cPairs = min(cPairs, font->total_kern_pairs);
5641 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5642 LeaveCriticalSection( &freetype_cs );
5645 LeaveCriticalSection( &freetype_cs );
5646 return font->total_kern_pairs;
5649 font->total_kern_pairs = 0;
5651 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5653 if (length == GDI_ERROR)
5655 TRACE("no kerning data in the font\n");
5656 LeaveCriticalSection( &freetype_cs );
5660 buf = HeapAlloc(GetProcessHeap(), 0, length);
5663 WARN("Out of memory\n");
5664 LeaveCriticalSection( &freetype_cs );
5668 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5670 /* build a glyph index to char code map */
5671 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5674 WARN("Out of memory allocating a glyph index to char code map\n");
5675 HeapFree(GetProcessHeap(), 0, buf);
5676 LeaveCriticalSection( &freetype_cs );
5680 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5686 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5688 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5689 font->ft_face->num_glyphs, glyph_code, char_code);
5693 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5695 /* FIXME: This doesn't match what Windows does: it does some fancy
5696 * things with duplicate glyph index to char code mappings, while
5697 * we just avoid overriding existing entries.
5699 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5700 glyph_to_char[glyph_code] = (USHORT)char_code;
5702 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5709 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5710 for (n = 0; n <= 65535; n++)
5711 glyph_to_char[n] = (USHORT)n;
5714 tt_kern_table = buf;
5715 nTables = GET_BE_WORD(tt_kern_table->nTables);
5716 TRACE("version %u, nTables %u\n",
5717 GET_BE_WORD(tt_kern_table->version), nTables);
5719 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5721 for (i = 0; i < nTables; i++)
5723 struct TT_kern_subtable tt_kern_subtable_copy;
5725 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5726 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5727 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5729 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5730 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
5731 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
5733 /* According to the TrueType specification this is the only format
5734 * that will be properly interpreted by Windows and OS/2
5736 if (tt_kern_subtable_copy.coverage.bits.format == 0)
5738 DWORD new_chunk, old_total = font->total_kern_pairs;
5740 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5741 glyph_to_char, NULL, 0);
5742 font->total_kern_pairs += new_chunk;
5744 if (!font->kern_pairs)
5745 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
5746 font->total_kern_pairs * sizeof(*font->kern_pairs));
5748 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
5749 font->total_kern_pairs * sizeof(*font->kern_pairs));
5751 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5752 glyph_to_char, font->kern_pairs + old_total, new_chunk);
5755 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
5757 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
5760 HeapFree(GetProcessHeap(), 0, glyph_to_char);
5761 HeapFree(GetProcessHeap(), 0, buf);
5763 if (cPairs && kern_pair)
5765 cPairs = min(cPairs, font->total_kern_pairs);
5766 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5767 LeaveCriticalSection( &freetype_cs );
5770 LeaveCriticalSection( &freetype_cs );
5771 return font->total_kern_pairs;
5774 #else /* HAVE_FREETYPE */
5776 /*************************************************************************/
5778 BOOL WineEngInit(void)
5782 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
5786 BOOL WineEngDestroyFontInstance(HFONT hfont)
5791 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
5796 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
5797 LPWORD pgi, DWORD flags)
5802 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
5803 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5806 ERR("called but we don't have FreeType\n");
5810 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5812 ERR("called but we don't have FreeType\n");
5816 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5817 OUTLINETEXTMETRICW *potm)
5819 ERR("called but we don't have FreeType\n");
5823 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5826 ERR("called but we don't have FreeType\n");
5830 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5833 ERR("called but we don't have FreeType\n");
5837 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5840 ERR("called but we don't have FreeType\n");
5844 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5845 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5847 ERR("called but we don't have FreeType\n");
5851 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5852 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5854 ERR("called but we don't have FreeType\n");
5858 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5861 ERR("called but we don't have FreeType\n");
5865 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5867 ERR("called but we don't have FreeType\n");
5871 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5877 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5883 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
5889 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5892 return DEFAULT_CHARSET;
5895 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5900 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5902 FIXME("(%p, %p): stub\n", font, glyphset);
5906 BOOL WineEngFontIsLinked(GdiFont *font)
5911 /*************************************************************************
5912 * GetRasterizerCaps (GDI32.@)
5914 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5916 lprs->nSize = sizeof(RASTERIZER_STATUS);
5918 lprs->nLanguageID = 0;
5922 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5924 ERR("called but we don't have FreeType\n");
5928 #endif /* HAVE_FREETYPE */