2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
40 #ifdef HAVE_CARBON_CARBON_H
41 #define LoadResource __carbon_LoadResource
42 #define CompareString __carbon_CompareString
43 #define GetCurrentThread __carbon_GetCurrentThread
44 #define GetCurrentProcess __carbon_GetCurrentProcess
45 #define AnimatePalette __carbon_AnimatePalette
46 #define EqualRgn __carbon_EqualRgn
47 #define FillRgn __carbon_FillRgn
48 #define FrameRgn __carbon_FrameRgn
49 #define GetPixel __carbon_GetPixel
50 #define InvertRgn __carbon_InvertRgn
51 #define LineTo __carbon_LineTo
52 #define OffsetRgn __carbon_OffsetRgn
53 #define PaintRgn __carbon_PaintRgn
54 #define Polygon __carbon_Polygon
55 #define ResizePalette __carbon_ResizePalette
56 #define SetRectRgn __carbon_SetRectRgn
57 #include <Carbon/Carbon.h>
60 #undef GetCurrentThread
63 #undef GetCurrentProcess
76 #endif /* HAVE_CARBON_CARBON_H */
84 #include "gdi_private.h"
85 #include "wine/unicode.h"
86 #include "wine/debug.h"
87 #include "wine/list.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(font);
93 #ifdef HAVE_FT2BUILD_H
96 #ifdef HAVE_FREETYPE_FREETYPE_H
97 #include <freetype/freetype.h>
99 #ifdef HAVE_FREETYPE_FTGLYPH_H
100 #include <freetype/ftglyph.h>
102 #ifdef HAVE_FREETYPE_TTTABLES_H
103 #include <freetype/tttables.h>
105 #ifdef HAVE_FREETYPE_FTTYPES_H
106 #include <freetype/fttypes.h>
108 #ifdef HAVE_FREETYPE_FTSNAMES_H
109 #include <freetype/ftsnames.h>
111 # ifdef HAVE_FREETYPE_FTNAMES_H
112 # include <freetype/ftnames.h>
115 #ifdef HAVE_FREETYPE_TTNAMEID_H
116 #include <freetype/ttnameid.h>
118 #ifdef HAVE_FREETYPE_FTOUTLN_H
119 #include <freetype/ftoutln.h>
121 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
122 #include <freetype/internal/sfnt.h>
124 #ifdef HAVE_FREETYPE_FTTRIGON_H
125 #include <freetype/fttrigon.h>
127 #ifdef HAVE_FREETYPE_FTWINFNT_H
128 #include <freetype/ftwinfnt.h>
130 #ifdef HAVE_FREETYPE_FTMODAPI_H
131 #include <freetype/ftmodapi.h>
134 #ifndef HAVE_FT_TRUETYPEENGINETYPE
137 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
138 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
139 FT_TRUETYPE_ENGINE_TYPE_PATENTED
140 } FT_TrueTypeEngineType;
143 static FT_Library library = 0;
150 static FT_Version_t FT_Version;
151 static DWORD FT_SimpleVersion;
153 static void *ft_handle = NULL;
155 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
156 MAKE_FUNCPTR(FT_Vector_Unit);
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_Module);
160 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
163 MAKE_FUNCPTR(FT_Init_FreeType);
164 MAKE_FUNCPTR(FT_Load_Glyph);
165 MAKE_FUNCPTR(FT_Matrix_Multiply);
166 MAKE_FUNCPTR(FT_MulFix);
167 MAKE_FUNCPTR(FT_New_Face);
168 MAKE_FUNCPTR(FT_New_Memory_Face);
169 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
170 MAKE_FUNCPTR(FT_Outline_Transform);
171 MAKE_FUNCPTR(FT_Outline_Translate);
172 MAKE_FUNCPTR(FT_Select_Charmap);
173 MAKE_FUNCPTR(FT_Set_Charmap);
174 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
175 MAKE_FUNCPTR(FT_Vector_Transform);
176 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
177 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
178 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
179 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
180 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
181 #ifdef HAVE_FREETYPE_FTWINFNT_H
182 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
185 #ifdef SONAME_LIBFONTCONFIG
186 #include <fontconfig/fontconfig.h>
187 MAKE_FUNCPTR(FcConfigGetCurrent);
188 MAKE_FUNCPTR(FcFontList);
189 MAKE_FUNCPTR(FcFontSetDestroy);
190 MAKE_FUNCPTR(FcInit);
191 MAKE_FUNCPTR(FcObjectSetAdd);
192 MAKE_FUNCPTR(FcObjectSetCreate);
193 MAKE_FUNCPTR(FcObjectSetDestroy);
194 MAKE_FUNCPTR(FcPatternCreate);
195 MAKE_FUNCPTR(FcPatternDestroy);
196 MAKE_FUNCPTR(FcPatternGetBool);
197 MAKE_FUNCPTR(FcPatternGetString);
203 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
204 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
205 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
208 #ifndef ft_encoding_none
209 #define FT_ENCODING_NONE ft_encoding_none
211 #ifndef ft_encoding_ms_symbol
212 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
214 #ifndef ft_encoding_unicode
215 #define FT_ENCODING_UNICODE ft_encoding_unicode
217 #ifndef ft_encoding_apple_roman
218 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
221 #ifdef WORDS_BIGENDIAN
222 #define GET_BE_WORD(x) (x)
224 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
227 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
234 FT_Short internal_leading;
237 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
238 So to let this compile on older versions of FreeType we'll define the
239 new structure here. */
241 FT_Short height, width;
242 FT_Pos size, x_ppem, y_ppem;
248 NEWTEXTMETRICEXW ntm;
252 typedef struct tagFace {
257 DWORD font_data_size;
260 FONTSIGNATURE fs_links;
262 FT_Fixed font_version;
264 Bitmap_Size size; /* set if face is a bitmap */
265 BOOL external; /* TRUE if we should manually add this font to the registry */
266 struct tagFamily *family;
267 /* Cached data for Enum */
268 struct enum_data *cached_enum_data;
271 typedef struct tagFamily {
273 const WCHAR *FamilyName;
279 INT adv; /* These three hold to widths of the unrotated chars */
297 typedef struct tagHFONTLIST {
312 struct list hfontlist;
313 OUTLINETEXTMETRICW *potm;
314 DWORD total_kern_pairs;
315 KERNINGPAIR *kern_pairs;
316 struct list child_fonts;
318 /* the following members can be accessed without locking, they are never modified after creation */
320 struct font_mapping *mapping;
342 const WCHAR *font_name;
346 #define GM_BLOCK_SIZE 128
347 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
349 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
350 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
351 #define UNUSED_CACHE_SIZE 10
352 static struct list child_font_list = LIST_INIT(child_font_list);
353 static struct list system_links = LIST_INIT(system_links);
355 static struct list font_subst_list = LIST_INIT(font_subst_list);
357 static struct list font_list = LIST_INIT(font_list);
359 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
360 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
361 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
363 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
365 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
366 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
367 'W','i','n','d','o','w','s','\\',
368 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
369 'F','o','n','t','s','\0'};
371 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
372 'W','i','n','d','o','w','s',' ','N','T','\\',
373 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
374 'F','o','n','t','s','\0'};
376 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
377 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
378 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
379 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
381 static const WCHAR * const SystemFontValues[4] = {
388 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
389 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
391 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
392 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
393 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
394 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
395 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
396 'E','u','r','o','p','e','a','n','\0'};
397 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
398 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
399 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
400 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
401 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
402 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
403 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
404 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
405 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
406 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
407 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
408 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
410 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
420 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
428 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
437 typedef struct tagFontSubst {
453 static struct list mappings_list = LIST_INIT( mappings_list );
455 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
457 static CRITICAL_SECTION freetype_cs;
458 static CRITICAL_SECTION_DEBUG critsect_debug =
461 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
462 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
464 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
466 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
468 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
469 static BOOL use_default_fallback = FALSE;
471 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
473 /****************************************
474 * Notes on .fon files
476 * The fonts System, FixedSys and Terminal are special. There are typically multiple
477 * versions installed for different resolutions and codepages. Windows stores which one to use
478 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
480 * FIXEDFON.FON FixedSys
482 * OEMFONT.FON Terminal
483 * LogPixels Current dpi set by the display control panel applet
484 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
485 * also has a LogPixels value that appears to mirror this)
487 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
488 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
489 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
490 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
491 * so that makes sense.
493 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
494 * to be mapped into the registry on Windows 2000 at least).
497 * ega80woa.fon=ega80850.fon
498 * ega40woa.fon=ega40850.fon
499 * cga80woa.fon=cga80850.fon
500 * cga40woa.fon=cga40850.fon
503 /* These are all structures needed for the GSUB table */
505 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
506 #define TATEGAKI_LOWER_BOUND 0x02F1
522 GSUB_ScriptRecord ScriptRecord[1];
528 } GSUB_LangSysRecord;
533 GSUB_LangSysRecord LangSysRecord[1];
537 WORD LookupOrder; /* Reserved */
538 WORD ReqFeatureIndex;
540 WORD FeatureIndex[1];
546 } GSUB_FeatureRecord;
550 GSUB_FeatureRecord FeatureRecord[1];
554 WORD FeatureParams; /* Reserved */
556 WORD LookupListIndex[1];
575 } GSUB_CoverageFormat1;
580 WORD StartCoverageIndex;
586 GSUB_RangeRecord RangeRecord[1];
587 } GSUB_CoverageFormat2;
590 WORD SubstFormat; /* = 1 */
593 } GSUB_SingleSubstFormat1;
596 WORD SubstFormat; /* = 2 */
600 }GSUB_SingleSubstFormat2;
602 #ifdef HAVE_CARBON_CARBON_H
603 static char *find_cache_dir(void)
607 static char cached_path[MAX_PATH];
608 static const char *wine = "/Wine", *fonts = "/Fonts";
610 if(*cached_path) return cached_path;
612 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
615 WARN("can't create cached data folder\n");
618 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
621 WARN("can't create cached data path\n");
625 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
627 ERR("Could not create full path\n");
631 strcat(cached_path, wine);
633 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
635 WARN("Couldn't mkdir %s\n", cached_path);
639 strcat(cached_path, fonts);
640 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
642 WARN("Couldn't mkdir %s\n", cached_path);
649 /******************************************************************
652 * Extracts individual TrueType font files from a Mac suitcase font
653 * and saves them into the user's caches directory (see
655 * Returns a NULL terminated array of filenames.
657 * We do this because they are apps that try to read ttf files
658 * themselves and they don't like Mac suitcase files.
660 static char **expand_mac_font(const char *path)
667 const char *filename;
671 unsigned int size, max_size;
674 TRACE("path %s\n", path);
676 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
679 WARN("failed to get ref\n");
683 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
686 TRACE("no data fork, so trying resource fork\n");
687 res_ref = FSOpenResFile(&ref, fsRdPerm);
690 TRACE("unable to open resource fork\n");
697 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
700 CloseResFile(res_ref);
704 out_dir = find_cache_dir();
706 filename = strrchr(path, '/');
707 if(!filename) filename = path;
710 /* output filename has the form out_dir/filename_%04x.ttf */
711 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
718 unsigned short *num_faces_ptr, num_faces, face;
721 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
723 fond = Get1IndResource(fond_res, idx);
725 TRACE("got fond resource %d\n", idx);
728 fam_rec = *(FamRec**)fond;
729 num_faces_ptr = (unsigned short *)(fam_rec + 1);
730 num_faces = GET_BE_WORD(*num_faces_ptr);
732 assoc = (AsscEntry*)(num_faces_ptr + 1);
733 TRACE("num faces %04x\n", num_faces);
734 for(face = 0; face < num_faces; face++, assoc++)
737 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
738 unsigned short size, font_id;
741 size = GET_BE_WORD(assoc->fontSize);
742 font_id = GET_BE_WORD(assoc->fontID);
745 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
749 TRACE("trying to load sfnt id %04x\n", font_id);
750 sfnt = GetResource(sfnt_res, font_id);
753 TRACE("can't get sfnt resource %04x\n", font_id);
757 output = HeapAlloc(GetProcessHeap(), 0, output_len);
762 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
764 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
765 if(fd != -1 || errno == EEXIST)
769 unsigned char *sfnt_data;
772 sfnt_data = *(unsigned char**)sfnt;
773 write(fd, sfnt_data, GetHandleSize(sfnt));
777 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
780 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
782 ret.array[ret.size++] = output;
786 WARN("unable to create %s\n", output);
787 HeapFree(GetProcessHeap(), 0, output);
790 ReleaseResource(sfnt);
793 ReleaseResource(fond);
796 CloseResFile(res_ref);
801 #endif /* HAVE_CARBON_CARBON_H */
803 static inline BOOL is_win9x(void)
805 return GetVersion() & 0x80000000;
808 This function builds an FT_Fixed from a float. It puts the integer part
809 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
810 It fails if the integer part of the float number is greater than SHORT_MAX.
812 static inline FT_Fixed FT_FixedFromFloat(float f)
815 unsigned short fract = (f - value) * 0xFFFF;
816 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
820 This function builds an FT_Fixed from a FIXED. It simply put f.value
821 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
823 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
825 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
829 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
834 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
835 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
837 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
838 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
840 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
842 if(face_name && strcmpiW(face_name, family->FamilyName))
844 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
848 file = strrchr(face->file, '/');
853 if(!strcasecmp(file, file_nameA))
855 HeapFree(GetProcessHeap(), 0, file_nameA);
860 HeapFree(GetProcessHeap(), 0, file_nameA);
864 static Family *find_family_from_name(const WCHAR *name)
868 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
870 if(!strcmpiW(family->FamilyName, name))
877 static void DumpSubstList(void)
881 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
883 if(psub->from.charset != -1 || psub->to.charset != -1)
884 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
885 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
887 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
888 debugstr_w(psub->to.name));
893 static LPWSTR strdupW(LPCWSTR p)
896 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
897 ret = HeapAlloc(GetProcessHeap(), 0, len);
902 static LPSTR strdupA(LPCSTR p)
905 DWORD len = (strlen(p) + 1);
906 ret = HeapAlloc(GetProcessHeap(), 0, len);
911 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
916 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
918 if(!strcmpiW(element->from.name, from_name) &&
919 (element->from.charset == from_charset ||
920 element->from.charset == -1))
927 #define ADD_FONT_SUBST_FORCE 1
929 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
931 FontSubst *from_exist, *to_exist;
933 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
935 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
937 list_remove(&from_exist->entry);
938 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
939 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
940 HeapFree(GetProcessHeap(), 0, from_exist);
946 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
950 HeapFree(GetProcessHeap(), 0, subst->to.name);
951 subst->to.name = strdupW(to_exist->to.name);
954 list_add_tail(subst_list, &subst->entry);
959 HeapFree(GetProcessHeap(), 0, subst->from.name);
960 HeapFree(GetProcessHeap(), 0, subst->to.name);
961 HeapFree(GetProcessHeap(), 0, subst);
965 static void split_subst_info(NameCs *nc, LPSTR str)
967 CHAR *p = strrchr(str, ',');
972 nc->charset = strtol(p+1, NULL, 10);
975 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
976 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
977 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
980 static void LoadSubstList(void)
984 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
988 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
989 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
990 &hkey) == ERROR_SUCCESS) {
992 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
993 &valuelen, &datalen, NULL, NULL);
995 valuelen++; /* returned value doesn't include room for '\0' */
996 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
997 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1001 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1002 &dlen) == ERROR_SUCCESS) {
1003 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1005 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1006 split_subst_info(&psub->from, value);
1007 split_subst_info(&psub->to, data);
1009 /* Win 2000 doesn't allow mapping between different charsets
1010 or mapping of DEFAULT_CHARSET */
1011 if((psub->to.charset != psub->from.charset) ||
1012 psub->to.charset == DEFAULT_CHARSET) {
1013 HeapFree(GetProcessHeap(), 0, psub->to.name);
1014 HeapFree(GetProcessHeap(), 0, psub->from.name);
1015 HeapFree(GetProcessHeap(), 0, psub);
1017 add_font_subst(&font_subst_list, psub, 0);
1019 /* reset dlen and vlen */
1023 HeapFree(GetProcessHeap(), 0, data);
1024 HeapFree(GetProcessHeap(), 0, value);
1029 static WCHAR *get_familyname(FT_Face ft_face)
1031 WCHAR *family = NULL;
1033 FT_UInt num_names, name_index, i;
1035 if(FT_IS_SFNT(ft_face))
1037 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1039 for(name_index = 0; name_index < num_names; name_index++)
1041 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1043 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
1044 (name.language_id == GetUserDefaultLCID()) &&
1045 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
1046 (name.encoding_id == TT_MS_ID_UNICODE_CS))
1048 /* String is not nul terminated and string_len is a byte length. */
1049 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1050 for(i = 0; i < name.string_len / 2; i++)
1052 WORD *tmp = (WORD *)&name.string[i * 2];
1053 family[i] = GET_BE_WORD(*tmp);
1057 TRACE("Got localised name %s\n", debugstr_w(family));
1068 /*****************************************************************
1071 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1072 * of FreeType that don't export this function.
1075 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1080 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1081 if(pFT_Load_Sfnt_Table)
1083 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1085 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1086 else /* Do it the hard way */
1088 TT_Face tt_face = (TT_Face) ft_face;
1089 SFNT_Interface *sfnt;
1090 if (FT_Version.major==2 && FT_Version.minor==0)
1093 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1097 /* A field was added in the middle of the structure in 2.1.x */
1098 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1100 err = sfnt->load_any(tt_face, table, offset, buf, len);
1108 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1109 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1110 "Please upgrade your freetype library.\n");
1113 err = FT_Err_Unimplemented_Feature;
1120 #define ADDFONT_EXTERNAL_FONT 0x01
1121 #define ADDFONT_FORCE_BITMAP 0x02
1122 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1126 TT_Header *pHeader = NULL;
1127 WCHAR *english_family, *localised_family, *StyleW;
1131 struct list *family_elem_ptr, *face_elem_ptr;
1133 FT_Long face_index = 0, num_faces;
1134 #ifdef HAVE_FREETYPE_FTWINFNT_H
1135 FT_WinFNT_HeaderRec winfnt_header;
1137 int i, bitmap_num, internal_leading;
1140 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1141 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1143 #ifdef HAVE_CARBON_CARBON_H
1144 if(file && !fake_family)
1146 char **mac_list = expand_mac_font(file);
1149 BOOL had_one = FALSE;
1151 for(cursor = mac_list; *cursor; cursor++)
1154 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1155 HeapFree(GetProcessHeap(), 0, *cursor);
1157 HeapFree(GetProcessHeap(), 0, mac_list);
1162 #endif /* HAVE_CARBON_CARBON_H */
1165 char *family_name = fake_family;
1169 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1170 err = pFT_New_Face(library, file, face_index, &ft_face);
1173 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1174 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1178 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1182 if(!FT_IS_SFNT(ft_face) && (FT_IS_SCALABLE(ft_face) || !(flags & ADDFONT_FORCE_BITMAP))) { /* for now we'll accept TT/OT or bitmap fonts*/
1183 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1184 pFT_Done_Face(ft_face);
1188 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1189 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1190 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1191 pFT_Done_Face(ft_face);
1195 if(FT_IS_SFNT(ft_face))
1197 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1198 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1199 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1201 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1202 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1203 pFT_Done_Face(ft_face);
1207 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1208 we don't want to load these. */
1209 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1213 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1215 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1216 pFT_Done_Face(ft_face);
1222 if(!ft_face->family_name || !ft_face->style_name) {
1223 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1224 pFT_Done_Face(ft_face);
1228 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1230 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1231 pFT_Done_Face(ft_face);
1237 localised_family = get_familyname(ft_face);
1238 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1240 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1241 HeapFree(GetProcessHeap(), 0, localised_family);
1242 num_faces = ft_face->num_faces;
1243 pFT_Done_Face(ft_face);
1246 HeapFree(GetProcessHeap(), 0, localised_family);
1250 family_name = ft_face->family_name;
1254 My_FT_Bitmap_Size *size = NULL;
1257 if(!FT_IS_SCALABLE(ft_face))
1258 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1260 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1261 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1262 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1264 localised_family = NULL;
1266 localised_family = get_familyname(ft_face);
1267 if(localised_family && !strcmpW(localised_family, english_family)) {
1268 HeapFree(GetProcessHeap(), 0, localised_family);
1269 localised_family = NULL;
1274 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1275 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1276 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1281 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1282 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1283 list_init(&family->faces);
1284 list_add_tail(&font_list, &family->entry);
1286 if(localised_family) {
1287 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1288 subst->from.name = strdupW(english_family);
1289 subst->from.charset = -1;
1290 subst->to.name = strdupW(localised_family);
1291 subst->to.charset = -1;
1292 add_font_subst(&font_subst_list, subst, 0);
1295 HeapFree(GetProcessHeap(), 0, localised_family);
1296 HeapFree(GetProcessHeap(), 0, english_family);
1298 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1299 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1300 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1302 internal_leading = 0;
1303 memset(&fs, 0, sizeof(fs));
1305 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1307 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1308 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1309 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1310 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1311 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1312 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1313 if(pOS2->version == 0) {
1316 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1317 fs.fsCsb[0] |= FS_LATIN1;
1319 fs.fsCsb[0] |= FS_SYMBOL;
1322 #ifdef HAVE_FREETYPE_FTWINFNT_H
1323 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1325 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1326 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1327 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1329 internal_leading = winfnt_header.internal_leading;
1333 face_elem_ptr = list_head(&family->faces);
1334 while(face_elem_ptr) {
1335 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1336 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1337 if(!strcmpW(face->StyleName, StyleW) &&
1338 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1339 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1340 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1341 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1344 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1345 HeapFree(GetProcessHeap(), 0, StyleW);
1346 pFT_Done_Face(ft_face);
1349 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1350 TRACE("Original font is newer so skipping this one\n");
1351 HeapFree(GetProcessHeap(), 0, StyleW);
1352 pFT_Done_Face(ft_face);
1355 TRACE("Replacing original with this one\n");
1356 list_remove(&face->entry);
1357 HeapFree(GetProcessHeap(), 0, face->file);
1358 HeapFree(GetProcessHeap(), 0, face->StyleName);
1359 HeapFree(GetProcessHeap(), 0, face);
1364 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1365 face->cached_enum_data = NULL;
1366 list_add_tail(&family->faces, &face->entry);
1367 face->StyleName = StyleW;
1370 face->file = strdupA(file);
1371 face->font_data_ptr = NULL;
1372 face->font_data_size = 0;
1377 face->font_data_ptr = font_data_ptr;
1378 face->font_data_size = font_data_size;
1380 face->face_index = face_index;
1382 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1383 face->ntmFlags |= NTM_ITALIC;
1384 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1385 face->ntmFlags |= NTM_BOLD;
1386 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1387 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1388 face->family = family;
1389 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1391 memset(&face->fs_links, 0, sizeof(face->fs_links));
1393 if(FT_IS_SCALABLE(ft_face)) {
1394 memset(&face->size, 0, sizeof(face->size));
1395 face->scalable = TRUE;
1397 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1398 size->height, size->width, size->size >> 6,
1399 size->x_ppem >> 6, size->y_ppem >> 6);
1400 face->size.height = size->height;
1401 face->size.width = size->width;
1402 face->size.size = size->size;
1403 face->size.x_ppem = size->x_ppem;
1404 face->size.y_ppem = size->y_ppem;
1405 face->size.internal_leading = internal_leading;
1406 face->scalable = FALSE;
1409 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1411 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1413 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1414 face->ntmFlags |= NTM_PS_OPENTYPE;
1417 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1418 face->fs.fsCsb[0], face->fs.fsCsb[1],
1419 face->fs.fsUsb[0], face->fs.fsUsb[1],
1420 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1423 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1424 for(i = 0; i < ft_face->num_charmaps; i++) {
1425 switch(ft_face->charmaps[i]->encoding) {
1426 case FT_ENCODING_UNICODE:
1427 case FT_ENCODING_APPLE_ROMAN:
1428 face->fs.fsCsb[0] |= FS_LATIN1;
1430 case FT_ENCODING_MS_SYMBOL:
1431 face->fs.fsCsb[0] |= FS_SYMBOL;
1439 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1440 have_installed_roman_font = TRUE;
1441 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1443 num_faces = ft_face->num_faces;
1444 pFT_Done_Face(ft_face);
1445 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1446 debugstr_w(StyleW));
1447 } while(num_faces > ++face_index);
1451 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1453 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1456 static void DumpFontList(void)
1460 struct list *family_elem_ptr, *face_elem_ptr;
1462 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1463 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1464 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1465 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1466 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1467 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1469 TRACE(" %d", face->size.height);
1476 /***********************************************************
1477 * The replacement list is a way to map an entire font
1478 * family onto another family. For example adding
1480 * [HKCU\Software\Wine\Fonts\Replacements]
1481 * "Wingdings"="Winedings"
1483 * would enumerate the Winedings font both as Winedings and
1484 * Wingdings. However if a real Wingdings font is present the
1485 * replacement does not take place.
1488 static void LoadReplaceList(void)
1491 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1496 struct list *family_elem_ptr, *face_elem_ptr;
1499 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1500 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1502 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1503 &valuelen, &datalen, NULL, NULL);
1505 valuelen++; /* returned value doesn't include room for '\0' */
1506 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1507 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1511 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1512 &dlen) == ERROR_SUCCESS) {
1513 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1514 /* "NewName"="Oldname" */
1515 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1517 /* Find the old family and hence all of the font files
1519 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1520 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1521 if(!strcmpiW(family->FamilyName, data)) {
1522 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1523 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1524 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1525 debugstr_w(face->StyleName), familyA);
1526 /* Now add a new entry with the new family name */
1527 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1532 /* reset dlen and vlen */
1536 HeapFree(GetProcessHeap(), 0, data);
1537 HeapFree(GetProcessHeap(), 0, value);
1542 /*************************************************************
1545 static BOOL init_system_links(void)
1547 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1548 'W','i','n','d','o','w','s',' ','N','T','\\',
1549 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1550 'S','y','s','t','e','m','L','i','n','k',0};
1553 DWORD type, max_val, max_data, val_len, data_len, index;
1554 WCHAR *value, *data;
1555 WCHAR *entry, *next;
1556 SYSTEM_LINKS *font_link, *system_font_link;
1557 CHILD_FONT *child_font;
1558 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1559 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1560 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1566 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1568 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1569 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1570 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1571 val_len = max_val + 1;
1572 data_len = max_data;
1574 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1576 TRACE("%s:\n", debugstr_w(value));
1578 memset(&fs, 0, sizeof(fs));
1579 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1580 psub = get_font_subst(&font_subst_list, value, -1);
1581 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1582 list_init(&font_link->links);
1583 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1586 CHILD_FONT *child_font;
1588 TRACE("\t%s\n", debugstr_w(entry));
1590 next = entry + strlenW(entry) + 1;
1592 face_name = strchrW(entry, ',');
1596 while(isspaceW(*face_name))
1599 psub = get_font_subst(&font_subst_list, face_name, -1);
1601 face_name = psub->to.name;
1603 face = find_face_from_filename(entry, face_name);
1606 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1610 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1611 child_font->face = face;
1612 child_font->font = NULL;
1613 fs.fsCsb[0] |= face->fs.fsCsb[0];
1614 fs.fsCsb[1] |= face->fs.fsCsb[1];
1615 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1616 list_add_tail(&font_link->links, &child_font->entry);
1618 family = find_family_from_name(font_link->font_name);
1621 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1623 face->fs_links = fs;
1626 list_add_tail(&system_links, &font_link->entry);
1627 val_len = max_val + 1;
1628 data_len = max_data;
1631 HeapFree(GetProcessHeap(), 0, value);
1632 HeapFree(GetProcessHeap(), 0, data);
1636 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1639 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1640 system_font_link->font_name = strdupW(System);
1641 list_init(&system_font_link->links);
1643 face = find_face_from_filename(tahoma_ttf, Tahoma);
1646 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1647 child_font->face = face;
1648 child_font->font = NULL;
1649 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1650 list_add_tail(&system_font_link->links, &child_font->entry);
1652 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1654 if(!strcmpiW(font_link->font_name, Tahoma))
1656 CHILD_FONT *font_link_entry;
1657 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1659 CHILD_FONT *new_child;
1660 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1661 new_child->face = font_link_entry->face;
1662 new_child->font = NULL;
1663 list_add_tail(&system_font_link->links, &new_child->entry);
1668 list_add_tail(&system_links, &system_font_link->entry);
1672 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1675 struct dirent *dent;
1676 char path[MAX_PATH];
1678 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1680 dir = opendir(dirname);
1682 WARN("Can't open directory %s\n", debugstr_a(dirname));
1685 while((dent = readdir(dir)) != NULL) {
1686 struct stat statbuf;
1688 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1691 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1693 sprintf(path, "%s/%s", dirname, dent->d_name);
1695 if(stat(path, &statbuf) == -1)
1697 WARN("Can't stat %s\n", debugstr_a(path));
1700 if(S_ISDIR(statbuf.st_mode))
1701 ReadFontDir(path, external_fonts);
1703 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1709 static void load_fontconfig_fonts(void)
1711 #ifdef SONAME_LIBFONTCONFIG
1712 void *fc_handle = NULL;
1721 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1723 TRACE("Wine cannot find the fontconfig library (%s).\n",
1724 SONAME_LIBFONTCONFIG);
1727 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1728 LOAD_FUNCPTR(FcConfigGetCurrent);
1729 LOAD_FUNCPTR(FcFontList);
1730 LOAD_FUNCPTR(FcFontSetDestroy);
1731 LOAD_FUNCPTR(FcInit);
1732 LOAD_FUNCPTR(FcObjectSetAdd);
1733 LOAD_FUNCPTR(FcObjectSetCreate);
1734 LOAD_FUNCPTR(FcObjectSetDestroy);
1735 LOAD_FUNCPTR(FcPatternCreate);
1736 LOAD_FUNCPTR(FcPatternDestroy);
1737 LOAD_FUNCPTR(FcPatternGetBool);
1738 LOAD_FUNCPTR(FcPatternGetString);
1741 if(!pFcInit()) return;
1743 config = pFcConfigGetCurrent();
1744 pat = pFcPatternCreate();
1745 os = pFcObjectSetCreate();
1746 pFcObjectSetAdd(os, FC_FILE);
1747 pFcObjectSetAdd(os, FC_SCALABLE);
1748 fontset = pFcFontList(config, pat, os);
1749 if(!fontset) return;
1750 for(i = 0; i < fontset->nfont; i++) {
1753 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1755 TRACE("fontconfig: %s\n", file);
1757 /* We're just interested in OT/TT fonts for now, so this hack just
1758 picks up the scalable fonts without extensions .pf[ab] to save time
1759 loading every other font */
1761 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1763 TRACE("not scalable\n");
1767 len = strlen( file );
1768 if(len < 4) continue;
1769 ext = &file[ len - 3 ];
1770 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1771 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1773 pFcFontSetDestroy(fontset);
1774 pFcObjectSetDestroy(os);
1775 pFcPatternDestroy(pat);
1781 static BOOL load_font_from_data_dir(LPCWSTR file)
1784 const char *data_dir = wine_get_data_dir();
1786 if (!data_dir) data_dir = wine_get_build_dir();
1793 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1795 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1797 strcpy(unix_name, data_dir);
1798 strcat(unix_name, "/fonts/");
1800 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1802 EnterCriticalSection( &freetype_cs );
1803 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1804 LeaveCriticalSection( &freetype_cs );
1805 HeapFree(GetProcessHeap(), 0, unix_name);
1810 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1812 static const WCHAR slashW[] = {'\\','\0'};
1814 WCHAR windowsdir[MAX_PATH];
1817 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1818 strcatW(windowsdir, fontsW);
1819 strcatW(windowsdir, slashW);
1820 strcatW(windowsdir, file);
1821 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1822 EnterCriticalSection( &freetype_cs );
1823 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1824 LeaveCriticalSection( &freetype_cs );
1825 HeapFree(GetProcessHeap(), 0, unixname);
1830 static void load_system_fonts(void)
1833 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1834 const WCHAR * const *value;
1836 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1839 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1840 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1841 strcatW(windowsdir, fontsW);
1842 for(value = SystemFontValues; *value; value++) {
1843 dlen = sizeof(data);
1844 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1848 sprintfW(pathW, fmtW, windowsdir, data);
1849 if((unixname = wine_get_unix_file_name(pathW))) {
1850 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1851 HeapFree(GetProcessHeap(), 0, unixname);
1854 load_font_from_data_dir(data);
1861 /*************************************************************
1863 * This adds registry entries for any externally loaded fonts
1864 * (fonts from fontconfig or FontDirs). It also deletes entries
1865 * of no longer existing fonts.
1868 static void update_reg_entries(void)
1870 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1875 struct list *family_elem_ptr, *face_elem_ptr;
1877 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1878 static const WCHAR spaceW[] = {' ', '\0'};
1881 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1882 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1883 ERR("Can't create Windows font reg key\n");
1887 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1888 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1889 ERR("Can't create Windows font reg key\n");
1893 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1894 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1895 ERR("Can't create external font reg key\n");
1899 /* enumerate the fonts and add external ones to the two keys */
1901 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1902 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1903 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1904 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1905 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1906 if(!face->external) continue;
1908 if(strcmpiW(face->StyleName, RegularW))
1909 len = len_fam + strlenW(face->StyleName) + 1;
1910 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1911 strcpyW(valueW, family->FamilyName);
1912 if(len != len_fam) {
1913 strcatW(valueW, spaceW);
1914 strcatW(valueW, face->StyleName);
1916 strcatW(valueW, TrueType);
1918 file = wine_get_dos_file_name(face->file);
1920 len = strlenW(file) + 1;
1923 if((path = strrchr(face->file, '/')) == NULL)
1927 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1929 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1930 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1932 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1933 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1934 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1936 HeapFree(GetProcessHeap(), 0, file);
1937 HeapFree(GetProcessHeap(), 0, valueW);
1941 if(external_key) RegCloseKey(external_key);
1942 if(win9x_key) RegCloseKey(win9x_key);
1943 if(winnt_key) RegCloseKey(winnt_key);
1947 static void delete_external_font_keys(void)
1949 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1950 DWORD dlen, vlen, datalen, valuelen, i, type;
1954 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1955 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1956 ERR("Can't create Windows font reg key\n");
1960 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1961 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1962 ERR("Can't create Windows font reg key\n");
1966 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
1967 ERR("Can't create external font reg key\n");
1971 /* Delete all external fonts added last time */
1973 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1974 &valuelen, &datalen, NULL, NULL);
1975 valuelen++; /* returned value doesn't include room for '\0' */
1976 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1977 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1979 dlen = datalen * sizeof(WCHAR);
1982 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
1983 &dlen) == ERROR_SUCCESS) {
1985 RegDeleteValueW(winnt_key, valueW);
1986 RegDeleteValueW(win9x_key, valueW);
1987 /* reset dlen and vlen */
1991 HeapFree(GetProcessHeap(), 0, data);
1992 HeapFree(GetProcessHeap(), 0, valueW);
1994 /* Delete the old external fonts key */
1995 RegCloseKey(external_key);
1996 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1999 if(win9x_key) RegCloseKey(win9x_key);
2000 if(winnt_key) RegCloseKey(winnt_key);
2003 /*************************************************************
2004 * WineEngAddFontResourceEx
2007 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2010 if (ft_handle) /* do it only if we have freetype up and running */
2015 FIXME("Ignoring flags %x\n", flags);
2017 if((unixname = wine_get_unix_file_name(file)))
2019 EnterCriticalSection( &freetype_cs );
2020 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2021 LeaveCriticalSection( &freetype_cs );
2022 HeapFree(GetProcessHeap(), 0, unixname);
2024 if (!ret && !strchrW(file, '\\')) {
2025 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2026 ret = load_font_from_winfonts_dir(file);
2028 /* Try in datadir/fonts (or builddir/fonts),
2029 * needed for Magic the Gathering Online
2031 ret = load_font_from_data_dir(file);
2038 /*************************************************************
2039 * WineEngAddFontMemResourceEx
2042 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2044 if (ft_handle) /* do it only if we have freetype up and running */
2046 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2048 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2049 memcpy(pFontCopy, pbFont, cbFont);
2051 EnterCriticalSection( &freetype_cs );
2052 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2053 LeaveCriticalSection( &freetype_cs );
2057 TRACE("AddFontToList failed\n");
2058 HeapFree(GetProcessHeap(), 0, pFontCopy);
2061 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2062 * For now return something unique but quite random
2064 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2065 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2072 /*************************************************************
2073 * WineEngRemoveFontResourceEx
2076 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2082 static const struct nls_update_font_list
2084 UINT ansi_cp, oem_cp;
2085 const char *oem, *fixed, *system;
2086 const char *courier, *serif, *small, *sserif;
2087 /* these are for font substitute */
2088 const char *shelldlg, *tmsrmn;
2089 } nls_update_font_list[] =
2091 /* Latin 1 (United States) */
2092 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2093 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2094 "Tahoma","Times New Roman",
2096 /* Latin 1 (Multilingual) */
2097 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2098 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2099 "Tahoma","Times New Roman", /* FIXME unverified */
2101 /* Eastern Europe */
2102 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2103 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2104 "Tahoma","Times New Roman", /* FIXME unverified */
2107 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2108 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2109 "Tahoma","Times New Roman", /* FIXME unverified */
2112 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2113 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2114 "Tahoma","Times New Roman", /* FIXME unverified */
2117 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2118 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2119 "Tahoma","Times New Roman", /* FIXME unverified */
2122 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2123 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2124 "Tahoma","Times New Roman", /* FIXME unverified */
2127 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2128 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2129 "Tahoma","Times New Roman", /* FIXME unverified */
2132 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2133 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2134 "Tahoma","Times New Roman", /* FIXME unverified */
2137 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2138 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2139 "Tahoma","Times New Roman", /* FIXME unverified */
2142 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2143 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2144 "Tahoma","Times New Roman", /* FIXME unverified */
2147 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2148 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2149 "MS UI Gothic","MS Serif",
2151 /* Chinese Simplified */
2152 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2153 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2154 "Tahoma", "Times New Roman", /* FIXME unverified */
2157 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2158 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2161 /* Chinese Traditional */
2162 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2163 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2164 "PMingLiU", "MingLiU",
2168 static inline HKEY create_fonts_NT_registry_key(void)
2172 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2173 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2177 static inline HKEY create_fonts_9x_registry_key(void)
2181 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2182 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2186 static inline HKEY create_config_fonts_registry_key(void)
2190 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2191 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2195 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2197 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2198 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2199 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2200 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2203 static void update_font_info(void)
2205 char buf[40], cpbuf[40];
2208 UINT i, ansi_cp = 0, oem_cp = 0;
2210 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2213 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2214 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2215 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2216 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2217 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2219 /* Setup Default_Fallback usage */
2221 use_default_fallback = TRUE;
2224 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2226 if (!strcmp( buf, cpbuf )) /* already set correctly */
2231 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2233 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2235 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2238 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2240 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2241 nls_update_font_list[i].oem_cp == oem_cp)
2245 hkey = create_config_fonts_registry_key();
2246 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2247 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2248 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2251 hkey = create_fonts_NT_registry_key();
2252 add_font_list(hkey, &nls_update_font_list[i]);
2255 hkey = create_fonts_9x_registry_key();
2256 add_font_list(hkey, &nls_update_font_list[i]);
2259 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2261 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2262 strlen(nls_update_font_list[i].shelldlg)+1);
2263 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2264 strlen(nls_update_font_list[i].tmsrmn)+1);
2270 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2274 static BOOL init_freetype(void)
2276 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2279 "Wine cannot find the FreeType font library. To enable Wine to\n"
2280 "use TrueType fonts please install a version of FreeType greater than\n"
2281 "or equal to 2.0.5.\n"
2282 "http://www.freetype.org\n");
2286 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(ft_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
2288 LOAD_FUNCPTR(FT_Vector_Unit)
2289 LOAD_FUNCPTR(FT_Done_Face)
2290 LOAD_FUNCPTR(FT_Get_Char_Index)
2291 LOAD_FUNCPTR(FT_Get_Module)
2292 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2293 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2294 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2295 LOAD_FUNCPTR(FT_Init_FreeType)
2296 LOAD_FUNCPTR(FT_Load_Glyph)
2297 LOAD_FUNCPTR(FT_Matrix_Multiply)
2298 LOAD_FUNCPTR(FT_MulFix)
2299 LOAD_FUNCPTR(FT_New_Face)
2300 LOAD_FUNCPTR(FT_New_Memory_Face)
2301 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2302 LOAD_FUNCPTR(FT_Outline_Transform)
2303 LOAD_FUNCPTR(FT_Outline_Translate)
2304 LOAD_FUNCPTR(FT_Select_Charmap)
2305 LOAD_FUNCPTR(FT_Set_Charmap)
2306 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2307 LOAD_FUNCPTR(FT_Vector_Transform)
2310 /* Don't warn if these ones are missing */
2311 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2312 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2313 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2314 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2315 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2316 #ifdef HAVE_FREETYPE_FTWINFNT_H
2317 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2319 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2320 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2321 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2322 <= 2.0.3 has FT_Sqrt64 */
2326 if(pFT_Init_FreeType(&library) != 0) {
2327 ERR("Can't init FreeType library\n");
2328 wine_dlclose(ft_handle, NULL, 0);
2332 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2333 if (pFT_Library_Version)
2334 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2336 if (FT_Version.major<=0)
2342 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2343 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2344 ((FT_Version.minor << 8) & 0x00ff00) |
2345 ((FT_Version.patch ) & 0x0000ff);
2351 "Wine cannot find certain functions that it needs inside the FreeType\n"
2352 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2353 "FreeType to at least version 2.0.5.\n"
2354 "http://www.freetype.org\n");
2355 wine_dlclose(ft_handle, NULL, 0);
2360 /*************************************************************
2363 * Initialize FreeType library and create a list of available faces
2365 BOOL WineEngInit(void)
2367 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2368 static const WCHAR pathW[] = {'P','a','t','h',0};
2370 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2372 WCHAR windowsdir[MAX_PATH];
2375 const char *data_dir;
2379 /* update locale dependent font info in registry */
2382 if(!init_freetype()) return FALSE;
2384 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2385 ERR("Failed to create font mutex\n");
2388 WaitForSingleObject(font_mutex, INFINITE);
2390 delete_external_font_keys();
2392 /* load the system bitmap fonts */
2393 load_system_fonts();
2395 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2396 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2397 strcatW(windowsdir, fontsW);
2398 if((unixname = wine_get_unix_file_name(windowsdir)))
2400 ReadFontDir(unixname, FALSE);
2401 HeapFree(GetProcessHeap(), 0, unixname);
2404 /* load the system truetype fonts */
2405 data_dir = wine_get_data_dir();
2406 if (!data_dir) data_dir = wine_get_build_dir();
2407 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2408 strcpy(unixname, data_dir);
2409 strcat(unixname, "/fonts/");
2410 ReadFontDir(unixname, TRUE);
2411 HeapFree(GetProcessHeap(), 0, unixname);
2414 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2415 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2416 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2418 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2419 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2420 &hkey) == ERROR_SUCCESS) {
2422 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2423 &valuelen, &datalen, NULL, NULL);
2425 valuelen++; /* returned value doesn't include room for '\0' */
2426 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2427 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2430 dlen = datalen * sizeof(WCHAR);
2432 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2433 &dlen) == ERROR_SUCCESS) {
2434 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2436 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2438 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2439 HeapFree(GetProcessHeap(), 0, unixname);
2442 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2444 WCHAR pathW[MAX_PATH];
2445 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2448 sprintfW(pathW, fmtW, windowsdir, data);
2449 if((unixname = wine_get_unix_file_name(pathW)))
2451 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2452 HeapFree(GetProcessHeap(), 0, unixname);
2455 load_font_from_data_dir(data);
2457 /* reset dlen and vlen */
2462 HeapFree(GetProcessHeap(), 0, data);
2463 HeapFree(GetProcessHeap(), 0, valueW);
2467 load_fontconfig_fonts();
2469 /* then look in any directories that we've specified in the config file */
2470 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2471 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2477 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2479 len += sizeof(WCHAR);
2480 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2481 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2483 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2484 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2485 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2486 TRACE( "got font path %s\n", debugstr_a(valueA) );
2490 LPSTR next = strchr( ptr, ':' );
2491 if (next) *next++ = 0;
2492 ReadFontDir( ptr, TRUE );
2495 HeapFree( GetProcessHeap(), 0, valueA );
2497 HeapFree( GetProcessHeap(), 0, valueW );
2506 update_reg_entries();
2508 init_system_links();
2510 ReleaseMutex(font_mutex);
2515 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2518 TT_HoriHeader *pHori;
2522 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2523 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2525 if(height == 0) height = 16;
2527 /* Calc. height of EM square:
2529 * For +ve lfHeight we have
2530 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2531 * Re-arranging gives:
2532 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2534 * For -ve lfHeight we have
2536 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2537 * with il = winAscent + winDescent - units_per_em]
2542 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2543 ppem = ft_face->units_per_EM * height /
2544 (pHori->Ascender - pHori->Descender);
2546 ppem = ft_face->units_per_EM * height /
2547 (pOS2->usWinAscent + pOS2->usWinDescent);
2555 static struct font_mapping *map_font_file( const char *name )
2557 struct font_mapping *mapping;
2561 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2562 if (fstat( fd, &st ) == -1) goto error;
2564 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2566 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2568 mapping->refcount++;
2573 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2576 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2579 if (mapping->data == MAP_FAILED)
2581 HeapFree( GetProcessHeap(), 0, mapping );
2584 mapping->refcount = 1;
2585 mapping->dev = st.st_dev;
2586 mapping->ino = st.st_ino;
2587 mapping->size = st.st_size;
2588 list_add_tail( &mappings_list, &mapping->entry );
2596 static void unmap_font_file( struct font_mapping *mapping )
2598 if (!--mapping->refcount)
2600 list_remove( &mapping->entry );
2601 munmap( mapping->data, mapping->size );
2602 HeapFree( GetProcessHeap(), 0, mapping );
2606 static LONG load_VDMX(GdiFont*, LONG);
2608 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2615 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2619 if (!(font->mapping = map_font_file( face->file )))
2621 WARN("failed to map %s\n", debugstr_a(face->file));
2624 data_ptr = font->mapping->data;
2625 data_size = font->mapping->size;
2629 data_ptr = face->font_data_ptr;
2630 data_size = face->font_data_size;
2633 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2635 ERR("FT_New_Face rets %d\n", err);
2639 /* set it here, as load_VDMX needs it */
2640 font->ft_face = ft_face;
2642 if(FT_IS_SCALABLE(ft_face)) {
2643 /* load the VDMX table if we have one */
2644 font->ppem = load_VDMX(font, height);
2646 font->ppem = calc_ppem_for_height(ft_face, height);
2648 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2649 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2651 font->ppem = height;
2652 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2653 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2659 static int get_nearest_charset(Face *face, int *cp)
2661 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2662 a single face with the requested charset. The idea is to check if
2663 the selected font supports the current ANSI codepage, if it does
2664 return the corresponding charset, else return the first charset */
2667 int acp = GetACP(), i;
2671 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2672 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2673 return csi.ciCharset;
2675 for(i = 0; i < 32; i++) {
2677 if(face->fs.fsCsb[0] & fs0) {
2678 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2680 return csi.ciCharset;
2683 FIXME("TCI failing on %x\n", fs0);
2687 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2688 face->fs.fsCsb[0], face->file);
2690 return DEFAULT_CHARSET;
2693 static GdiFont *alloc_font(void)
2695 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2697 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2698 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2700 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2701 ret->total_kern_pairs = (DWORD)-1;
2702 ret->kern_pairs = NULL;
2703 list_init(&ret->hfontlist);
2704 list_init(&ret->child_fonts);
2708 static void free_font(GdiFont *font)
2710 struct list *cursor, *cursor2;
2713 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2715 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2716 struct list *first_hfont;
2717 HFONTLIST *hfontlist;
2718 list_remove(cursor);
2721 first_hfont = list_head(&child->font->hfontlist);
2722 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2723 DeleteObject(hfontlist->hfont);
2724 HeapFree(GetProcessHeap(), 0, hfontlist);
2725 free_font(child->font);
2727 HeapFree(GetProcessHeap(), 0, child);
2730 if (font->ft_face) pFT_Done_Face(font->ft_face);
2731 if (font->mapping) unmap_font_file( font->mapping );
2732 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2733 HeapFree(GetProcessHeap(), 0, font->potm);
2734 HeapFree(GetProcessHeap(), 0, font->name);
2735 for (i = 0; i < font->gmsize; i++)
2736 HeapFree(GetProcessHeap(),0,font->gm[i]);
2737 HeapFree(GetProcessHeap(), 0, font->gm);
2738 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2739 HeapFree(GetProcessHeap(), 0, font);
2743 /*************************************************************
2746 * load the vdmx entry for the specified height
2749 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2750 ( ( (FT_ULong)_x4 << 24 ) | \
2751 ( (FT_ULong)_x3 << 16 ) | \
2752 ( (FT_ULong)_x2 << 8 ) | \
2755 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2770 static LONG load_VDMX(GdiFont *font, LONG height)
2774 BYTE devXRatio, devYRatio;
2775 USHORT numRecs, numRatios;
2776 DWORD result, offset = -1;
2780 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2782 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2785 /* FIXME: need the real device aspect ratio */
2789 numRecs = GET_BE_WORD(hdr[1]);
2790 numRatios = GET_BE_WORD(hdr[2]);
2792 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2793 for(i = 0; i < numRatios; i++) {
2796 offset = (3 * 2) + (i * sizeof(Ratios));
2797 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2800 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2802 if((ratio.xRatio == 0 &&
2803 ratio.yStartRatio == 0 &&
2804 ratio.yEndRatio == 0) ||
2805 (devXRatio == ratio.xRatio &&
2806 devYRatio >= ratio.yStartRatio &&
2807 devYRatio <= ratio.yEndRatio))
2809 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2810 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2811 offset = GET_BE_WORD(tmp);
2817 FIXME("No suitable ratio found\n");
2821 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2823 BYTE startsz, endsz;
2826 recs = GET_BE_WORD(group.recs);
2827 startsz = group.startsz;
2828 endsz = group.endsz;
2830 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2832 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2833 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2834 if(result == GDI_ERROR) {
2835 FIXME("Failed to retrieve vTable\n");
2840 for(i = 0; i < recs; i++) {
2841 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2842 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2843 ppem = GET_BE_WORD(vTable[i * 3]);
2845 if(yMax + -yMin == height) {
2848 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2851 if(yMax + -yMin > height) {
2854 goto end; /* failed */
2856 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2857 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2858 ppem = GET_BE_WORD(vTable[i * 3]);
2859 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2865 TRACE("ppem not found for height %d\n", height);
2869 if(ppem < startsz || ppem > endsz)
2872 for(i = 0; i < recs; i++) {
2874 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2876 if(yPelHeight > ppem)
2879 if(yPelHeight == ppem) {
2880 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2881 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2882 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2888 HeapFree(GetProcessHeap(), 0, vTable);
2894 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
2896 if(font->font_desc.hash != fd->hash) return TRUE;
2897 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2898 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2899 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2900 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2903 static void calc_hash(FONT_DESC *pfd)
2905 DWORD hash = 0, *ptr, two_chars;
2909 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2911 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2913 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2915 pwc = (WCHAR *)&two_chars;
2917 *pwc = toupperW(*pwc);
2919 *pwc = toupperW(*pwc);
2923 hash ^= !pfd->can_use_bitmap;
2928 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2933 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2936 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2937 fd.can_use_bitmap = can_use_bitmap;
2940 /* try the in-use list */
2941 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2942 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2943 if(!fontcmp(ret, &fd)) {
2944 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2945 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2946 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2947 if(hflist->hfont == hfont)
2950 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2951 hflist->hfont = hfont;
2952 list_add_head(&ret->hfontlist, &hflist->entry);
2957 /* then the unused list */
2958 font_elem_ptr = list_head(&unused_gdi_font_list);
2959 while(font_elem_ptr) {
2960 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2961 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2962 if(!fontcmp(ret, &fd)) {
2963 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2964 assert(list_empty(&ret->hfontlist));
2965 TRACE("Found %p in unused list\n", ret);
2966 list_remove(&ret->entry);
2967 list_add_head(&gdi_font_list, &ret->entry);
2968 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2969 hflist->hfont = hfont;
2970 list_add_head(&ret->hfontlist, &hflist->entry);
2978 /*************************************************************
2979 * create_child_font_list
2981 static BOOL create_child_font_list(GdiFont *font)
2984 SYSTEM_LINKS *font_link;
2985 CHILD_FONT *font_link_entry, *new_child;
2987 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2989 if(!strcmpW(font_link->font_name, font->name))
2991 TRACE("found entry in system list\n");
2992 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2994 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2995 new_child->face = font_link_entry->face;
2996 new_child->font = NULL;
2997 list_add_tail(&font->child_fonts, &new_child->entry);
2998 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3005 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3006 * Sans Serif. This is how asian windows get default fallbacks for fonts
3008 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3009 font->charset != OEM_CHARSET &&
3010 strcmpW(font->name,szDefaultFallbackLink) != 0)
3011 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3013 if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3015 TRACE("found entry in default fallback list\n");
3016 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3018 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3019 new_child->face = font_link_entry->face;
3020 new_child->font = NULL;
3021 list_add_tail(&font->child_fonts, &new_child->entry);
3022 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3032 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3034 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3036 if (pFT_Set_Charmap)
3039 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3041 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3043 for (i = 0; i < ft_face->num_charmaps; i++)
3045 if (ft_face->charmaps[i]->encoding == encoding)
3047 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3048 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3050 switch (ft_face->charmaps[i]->platform_id)
3053 cmap_def = ft_face->charmaps[i];
3055 case 0: /* Apple Unicode */
3056 cmap0 = ft_face->charmaps[i];
3058 case 1: /* Macintosh */
3059 cmap1 = ft_face->charmaps[i];
3062 cmap2 = ft_face->charmaps[i];
3064 case 3: /* Microsoft */
3065 cmap3 = ft_face->charmaps[i];
3070 if (cmap3) /* prefer Microsoft cmap table */
3071 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3073 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3075 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3077 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3079 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3081 return ft_err == FT_Err_Ok;
3084 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3087 /*************************************************************
3088 * WineEngCreateFontInstance
3091 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3094 Face *face, *best, *best_bitmap;
3095 Family *family, *last_resort_family;
3096 struct list *family_elem_ptr, *face_elem_ptr;
3097 INT height, width = 0;
3098 unsigned int score = 0, new_score;
3099 signed int diff = 0, newdiff;
3100 BOOL bd, it, can_use_bitmap;
3105 EnterCriticalSection( &freetype_cs );
3107 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
3109 struct list *first_hfont = list_head(&ret->hfontlist);
3110 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3111 if(hflist->hfont == hfont)
3113 LeaveCriticalSection( &freetype_cs );
3118 if (!GetObjectW( hfont, sizeof(lf), &lf ))
3120 LeaveCriticalSection( &freetype_cs );
3123 lf.lfWidth = abs(lf.lfWidth);
3125 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3127 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3128 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3129 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3132 /* check the cache first */
3133 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
3134 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3135 LeaveCriticalSection( &freetype_cs );
3139 TRACE("not in cache\n");
3140 if(list_empty(&font_list)) /* No fonts installed */
3142 TRACE("No fonts installed\n");
3143 LeaveCriticalSection( &freetype_cs );
3146 if(!have_installed_roman_font)
3148 TRACE("No roman font installed\n");
3149 LeaveCriticalSection( &freetype_cs );
3155 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
3156 ret->font_desc.lf = lf;
3157 ret->font_desc.can_use_bitmap = can_use_bitmap;
3158 calc_hash(&ret->font_desc);
3159 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3160 hflist->hfont = hfont;
3161 list_add_head(&ret->hfontlist, &hflist->entry);
3164 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3165 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3166 original value lfCharSet. Note this is a special case for
3167 Symbol and doesn't happen at least for "Wingdings*" */
3169 if(!strcmpiW(lf.lfFaceName, SymbolW))
3170 lf.lfCharSet = SYMBOL_CHARSET;
3172 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3173 switch(lf.lfCharSet) {
3174 case DEFAULT_CHARSET:
3175 csi.fs.fsCsb[0] = 0;
3178 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3179 csi.fs.fsCsb[0] = 0;
3185 if(lf.lfFaceName[0] != '\0') {
3187 SYSTEM_LINKS *font_link;
3188 CHILD_FONT *font_link_entry;
3189 LPWSTR FaceName = lf.lfFaceName;
3192 * Check for a leading '@' this signals that the font is being
3193 * requested in tategaki mode (vertical writing substitution) but
3194 * does not affect the fontface that is to be selected.
3196 if (lf.lfFaceName[0]=='@')
3197 FaceName = &lf.lfFaceName[1];
3199 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3202 TRACE("substituting %s -> %s\n", debugstr_w(FaceName),
3203 debugstr_w(psub->to.name));
3204 strcpyW(FaceName, psub->to.name);
3207 /* We want a match on name and charset or just name if
3208 charset was DEFAULT_CHARSET. If the latter then
3209 we fixup the returned charset later in get_nearest_charset
3210 where we'll either use the charset of the current ansi codepage
3211 or if that's unavailable the first charset that the font supports.
3213 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3214 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3215 if(!strcmpiW(family->FamilyName, FaceName)) {
3216 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3217 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3218 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3219 if(face->scalable || can_use_bitmap)
3226 * Try check the SystemLink list first for a replacement font.
3227 * We may find good replacements there.
3229 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3231 if(!strcmpiW(font_link->font_name, FaceName))
3233 TRACE("found entry in system list\n");
3234 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3236 face = font_link_entry->face;
3237 family = face->family;
3238 if(csi.fs.fsCsb[0] &
3239 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3241 if(face->scalable || can_use_bitmap)
3249 /* If requested charset was DEFAULT_CHARSET then try using charset
3250 corresponding to the current ansi codepage */
3251 if(!csi.fs.fsCsb[0]) {
3253 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3254 FIXME("TCI failed on codepage %d\n", acp);
3255 csi.fs.fsCsb[0] = 0;
3257 lf.lfCharSet = csi.ciCharset;
3260 /* Face families are in the top 4 bits of lfPitchAndFamily,
3261 so mask with 0xF0 before testing */
3263 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3264 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3265 strcpyW(lf.lfFaceName, defFixed);
3266 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3267 strcpyW(lf.lfFaceName, defSerif);
3268 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3269 strcpyW(lf.lfFaceName, defSans);
3271 strcpyW(lf.lfFaceName, defSans);
3272 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3273 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3274 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3275 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3276 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3277 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3278 if(face->scalable || can_use_bitmap)
3284 last_resort_family = NULL;
3285 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3286 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3287 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3288 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3289 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3292 if(can_use_bitmap && !last_resort_family)
3293 last_resort_family = family;
3298 if(last_resort_family) {
3299 family = last_resort_family;
3300 csi.fs.fsCsb[0] = 0;
3304 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3305 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3306 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3307 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3308 if(face->scalable) {
3309 csi.fs.fsCsb[0] = 0;
3310 WARN("just using first face for now\n");
3313 if(can_use_bitmap && !last_resort_family)
3314 last_resort_family = family;
3317 if(!last_resort_family) {
3318 FIXME("can't find a single appropriate font - bailing\n");
3320 LeaveCriticalSection( &freetype_cs );
3324 WARN("could only find a bitmap font - this will probably look awful!\n");
3325 family = last_resort_family;
3326 csi.fs.fsCsb[0] = 0;
3329 it = lf.lfItalic ? 1 : 0;
3330 bd = lf.lfWeight > 550 ? 1 : 0;
3332 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
3333 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
3335 face = best = best_bitmap = NULL;
3336 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3338 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3342 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3343 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3344 new_score = (italic ^ it) + (bold ^ bd);
3345 if(!best || new_score <= score)
3347 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3348 italic, bold, it, bd);
3351 if(best->scalable && score == 0) break;
3355 newdiff = height - (signed int)(best->size.height);
3357 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3358 if(!best_bitmap || new_score < score ||
3359 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3361 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3364 if(score == 0 && diff == 0) break;
3371 face = best->scalable ? best : best_bitmap;
3372 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3373 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3377 if(csi.fs.fsCsb[0]) {
3378 ret->charset = lf.lfCharSet;
3379 ret->codepage = csi.ciACP;
3382 ret->charset = get_nearest_charset(face, &ret->codepage);
3384 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3385 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3387 ret->aveWidth = height ? lf.lfWidth : 0;
3389 if(!face->scalable) {
3390 /* Windows uses integer scaling factors for bitmap fonts */
3391 INT scale, scaled_height;
3393 if (height != 0) height = diff;
3394 height += face->size.height;
3396 scale = (height + face->size.height - 1) / face->size.height;
3397 scaled_height = scale * face->size.height;
3398 /* XP allows not more than 10% deviation */
3399 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3400 ret->scale_y = scale;
3402 width = face->size.x_ppem >> 6;
3403 height = face->size.y_ppem >> 6;
3407 TRACE("font scale y: %f\n", ret->scale_y);
3409 ret->ft_face = OpenFontFace(ret, face, width, height);
3414 LeaveCriticalSection( &freetype_cs );
3418 ret->ntmFlags = face->ntmFlags;
3420 if (ret->charset == SYMBOL_CHARSET &&
3421 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3424 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3428 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3431 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3432 ret->name = strdupW(family->FamilyName);
3433 ret->underline = lf.lfUnderline ? 0xff : 0;
3434 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3435 create_child_font_list(ret);
3437 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3439 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3440 if (length != GDI_ERROR)
3442 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3443 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3444 TRACE("Loaded GSUB table of %i bytes\n",length);
3448 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3450 list_add_head(&gdi_font_list, &ret->entry);
3451 LeaveCriticalSection( &freetype_cs );
3455 static void dump_gdi_font_list(void)
3458 struct list *elem_ptr;
3460 TRACE("---------- gdiFont Cache ----------\n");
3461 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3462 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3463 TRACE("gdiFont=%p %s %d\n",
3464 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3467 TRACE("---------- Unused gdiFont Cache ----------\n");
3468 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3469 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3470 TRACE("gdiFont=%p %s %d\n",
3471 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3475 /*************************************************************
3476 * WineEngDestroyFontInstance
3478 * free the gdiFont associated with this handle
3481 BOOL WineEngDestroyFontInstance(HFONT handle)
3486 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3489 EnterCriticalSection( &freetype_cs );
3491 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3493 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3494 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3495 if(hflist->hfont == handle)
3497 TRACE("removing child font %p from child list\n", gdiFont);
3498 list_remove(&gdiFont->entry);
3499 LeaveCriticalSection( &freetype_cs );
3504 TRACE("destroying hfont=%p\n", handle);
3506 dump_gdi_font_list();
3508 font_elem_ptr = list_head(&gdi_font_list);
3509 while(font_elem_ptr) {
3510 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3511 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3513 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3514 while(hfontlist_elem_ptr) {
3515 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3516 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3517 if(hflist->hfont == handle) {
3518 list_remove(&hflist->entry);
3519 HeapFree(GetProcessHeap(), 0, hflist);
3523 if(list_empty(&gdiFont->hfontlist)) {
3524 TRACE("Moving to Unused list\n");
3525 list_remove(&gdiFont->entry);
3526 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3531 font_elem_ptr = list_head(&unused_gdi_font_list);
3532 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3533 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3534 while(font_elem_ptr) {
3535 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3536 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3537 TRACE("freeing %p\n", gdiFont);
3538 list_remove(&gdiFont->entry);
3541 LeaveCriticalSection( &freetype_cs );
3545 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3546 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3551 if (face->cached_enum_data)
3554 *pelf = face->cached_enum_data->elf;
3555 *pntm = face->cached_enum_data->ntm;
3556 *ptype = face->cached_enum_data->type;
3560 font = alloc_font();
3562 if(face->scalable) {
3563 height = -2048; /* 2048 is the most common em size */
3566 height = face->size.y_ppem >> 6;
3567 width = face->size.x_ppem >> 6;
3569 font->scale_y = 1.0;
3571 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3577 font->name = strdupW(face->family->FamilyName);
3578 font->ntmFlags = face->ntmFlags;
3580 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3582 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3584 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3586 lstrcpynW(pelf->elfLogFont.lfFaceName,
3587 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3589 lstrcpynW(pelf->elfFullName,
3590 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3592 lstrcpynW(pelf->elfStyle,
3593 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3598 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3600 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3602 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3603 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3604 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3607 pntm->ntmTm.ntmFlags = face->ntmFlags;
3608 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3609 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3610 pntm->ntmFontSig = face->fs;
3612 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3614 pelf->elfLogFont.lfEscapement = 0;
3615 pelf->elfLogFont.lfOrientation = 0;
3616 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3617 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3618 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3619 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3620 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3621 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3622 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3623 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3624 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3625 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3626 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3629 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3630 *ptype |= TRUETYPE_FONTTYPE;
3631 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3632 *ptype |= DEVICE_FONTTYPE;
3633 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3634 *ptype |= RASTER_FONTTYPE;
3636 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3637 if (face->cached_enum_data)
3639 face->cached_enum_data->elf = *pelf;
3640 face->cached_enum_data->ntm = *pntm;
3641 face->cached_enum_data->type = *ptype;
3647 /*************************************************************
3651 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3655 struct list *family_elem_ptr, *face_elem_ptr;
3657 NEWTEXTMETRICEXW ntm;
3666 lf.lfCharSet = DEFAULT_CHARSET;
3667 lf.lfPitchAndFamily = 0;
3668 lf.lfFaceName[0] = 0;
3672 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3674 EnterCriticalSection( &freetype_cs );
3675 if(plf->lfFaceName[0]) {
3677 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3680 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3681 debugstr_w(psub->to.name));
3683 strcpyW(lf.lfFaceName, psub->to.name);
3687 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3688 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3689 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3690 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3691 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3692 GetEnumStructs(face, &elf, &ntm, &type);
3693 for(i = 0; i < 32; i++) {
3694 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3695 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3696 strcpyW(elf.elfScript, OEM_DOSW);
3697 i = 32; /* break out of loop */
3698 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3701 fs.fsCsb[0] = 1L << i;
3703 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3705 csi.ciCharset = DEFAULT_CHARSET;
3706 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3707 if(csi.ciCharset != DEFAULT_CHARSET) {
3708 elf.elfLogFont.lfCharSet =
3709 ntm.ntmTm.tmCharSet = csi.ciCharset;
3711 strcpyW(elf.elfScript, ElfScriptsW[i]);
3713 FIXME("Unknown elfscript for bit %d\n", i);
3716 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3717 debugstr_w(elf.elfLogFont.lfFaceName),
3718 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3719 csi.ciCharset, type, debugstr_w(elf.elfScript),
3720 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3721 ntm.ntmTm.ntmFlags);
3722 /* release section before callback (FIXME) */
3723 LeaveCriticalSection( &freetype_cs );
3724 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3725 EnterCriticalSection( &freetype_cs );
3731 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3732 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3733 face_elem_ptr = list_head(&family->faces);
3734 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3735 GetEnumStructs(face, &elf, &ntm, &type);
3736 for(i = 0; i < 32; i++) {
3737 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3738 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3739 strcpyW(elf.elfScript, OEM_DOSW);
3740 i = 32; /* break out of loop */
3741 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3744 fs.fsCsb[0] = 1L << i;
3746 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3748 csi.ciCharset = DEFAULT_CHARSET;
3749 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3750 if(csi.ciCharset != DEFAULT_CHARSET) {
3751 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3754 strcpyW(elf.elfScript, ElfScriptsW[i]);
3756 FIXME("Unknown elfscript for bit %d\n", i);
3759 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3760 debugstr_w(elf.elfLogFont.lfFaceName),
3761 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3762 csi.ciCharset, type, debugstr_w(elf.elfScript),
3763 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3764 ntm.ntmTm.ntmFlags);
3765 /* release section before callback (FIXME) */
3766 LeaveCriticalSection( &freetype_cs );
3767 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
3768 EnterCriticalSection( &freetype_cs );
3772 LeaveCriticalSection( &freetype_cs );
3776 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3778 pt->x.value = vec->x >> 6;
3779 pt->x.fract = (vec->x & 0x3f) << 10;
3780 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3781 pt->y.value = vec->y >> 6;
3782 pt->y.fract = (vec->y & 0x3f) << 10;
3783 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3787 /***************************************************
3788 * According to the MSDN documentation on WideCharToMultiByte,
3789 * certain codepages cannot set the default_used parameter.
3790 * This returns TRUE if the codepage can set that parameter, false else
3791 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3793 static BOOL codepage_sets_default_used(UINT codepage)
3807 * GSUB Table handling functions
3810 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
3812 const GSUB_CoverageFormat1* cf1;
3814 cf1 = (GSUB_CoverageFormat1*)table;
3816 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
3818 int count = GET_BE_WORD(cf1->GlyphCount);
3820 TRACE("Coverage Format 1, %i glyphs\n",count);
3821 for (i = 0; i < count; i++)
3822 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
3826 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
3828 const GSUB_CoverageFormat2* cf2;
3831 cf2 = (GSUB_CoverageFormat2*)cf1;
3833 count = GET_BE_WORD(cf2->RangeCount);
3834 TRACE("Coverage Format 2, %i ranges\n",count);
3835 for (i = 0; i < count; i++)
3837 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
3839 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
3840 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
3842 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
3843 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
3849 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
3854 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
3856 const GSUB_ScriptList *script;
3857 const GSUB_Script *deflt = NULL;
3859 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
3861 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
3862 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
3864 const GSUB_Script *scr;
3867 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
3868 scr = (GSUB_Script*)((LPBYTE)script + offset);
3870 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
3872 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
3878 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
3882 const GSUB_LangSys *Lang;
3884 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
3886 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
3888 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
3889 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
3891 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
3894 offset = GET_BE_WORD(script->DefaultLangSys);
3897 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
3903 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
3906 const GSUB_FeatureList *feature;
3907 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
3909 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
3910 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
3912 int index = GET_BE_WORD(lang->FeatureIndex[i]);
3913 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
3915 const GSUB_Feature *feat;
3916 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
3923 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
3927 const GSUB_LookupList *lookup;
3928 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
3930 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
3931 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
3933 const GSUB_LookupTable *look;
3934 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
3935 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
3936 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
3937 if (GET_BE_WORD(look->LookupType) != 1)
3938 FIXME("We only handle SubType 1\n");
3943 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
3945 const GSUB_SingleSubstFormat1 *ssf1;
3946 offset = GET_BE_WORD(look->SubTable[j]);
3947 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
3948 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
3950 int offset = GET_BE_WORD(ssf1->Coverage);
3951 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
3952 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
3954 TRACE(" Glyph 0x%x ->",glyph);
3955 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
3956 TRACE(" 0x%x\n",glyph);
3961 const GSUB_SingleSubstFormat2 *ssf2;
3965 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
3966 offset = GET_BE_WORD(ssf1->Coverage);
3967 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
3968 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
3969 TRACE(" Coverage index %i\n",index);
3972 TRACE(" Glyph is 0x%x ->",glyph);
3973 glyph = GET_BE_WORD(ssf2->Substitute[index]);
3974 TRACE("0x%x\n",glyph);
3983 static const char* get_opentype_script(const GdiFont *font)
3986 * I am not sure if this is the correct way to generate our script tag
3989 switch (font->charset)
3991 case ANSI_CHARSET: return "latn";
3992 case BALTIC_CHARSET: return "latn"; /* ?? */
3993 case CHINESEBIG5_CHARSET: return "hani";
3994 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
3995 case GB2312_CHARSET: return "hani";
3996 case GREEK_CHARSET: return "grek";
3997 case HANGUL_CHARSET: return "hang";
3998 case RUSSIAN_CHARSET: return "cyrl";
3999 case SHIFTJIS_CHARSET: return "kana";
4000 case TURKISH_CHARSET: return "latn"; /* ?? */
4001 case VIETNAMESE_CHARSET: return "latn";
4002 case JOHAB_CHARSET: return "latn"; /* ?? */
4003 case ARABIC_CHARSET: return "arab";
4004 case HEBREW_CHARSET: return "hebr";
4005 case THAI_CHARSET: return "thai";
4006 default: return "latn";
4010 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4012 const GSUB_Header *header;
4013 const GSUB_Script *script;
4014 const GSUB_LangSys *language;
4015 const GSUB_Feature *feature;
4017 if (!font->GSUB_Table)
4020 header = font->GSUB_Table;
4022 script = GSUB_get_script_table(header, get_opentype_script(font));
4025 TRACE("Script not found\n");
4028 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4031 TRACE("Language not found\n");
4034 feature = GSUB_get_feature(header, language, "vrt2");
4036 feature = GSUB_get_feature(header, language, "vert");
4039 TRACE("vrt2/vert feature not found\n");
4042 return GSUB_apply_feature(header, feature, glyph);
4045 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4049 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4050 WCHAR wc = (WCHAR)glyph;
4052 BOOL *default_used_pointer;
4055 default_used_pointer = NULL;
4056 default_used = FALSE;
4057 if (codepage_sets_default_used(font->codepage))
4058 default_used_pointer = &default_used;
4059 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4062 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4063 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4064 return get_GSUB_vert_glyph(font,ret);
4067 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4068 glyph = glyph + 0xf000;
4069 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4070 return get_GSUB_vert_glyph(font,glyphId);
4073 /*************************************************************
4074 * WineEngGetGlyphIndices
4077 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4078 LPWORD pgi, DWORD flags)
4081 int default_char = -1;
4083 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4085 for(i = 0; i < count; i++)
4087 pgi[i] = get_glyph_index(font, lpstr[i]);
4090 if (default_char == -1)
4092 if (FT_IS_SFNT(font->ft_face))
4094 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4095 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4100 WineEngGetTextMetrics(font, &textm);
4101 default_char = textm.tmDefaultChar;
4104 pgi[i] = default_char;
4110 /*************************************************************
4111 * WineEngGetGlyphOutline
4113 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4114 * except that the first parameter is the HWINEENGFONT of the font in
4115 * question rather than an HDC.
4118 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4119 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4122 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4123 FT_Face ft_face = incoming_font->ft_face;
4124 GdiFont *font = incoming_font;
4125 FT_UInt glyph_index;
4126 DWORD width, height, pitch, needed = 0;
4127 FT_Bitmap ft_bitmap;
4129 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4131 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4132 float widthRatio = 1.0;
4133 FT_Matrix transMat = identityMat;
4134 BOOL needsTransform = FALSE;
4135 BOOL tategaki = (font->GSUB_Table != NULL);
4136 UINT original_index;
4139 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4140 buflen, buf, lpmat);
4142 EnterCriticalSection( &freetype_cs );
4144 if(format & GGO_GLYPH_INDEX) {
4145 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4146 original_index = glyph;
4147 format &= ~GGO_GLYPH_INDEX;
4149 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4150 ft_face = font->ft_face;
4151 original_index = glyph_index;
4154 /* tategaki never appears to happen to lower glyph index */
4155 if (glyph_index < TATEGAKI_LOWER_BOUND )
4158 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4159 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4160 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4161 font->gmsize * sizeof(GM*));
4163 if(format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL && FONT_GM(font,original_index)->init ) {
4164 *lpgm = FONT_GM(font,original_index)->gm;
4165 LeaveCriticalSection( &freetype_cs );
4166 return 1; /* FIXME */
4170 if (!font->gm[original_index / GM_BLOCK_SIZE])
4171 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4173 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || lpmat)
4174 load_flags |= FT_LOAD_NO_BITMAP;
4176 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4179 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4180 LeaveCriticalSection( &freetype_cs );
4184 /* Scaling factor */
4185 if (font->aveWidth && font->potm)
4187 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11;
4188 widthRatio /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
4191 widthRatio = font->scale_y;
4193 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
4194 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
4196 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
4198 bbx = (right - left) >> 6;
4200 /* Scaling transform */
4201 if(font->aveWidth) {
4203 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4206 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4208 pFT_Matrix_Multiply(&scaleMat, &transMat);
4209 needsTransform = TRUE;
4212 /* Slant transform */
4213 if (font->fake_italic) {
4216 slantMat.xx = (1 << 16);
4217 slantMat.xy = ((1 << 16) >> 2);
4219 slantMat.yy = (1 << 16);
4220 pFT_Matrix_Multiply(&slantMat, &transMat);
4221 needsTransform = TRUE;
4224 /* Rotation transform */
4225 if(font->orientation && !tategaki) {
4226 FT_Matrix rotationMat;
4228 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
4229 pFT_Vector_Unit(&vecAngle, angle);
4230 rotationMat.xx = vecAngle.x;
4231 rotationMat.xy = -vecAngle.y;
4232 rotationMat.yx = -rotationMat.xy;
4233 rotationMat.yy = rotationMat.xx;
4235 pFT_Matrix_Multiply(&rotationMat, &transMat);
4236 needsTransform = TRUE;
4239 /* Extra transformation specified by caller */
4242 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4243 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
4244 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
4245 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4246 pFT_Matrix_Multiply(&extraMat, &transMat);
4247 needsTransform = TRUE;
4250 if(!needsTransform) {
4251 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4252 bottom = (ft_face->glyph->metrics.horiBearingY -
4253 ft_face->glyph->metrics.height) & -64;
4254 lpgm->gmCellIncX = adv;
4255 lpgm->gmCellIncY = 0;
4259 for(xc = 0; xc < 2; xc++) {
4260 for(yc = 0; yc < 2; yc++) {
4261 vec.x = (ft_face->glyph->metrics.horiBearingX +
4262 xc * ft_face->glyph->metrics.width);
4263 vec.y = ft_face->glyph->metrics.horiBearingY -
4264 yc * ft_face->glyph->metrics.height;
4265 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4266 pFT_Vector_Transform(&vec, &transMat);
4267 if(xc == 0 && yc == 0) {
4268 left = right = vec.x;
4269 top = bottom = vec.y;
4271 if(vec.x < left) left = vec.x;
4272 else if(vec.x > right) right = vec.x;
4273 if(vec.y < bottom) bottom = vec.y;
4274 else if(vec.y > top) top = vec.y;
4279 right = (right + 63) & -64;
4280 bottom = bottom & -64;
4281 top = (top + 63) & -64;
4283 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4284 vec.x = ft_face->glyph->metrics.horiAdvance;
4286 pFT_Vector_Transform(&vec, &transMat);
4287 lpgm->gmCellIncX = (vec.x+63) >> 6;
4288 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4290 lpgm->gmBlackBoxX = (right - left) >> 6;
4291 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4292 lpgm->gmptGlyphOrigin.x = left >> 6;
4293 lpgm->gmptGlyphOrigin.y = top >> 6;
4295 if(format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP)
4297 FONT_GM(font,original_index)->gm = *lpgm;
4298 FONT_GM(font,original_index)->adv = adv;
4299 FONT_GM(font,original_index)->lsb = lsb;
4300 FONT_GM(font,original_index)->bbx = bbx;
4301 FONT_GM(font,original_index)->init = TRUE;
4304 if(format == GGO_METRICS)
4306 LeaveCriticalSection( &freetype_cs );
4307 return 1; /* FIXME */
4310 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
4311 TRACE("loaded a bitmap\n");
4312 LeaveCriticalSection( &freetype_cs );
4318 width = lpgm->gmBlackBoxX;
4319 height = lpgm->gmBlackBoxY;
4320 pitch = ((width + 31) >> 5) << 2;
4321 needed = pitch * height;
4323 if(!buf || !buflen) break;
4325 switch(ft_face->glyph->format) {
4326 case ft_glyph_format_bitmap:
4328 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4329 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4330 INT h = ft_face->glyph->bitmap.rows;
4332 memcpy(dst, src, w);
4333 src += ft_face->glyph->bitmap.pitch;
4339 case ft_glyph_format_outline:
4340 ft_bitmap.width = width;
4341 ft_bitmap.rows = height;
4342 ft_bitmap.pitch = pitch;
4343 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4344 ft_bitmap.buffer = buf;
4346 if(needsTransform) {
4347 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4350 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4352 /* Note: FreeType will only set 'black' bits for us. */
4353 memset(buf, 0, needed);
4354 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4358 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4359 LeaveCriticalSection( &freetype_cs );
4364 case GGO_GRAY2_BITMAP:
4365 case GGO_GRAY4_BITMAP:
4366 case GGO_GRAY8_BITMAP:
4367 case WINE_GGO_GRAY16_BITMAP:
4369 unsigned int mult, row, col;
4372 width = lpgm->gmBlackBoxX;
4373 height = lpgm->gmBlackBoxY;
4374 pitch = (width + 3) / 4 * 4;
4375 needed = pitch * height;
4377 if(!buf || !buflen) break;
4379 switch(ft_face->glyph->format) {
4380 case ft_glyph_format_bitmap:
4382 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4383 INT h = ft_face->glyph->bitmap.rows;
4386 for(x = 0; x < pitch; x++)
4388 if(x < ft_face->glyph->bitmap.width)
4389 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4393 src += ft_face->glyph->bitmap.pitch;
4396 LeaveCriticalSection( &freetype_cs );
4399 case ft_glyph_format_outline:
4401 ft_bitmap.width = width;
4402 ft_bitmap.rows = height;
4403 ft_bitmap.pitch = pitch;
4404 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4405 ft_bitmap.buffer = buf;
4408 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4410 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4412 memset(ft_bitmap.buffer, 0, buflen);
4414 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4416 if(format == GGO_GRAY2_BITMAP)
4418 else if(format == GGO_GRAY4_BITMAP)
4420 else if(format == GGO_GRAY8_BITMAP)
4422 else /* format == WINE_GGO_GRAY16_BITMAP */
4424 LeaveCriticalSection( &freetype_cs );
4430 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4431 LeaveCriticalSection( &freetype_cs );
4436 for(row = 0; row < height; row++) {
4438 for(col = 0; col < width; col++, ptr++) {
4439 *ptr = (((int)*ptr) * mult + 128) / 256;
4448 int contour, point = 0, first_pt;
4449 FT_Outline *outline = &ft_face->glyph->outline;
4450 TTPOLYGONHEADER *pph;
4452 DWORD pph_start, cpfx, type;
4454 if(buflen == 0) buf = NULL;
4456 if (needsTransform && buf) {
4457 pFT_Outline_Transform(outline, &transMat);
4460 for(contour = 0; contour < outline->n_contours; contour++) {
4462 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4465 pph->dwType = TT_POLYGON_TYPE;
4466 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4468 needed += sizeof(*pph);
4470 while(point <= outline->contours[contour]) {
4471 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4472 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4473 TT_PRIM_LINE : TT_PRIM_QSPLINE;
4477 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4480 } while(point <= outline->contours[contour] &&
4481 (outline->tags[point] & FT_Curve_Tag_On) ==
4482 (outline->tags[point-1] & FT_Curve_Tag_On));
4483 /* At the end of a contour Windows adds the start point, but
4485 if(point > outline->contours[contour] &&
4486 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
4488 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
4490 } else if(point <= outline->contours[contour] &&
4491 outline->tags[point] & FT_Curve_Tag_On) {
4492 /* add closing pt for bezier */
4494 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4502 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4505 pph->cb = needed - pph_start;
4511 /* Convert the quadratic Beziers to cubic Beziers.
4512 The parametric eqn for a cubic Bezier is, from PLRM:
4513 r(t) = at^3 + bt^2 + ct + r0
4514 with the control points:
4519 A quadratic Beizer has the form:
4520 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4522 So equating powers of t leads to:
4523 r1 = 2/3 p1 + 1/3 p0
4524 r2 = 2/3 p1 + 1/3 p2
4525 and of course r0 = p0, r3 = p2
4528 int contour, point = 0, first_pt;
4529 FT_Outline *outline = &ft_face->glyph->outline;
4530 TTPOLYGONHEADER *pph;
4532 DWORD pph_start, cpfx, type;
4533 FT_Vector cubic_control[4];
4534 if(buflen == 0) buf = NULL;
4536 if (needsTransform && buf) {
4537 pFT_Outline_Transform(outline, &transMat);
4540 for(contour = 0; contour < outline->n_contours; contour++) {
4542 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4545 pph->dwType = TT_POLYGON_TYPE;
4546 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4548 needed += sizeof(*pph);
4550 while(point <= outline->contours[contour]) {
4551 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4552 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4553 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4556 if(type == TT_PRIM_LINE) {
4558 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4562 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4565 /* FIXME: Possible optimization in endpoint calculation
4566 if there are two consecutive curves */
4567 cubic_control[0] = outline->points[point-1];
4568 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4569 cubic_control[0].x += outline->points[point].x + 1;
4570 cubic_control[0].y += outline->points[point].y + 1;
4571 cubic_control[0].x >>= 1;
4572 cubic_control[0].y >>= 1;
4574 if(point+1 > outline->contours[contour])
4575 cubic_control[3] = outline->points[first_pt];
4577 cubic_control[3] = outline->points[point+1];
4578 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4579 cubic_control[3].x += outline->points[point].x + 1;
4580 cubic_control[3].y += outline->points[point].y + 1;
4581 cubic_control[3].x >>= 1;
4582 cubic_control[3].y >>= 1;
4585 /* r1 = 1/3 p0 + 2/3 p1
4586 r2 = 1/3 p2 + 2/3 p1 */
4587 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4588 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4589 cubic_control[2] = cubic_control[1];
4590 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4591 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4592 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4593 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4595 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4596 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4597 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4602 } while(point <= outline->contours[contour] &&
4603 (outline->tags[point] & FT_Curve_Tag_On) ==
4604 (outline->tags[point-1] & FT_Curve_Tag_On));
4605 /* At the end of a contour Windows adds the start point,
4606 but only for Beziers and we've already done that.
4608 if(point <= outline->contours[contour] &&
4609 outline->tags[point] & FT_Curve_Tag_On) {
4610 /* This is the closing pt of a bezier, but we've already
4611 added it, so just inc point and carry on */
4618 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4621 pph->cb = needed - pph_start;
4627 FIXME("Unsupported format %d\n", format);
4628 LeaveCriticalSection( &freetype_cs );
4631 LeaveCriticalSection( &freetype_cs );
4635 static BOOL get_bitmap_text_metrics(GdiFont *font)
4637 FT_Face ft_face = font->ft_face;
4638 #ifdef HAVE_FREETYPE_FTWINFNT_H
4639 FT_WinFNT_HeaderRec winfnt_header;
4641 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4642 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4643 font->potm->otmSize = size;
4645 #define TM font->potm->otmTextMetrics
4646 #ifdef HAVE_FREETYPE_FTWINFNT_H
4647 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4649 TM.tmHeight = winfnt_header.pixel_height;
4650 TM.tmAscent = winfnt_header.ascent;
4651 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4652 TM.tmInternalLeading = winfnt_header.internal_leading;
4653 TM.tmExternalLeading = winfnt_header.external_leading;
4654 TM.tmAveCharWidth = winfnt_header.avg_width;
4655 TM.tmMaxCharWidth = winfnt_header.max_width;
4656 TM.tmWeight = winfnt_header.weight;
4658 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4659 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4660 TM.tmFirstChar = winfnt_header.first_char;
4661 TM.tmLastChar = winfnt_header.last_char;
4662 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4663 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4664 TM.tmItalic = winfnt_header.italic;
4665 TM.tmUnderlined = font->underline;
4666 TM.tmStruckOut = font->strikeout;
4667 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4668 TM.tmCharSet = winfnt_header.charset;
4673 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4674 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4675 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4676 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4677 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4678 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4679 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4680 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4682 TM.tmDigitizedAspectX = 96; /* FIXME */
4683 TM.tmDigitizedAspectY = 96; /* FIXME */
4685 TM.tmLastChar = 255;
4686 TM.tmDefaultChar = 32;
4687 TM.tmBreakChar = 32;
4688 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4689 TM.tmUnderlined = font->underline;
4690 TM.tmStruckOut = font->strikeout;
4691 /* NB inverted meaning of TMPF_FIXED_PITCH */
4692 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4693 TM.tmCharSet = font->charset;
4701 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
4707 scale_x = (float)font->aveWidth * font->font_desc.matrix.eM11;
4708 scale_x /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
4711 scale_x = font->scale_y;
4713 ptm->tmHeight = (float)ptm->tmHeight * font->scale_y;
4714 ptm->tmAscent = (float)ptm->tmAscent * font->scale_y;
4715 ptm->tmDescent = (float)ptm->tmDescent * font->scale_y;
4716 ptm->tmInternalLeading = (float)ptm->tmInternalLeading * font->scale_y;
4717 ptm->tmExternalLeading = (float)ptm->tmExternalLeading * font->scale_y;
4719 ptm->tmAveCharWidth = (float)ptm->tmAveCharWidth * scale_x;
4720 ptm->tmMaxCharWidth = (float)ptm->tmMaxCharWidth * scale_x;
4723 /*************************************************************
4724 * WineEngGetTextMetrics
4727 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4729 EnterCriticalSection( &freetype_cs );
4731 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
4732 if(!get_bitmap_text_metrics(font))
4734 LeaveCriticalSection( &freetype_cs );
4740 LeaveCriticalSection( &freetype_cs );
4743 *ptm = font->potm->otmTextMetrics;
4744 scale_font_metrics(font, ptm);
4745 LeaveCriticalSection( &freetype_cs );
4750 /*************************************************************
4751 * WineEngGetOutlineTextMetrics
4754 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4755 OUTLINETEXTMETRICW *potm)
4757 FT_Face ft_face = font->ft_face;
4758 UINT needed, lenfam, lensty, ret;
4760 TT_HoriHeader *pHori;
4761 TT_Postscript *pPost;
4762 FT_Fixed x_scale, y_scale;
4763 WCHAR *family_nameW, *style_nameW;
4764 static const WCHAR spaceW[] = {' ', '\0'};
4766 INT ascent, descent;
4768 TRACE("font=%p\n", font);
4770 if(!FT_IS_SCALABLE(ft_face))
4773 EnterCriticalSection( &freetype_cs );
4776 if(cbSize >= font->potm->otmSize)
4778 memcpy(potm, font->potm, font->potm->otmSize);
4779 scale_font_metrics(font, &potm->otmTextMetrics);
4781 LeaveCriticalSection( &freetype_cs );
4782 return font->potm->otmSize;
4786 needed = sizeof(*potm);
4788 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
4789 family_nameW = strdupW(font->name);
4791 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
4793 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
4794 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
4795 style_nameW, lensty/sizeof(WCHAR));
4797 /* These names should be read from the TT name table */
4799 /* length of otmpFamilyName */
4802 /* length of otmpFaceName */
4803 if(!strcasecmp(ft_face->style_name, "regular")) {
4804 needed += lenfam; /* just the family name */
4806 needed += lenfam + lensty; /* family + " " + style */
4809 /* length of otmpStyleName */
4812 /* length of otmpFullName */
4813 needed += lenfam + lensty;
4816 x_scale = ft_face->size->metrics.x_scale;
4817 y_scale = ft_face->size->metrics.y_scale;
4819 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4821 FIXME("Can't find OS/2 table - not TT font?\n");
4826 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4828 FIXME("Can't find HHEA table - not TT font?\n");
4833 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
4835 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",
4836 pOS2->usWinAscent, pOS2->usWinDescent,
4837 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
4838 ft_face->ascender, ft_face->descender, ft_face->height,
4839 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
4840 ft_face->bbox.yMax, ft_face->bbox.yMin);
4842 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
4843 font->potm->otmSize = needed;
4845 #define TM font->potm->otmTextMetrics
4847 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
4848 ascent = pHori->Ascender;
4849 descent = -pHori->Descender;
4851 ascent = pOS2->usWinAscent;
4852 descent = pOS2->usWinDescent;
4856 TM.tmAscent = font->yMax;
4857 TM.tmDescent = -font->yMin;
4858 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
4860 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
4861 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
4862 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
4863 - ft_face->units_per_EM, y_scale) + 32) >> 6;
4866 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4869 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4871 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
4872 ((ascent + descent) -
4873 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
4875 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
4876 if (TM.tmAveCharWidth == 0) {
4877 TM.tmAveCharWidth = 1;
4879 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
4880 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
4882 TM.tmDigitizedAspectX = 300;
4883 TM.tmDigitizedAspectY = 300;
4884 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4885 * symbol range to 0 - f0ff
4887 if (font->charset == SYMBOL_CHARSET)
4890 TM.tmFirstChar = pOS2->usFirstCharIndex;
4891 TM.tmLastChar = pOS2->usLastCharIndex;
4892 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4893 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
4894 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4895 TM.tmUnderlined = font->underline;
4896 TM.tmStruckOut = font->strikeout;
4898 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4899 if(!FT_IS_FIXED_WIDTH(ft_face) &&
4900 (pOS2->version == 0xFFFFU ||
4901 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4902 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
4904 TM.tmPitchAndFamily = 0;
4906 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
4907 case PAN_FAMILY_SCRIPT:
4908 TM.tmPitchAndFamily |= FF_SCRIPT;
4910 case PAN_FAMILY_DECORATIVE:
4911 case PAN_FAMILY_PICTORIAL:
4912 TM.tmPitchAndFamily |= FF_DECORATIVE;
4914 case PAN_FAMILY_TEXT_DISPLAY:
4915 if(TM.tmPitchAndFamily == 0) /* fixed */
4916 TM.tmPitchAndFamily = FF_MODERN;
4918 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
4919 case PAN_SERIF_NORMAL_SANS:
4920 case PAN_SERIF_OBTUSE_SANS:
4921 case PAN_SERIF_PERP_SANS:
4922 TM.tmPitchAndFamily |= FF_SWISS;
4925 TM.tmPitchAndFamily |= FF_ROMAN;
4930 TM.tmPitchAndFamily |= FF_DONTCARE;
4933 if(FT_IS_SCALABLE(ft_face))
4934 TM.tmPitchAndFamily |= TMPF_VECTOR;
4936 if(FT_IS_SFNT(ft_face))
4938 if (font->ntmFlags & NTM_PS_OPENTYPE)
4939 TM.tmPitchAndFamily |= TMPF_DEVICE;
4941 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
4944 TM.tmCharSet = font->charset;
4947 font->potm->otmFiller = 0;
4948 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
4949 font->potm->otmfsSelection = pOS2->fsSelection;
4950 font->potm->otmfsType = pOS2->fsType;
4951 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
4952 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
4953 font->potm->otmItalicAngle = 0; /* POST table */
4954 font->potm->otmEMSquare = ft_face->units_per_EM;
4955 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
4956 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4957 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4958 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
4959 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4960 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
4961 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
4962 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
4963 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4964 font->potm->otmMacAscent = 0; /* where do these come from ? */
4965 font->potm->otmMacDescent = 0;
4966 font->potm->otmMacLineGap = 0;
4967 font->potm->otmusMinimumPPEM = 0; /* TT Header */
4968 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
4969 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
4970 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
4971 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
4972 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
4973 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
4974 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
4975 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
4976 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
4977 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4979 font->potm->otmsUnderscoreSize = 0;
4980 font->potm->otmsUnderscorePosition = 0;
4982 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
4983 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
4986 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4987 cp = (char*)font->potm + sizeof(*font->potm);
4988 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4989 strcpyW((WCHAR*)cp, family_nameW);
4991 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4992 strcpyW((WCHAR*)cp, style_nameW);
4994 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4995 strcpyW((WCHAR*)cp, family_nameW);
4996 if(strcasecmp(ft_face->style_name, "regular")) {
4997 strcatW((WCHAR*)cp, spaceW);
4998 strcatW((WCHAR*)cp, style_nameW);
4999 cp += lenfam + lensty;
5002 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5003 strcpyW((WCHAR*)cp, family_nameW);
5004 strcatW((WCHAR*)cp, spaceW);
5005 strcatW((WCHAR*)cp, style_nameW);
5008 if(potm && needed <= cbSize)
5010 memcpy(potm, font->potm, font->potm->otmSize);
5011 scale_font_metrics(font, &potm->otmTextMetrics);
5015 HeapFree(GetProcessHeap(), 0, style_nameW);
5016 HeapFree(GetProcessHeap(), 0, family_nameW);
5018 LeaveCriticalSection( &freetype_cs );
5022 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5024 HFONTLIST *hfontlist;
5025 child->font = alloc_font();
5026 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5027 if(!child->font->ft_face)
5029 free_font(child->font);
5034 child->font->ntmFlags = child->face->ntmFlags;
5035 child->font->orientation = font->orientation;
5036 child->font->scale_y = font->scale_y;
5037 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5038 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5039 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5040 child->font->base_font = font;
5041 list_add_head(&child_font_list, &child->font->entry);
5042 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5046 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5049 CHILD_FONT *child_font;
5052 font = font->base_font;
5054 *linked_font = font;
5056 if((*glyph = get_glyph_index(font, c)))
5059 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5061 if(!child_font->font)
5062 if(!load_child_font(font, child_font))
5065 if(!child_font->font->ft_face)
5067 g = get_glyph_index(child_font->font, c);
5071 *linked_font = child_font->font;
5078 /*************************************************************
5079 * WineEngGetCharWidth
5082 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5087 FT_UInt glyph_index;
5088 GdiFont *linked_font;
5090 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5092 EnterCriticalSection( &freetype_cs );
5093 for(c = firstChar; c <= lastChar; c++) {
5094 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5095 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5096 &gm, 0, NULL, NULL);
5097 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5099 LeaveCriticalSection( &freetype_cs );
5103 /*************************************************************
5104 * WineEngGetCharABCWidths
5107 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5112 FT_UInt glyph_index;
5113 GdiFont *linked_font;
5115 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5117 if(!FT_IS_SCALABLE(font->ft_face))
5120 EnterCriticalSection( &freetype_cs );
5122 for(c = firstChar; c <= lastChar; c++) {
5123 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5124 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5125 &gm, 0, NULL, NULL);
5126 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5127 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5128 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5129 FONT_GM(linked_font,glyph_index)->bbx;
5131 LeaveCriticalSection( &freetype_cs );
5135 /*************************************************************
5136 * WineEngGetCharABCWidthsI
5139 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5144 FT_UInt glyph_index;
5145 GdiFont *linked_font;
5147 if(!FT_HAS_HORIZONTAL(font->ft_face))
5150 EnterCriticalSection( &freetype_cs );
5152 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5154 for(c = firstChar; c < firstChar+count; c++) {
5155 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5156 &gm, 0, NULL, NULL);
5157 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5158 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5159 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5160 - FONT_GM(linked_font,c)->bbx;
5163 for(c = 0; c < count; c++) {
5164 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5165 &gm, 0, NULL, NULL);
5166 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5167 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5168 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5169 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5172 LeaveCriticalSection( &freetype_cs );
5176 /*************************************************************
5177 * WineEngGetTextExtentExPoint
5180 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5181 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5187 FT_UInt glyph_index;
5188 GdiFont *linked_font;
5190 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5193 EnterCriticalSection( &freetype_cs );
5196 WineEngGetTextMetrics(font, &tm);
5197 size->cy = tm.tmHeight;
5199 for(idx = 0; idx < count; idx++) {
5200 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5201 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5202 &gm, 0, NULL, NULL);
5203 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5205 if (! pnfit || ext <= max_ext) {
5215 LeaveCriticalSection( &freetype_cs );
5216 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5220 /*************************************************************
5221 * WineEngGetTextExtentExPointI
5224 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5225 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5232 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5234 EnterCriticalSection( &freetype_cs );
5237 WineEngGetTextMetrics(font, &tm);
5238 size->cy = tm.tmHeight;
5240 for(idx = 0; idx < count; idx++) {
5241 WineEngGetGlyphOutline(font, indices[idx],
5242 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
5244 size->cx += FONT_GM(font,indices[idx])->adv;
5246 if (! pnfit || ext <= max_ext) {
5256 LeaveCriticalSection( &freetype_cs );
5257 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5261 /*************************************************************
5262 * WineEngGetFontData
5265 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5268 FT_Face ft_face = font->ft_face;
5272 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5273 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
5274 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
5276 if(!FT_IS_SFNT(ft_face))
5284 if(table) { /* MS tags differ in endianness from FT ones */
5285 table = table >> 24 | table << 24 |
5286 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
5289 /* make sure value of len is the value freetype says it needs */
5292 FT_ULong needed = 0;
5293 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
5294 if( !err && needed < len) len = needed;
5296 err = load_sfnt_table(ft_face, table, offset, buf, &len);
5299 TRACE("Can't find table %c%c%c%c\n",
5300 /* bytes were reversed */
5301 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
5302 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
5308 /*************************************************************
5309 * WineEngGetTextFace
5312 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5315 lstrcpynW(str, font->name, count);
5316 return strlenW(font->name);
5318 return strlenW(font->name) + 1;
5321 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5323 if (fs) *fs = font->fs;
5324 return font->charset;
5327 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5329 GdiFont *font = dc->gdiFont, *linked_font;
5330 struct list *first_hfont;
5333 EnterCriticalSection( &freetype_cs );
5334 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
5335 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
5336 if(font == linked_font)
5337 *new_hfont = dc->hFont;
5340 first_hfont = list_head(&linked_font->hfontlist);
5341 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
5343 LeaveCriticalSection( &freetype_cs );
5347 /* Retrieve a list of supported Unicode ranges for a given font.
5348 * Can be called with NULL gs to calculate the buffer size. Returns
5349 * the number of ranges found.
5351 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
5353 DWORD num_ranges = 0;
5355 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5358 FT_ULong char_code, char_code_prev;
5361 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
5363 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5364 face->num_glyphs, glyph_code, char_code);
5366 if (!glyph_code) return 0;
5370 gs->ranges[0].wcLow = (USHORT)char_code;
5371 gs->ranges[0].cGlyphs = 0;
5372 gs->cGlyphsSupported = 0;
5378 if (char_code < char_code_prev)
5380 ERR("expected increasing char code from FT_Get_Next_Char\n");
5383 if (char_code - char_code_prev > 1)
5388 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5389 gs->ranges[num_ranges - 1].cGlyphs = 1;
5390 gs->cGlyphsSupported++;
5395 gs->ranges[num_ranges - 1].cGlyphs++;
5396 gs->cGlyphsSupported++;
5398 char_code_prev = char_code;
5399 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
5403 FIXME("encoding %u not supported\n", face->charmap->encoding);
5408 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5411 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
5413 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5416 glyphset->cbThis = size;
5417 glyphset->cRanges = num_ranges;
5422 /*************************************************************
5425 BOOL WineEngFontIsLinked(GdiFont *font)
5428 EnterCriticalSection( &freetype_cs );
5429 ret = !list_empty(&font->child_fonts);
5430 LeaveCriticalSection( &freetype_cs );
5434 static BOOL is_hinting_enabled(void)
5436 /* Use the >= 2.2.0 function if available */
5437 if(pFT_Get_TrueType_Engine_Type)
5439 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
5440 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
5442 #ifdef FT_DRIVER_HAS_HINTER
5447 /* otherwise if we've been compiled with < 2.2.0 headers
5448 use the internal macro */
5449 mod = pFT_Get_Module(library, "truetype");
5450 if(mod && FT_DRIVER_HAS_HINTER(mod))
5458 /*************************************************************************
5459 * GetRasterizerCaps (GDI32.@)
5461 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5463 static int hinting = -1;
5467 hinting = is_hinting_enabled();
5468 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
5471 lprs->nSize = sizeof(RASTERIZER_STATUS);
5472 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
5473 lprs->nLanguageID = 0;
5477 /*************************************************************************
5478 * Kerning support for TrueType fonts
5480 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5482 struct TT_kern_table
5488 struct TT_kern_subtable
5497 USHORT horizontal : 1;
5499 USHORT cross_stream: 1;
5500 USHORT override : 1;
5501 USHORT reserved1 : 4;
5507 struct TT_format0_kern_subtable
5511 USHORT entrySelector;
5522 static DWORD parse_format0_kern_subtable(GdiFont *font,
5523 const struct TT_format0_kern_subtable *tt_f0_ks,
5524 const USHORT *glyph_to_char,
5525 KERNINGPAIR *kern_pair, DWORD cPairs)
5528 const struct TT_kern_pair *tt_kern_pair;
5530 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
5532 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
5534 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5535 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
5536 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
5538 if (!kern_pair || !cPairs)
5541 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
5543 nPairs = min(nPairs, cPairs);
5545 for (i = 0; i < nPairs; i++)
5547 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
5548 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
5549 /* this algorithm appears to better match what Windows does */
5550 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
5551 if (kern_pair->iKernAmount < 0)
5553 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
5554 kern_pair->iKernAmount -= font->ppem;
5556 else if (kern_pair->iKernAmount > 0)
5558 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
5559 kern_pair->iKernAmount += font->ppem;
5561 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
5563 TRACE("left %u right %u value %d\n",
5564 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
5568 TRACE("copied %u entries\n", nPairs);
5572 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5576 const struct TT_kern_table *tt_kern_table;
5577 const struct TT_kern_subtable *tt_kern_subtable;
5579 USHORT *glyph_to_char;
5581 EnterCriticalSection( &freetype_cs );
5582 if (font->total_kern_pairs != (DWORD)-1)
5584 if (cPairs && kern_pair)
5586 cPairs = min(cPairs, font->total_kern_pairs);
5587 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5588 LeaveCriticalSection( &freetype_cs );
5591 LeaveCriticalSection( &freetype_cs );
5592 return font->total_kern_pairs;
5595 font->total_kern_pairs = 0;
5597 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5599 if (length == GDI_ERROR)
5601 TRACE("no kerning data in the font\n");
5602 LeaveCriticalSection( &freetype_cs );
5606 buf = HeapAlloc(GetProcessHeap(), 0, length);
5609 WARN("Out of memory\n");
5610 LeaveCriticalSection( &freetype_cs );
5614 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5616 /* build a glyph index to char code map */
5617 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5620 WARN("Out of memory allocating a glyph index to char code map\n");
5621 HeapFree(GetProcessHeap(), 0, buf);
5622 LeaveCriticalSection( &freetype_cs );
5626 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5632 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5634 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5635 font->ft_face->num_glyphs, glyph_code, char_code);
5639 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5641 /* FIXME: This doesn't match what Windows does: it does some fancy
5642 * things with duplicate glyph index to char code mappings, while
5643 * we just avoid overriding existing entries.
5645 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5646 glyph_to_char[glyph_code] = (USHORT)char_code;
5648 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5655 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5656 for (n = 0; n <= 65535; n++)
5657 glyph_to_char[n] = (USHORT)n;
5660 tt_kern_table = buf;
5661 nTables = GET_BE_WORD(tt_kern_table->nTables);
5662 TRACE("version %u, nTables %u\n",
5663 GET_BE_WORD(tt_kern_table->version), nTables);
5665 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5667 for (i = 0; i < nTables; i++)
5669 struct TT_kern_subtable tt_kern_subtable_copy;
5671 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5672 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5673 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5675 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5676 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
5677 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
5679 /* According to the TrueType specification this is the only format
5680 * that will be properly interpreted by Windows and OS/2
5682 if (tt_kern_subtable_copy.coverage.bits.format == 0)
5684 DWORD new_chunk, old_total = font->total_kern_pairs;
5686 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5687 glyph_to_char, NULL, 0);
5688 font->total_kern_pairs += new_chunk;
5690 if (!font->kern_pairs)
5691 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
5692 font->total_kern_pairs * sizeof(*font->kern_pairs));
5694 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
5695 font->total_kern_pairs * sizeof(*font->kern_pairs));
5697 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5698 glyph_to_char, font->kern_pairs + old_total, new_chunk);
5701 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
5703 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
5706 HeapFree(GetProcessHeap(), 0, glyph_to_char);
5707 HeapFree(GetProcessHeap(), 0, buf);
5709 if (cPairs && kern_pair)
5711 cPairs = min(cPairs, font->total_kern_pairs);
5712 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5713 LeaveCriticalSection( &freetype_cs );
5716 LeaveCriticalSection( &freetype_cs );
5717 return font->total_kern_pairs;
5720 #else /* HAVE_FREETYPE */
5722 /*************************************************************************/
5724 BOOL WineEngInit(void)
5728 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
5732 BOOL WineEngDestroyFontInstance(HFONT hfont)
5737 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
5742 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
5743 LPWORD pgi, DWORD flags)
5748 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
5749 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5752 ERR("called but we don't have FreeType\n");
5756 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5758 ERR("called but we don't have FreeType\n");
5762 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5763 OUTLINETEXTMETRICW *potm)
5765 ERR("called but we don't have FreeType\n");
5769 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5772 ERR("called but we don't have FreeType\n");
5776 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5779 ERR("called but we don't have FreeType\n");
5783 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5786 ERR("called but we don't have FreeType\n");
5790 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5791 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5793 ERR("called but we don't have FreeType\n");
5797 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5798 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5800 ERR("called but we don't have FreeType\n");
5804 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5807 ERR("called but we don't have FreeType\n");
5811 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5813 ERR("called but we don't have FreeType\n");
5817 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5823 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5829 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
5835 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5838 return DEFAULT_CHARSET;
5841 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5846 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5848 FIXME("(%p, %p): stub\n", font, glyphset);
5852 BOOL WineEngFontIsLinked(GdiFont *font)
5857 /*************************************************************************
5858 * GetRasterizerCaps (GDI32.@)
5860 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5862 lprs->nSize = sizeof(RASTERIZER_STATUS);
5864 lprs->nLanguageID = 0;
5868 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5870 ERR("called but we don't have FreeType\n");
5874 #endif /* HAVE_FREETYPE */