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_FTSNAMES_H
106 #include <freetype/ftsnames.h>
108 # ifdef HAVE_FREETYPE_FTNAMES_H
109 # include <freetype/ftnames.h>
112 #ifdef HAVE_FREETYPE_TTNAMEID_H
113 #include <freetype/ttnameid.h>
115 #ifdef HAVE_FREETYPE_FTOUTLN_H
116 #include <freetype/ftoutln.h>
118 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
119 #include <freetype/internal/sfnt.h>
121 #ifdef HAVE_FREETYPE_FTTRIGON_H
122 #include <freetype/fttrigon.h>
124 #ifdef HAVE_FREETYPE_FTWINFNT_H
125 #include <freetype/ftwinfnt.h>
127 #ifdef HAVE_FREETYPE_FTMODAPI_H
128 #include <freetype/ftmodapi.h>
131 #ifndef SONAME_LIBFREETYPE
132 #define SONAME_LIBFREETYPE "libfreetype.so"
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
138 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType;
144 static FT_Library library = 0;
151 static FT_Version_t FT_Version;
152 static DWORD FT_SimpleVersion;
154 static void *ft_handle = NULL;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Vector_Unit);
158 MAKE_FUNCPTR(FT_Done_Face);
159 MAKE_FUNCPTR(FT_Get_Char_Index);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
164 MAKE_FUNCPTR(FT_Init_FreeType);
165 MAKE_FUNCPTR(FT_Load_Glyph);
166 MAKE_FUNCPTR(FT_Matrix_Multiply);
167 MAKE_FUNCPTR(FT_MulFix);
168 MAKE_FUNCPTR(FT_New_Face);
169 MAKE_FUNCPTR(FT_New_Memory_Face);
170 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
171 MAKE_FUNCPTR(FT_Outline_Transform);
172 MAKE_FUNCPTR(FT_Outline_Translate);
173 MAKE_FUNCPTR(FT_Select_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 HAVE_FONTCONFIG_FONTCONFIG_H
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);
198 #ifndef SONAME_LIBFONTCONFIG
199 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
205 #ifndef ft_encoding_none
206 #define FT_ENCODING_NONE ft_encoding_none
208 #ifndef ft_encoding_ms_symbol
209 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
211 #ifndef ft_encoding_unicode
212 #define FT_ENCODING_UNICODE ft_encoding_unicode
214 #ifndef ft_encoding_apple_roman
215 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
218 #ifdef WORDS_BIGENDIAN
219 #define GET_BE_WORD(x) (x)
221 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
224 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
231 FT_Short internal_leading;
234 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
235 So to let this compile on older versions of FreeType we'll define the
236 new structure here. */
238 FT_Short height, width;
239 FT_Pos size, x_ppem, y_ppem;
242 typedef struct tagFace {
250 FONTSIGNATURE fs_links;
251 FT_Fixed font_version;
253 Bitmap_Size size; /* set if face is a bitmap */
254 BOOL external; /* TRUE if we should manually add this font to the registry */
255 struct tagFamily *family;
258 typedef struct tagFamily {
260 const WCHAR *FamilyName;
266 INT adv; /* These three hold to widths of the unrotated chars */
284 typedef struct tagHFONTLIST {
299 struct font_mapping *mapping;
310 struct list hfontlist;
315 OUTLINETEXTMETRICW *potm;
316 DWORD total_kern_pairs;
317 KERNINGPAIR *kern_pairs;
320 struct list child_fonts;
326 const WCHAR *font_name;
330 #define INIT_GM_SIZE 128
332 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
333 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
334 #define UNUSED_CACHE_SIZE 10
335 static struct list child_font_list = LIST_INIT(child_font_list);
336 static struct list system_links = LIST_INIT(system_links);
338 static struct list font_subst_list = LIST_INIT(font_subst_list);
340 static struct list font_list = LIST_INIT(font_list);
342 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
343 static const WCHAR defSans[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
344 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
346 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
348 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
349 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
350 'W','i','n','d','o','w','s','\\',
351 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
352 'F','o','n','t','s','\0'};
354 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
355 'W','i','n','d','o','w','s',' ','N','T','\\',
356 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
357 'F','o','n','t','s','\0'};
359 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
360 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
361 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
362 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
364 static const WCHAR * const SystemFontValues[4] = {
371 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
372 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
374 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
375 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
376 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
377 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
378 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
379 'E','u','r','o','p','e','a','n','\0'};
380 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
381 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
382 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
383 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
384 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
385 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
386 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
387 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
388 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
389 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
390 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
391 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
393 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
403 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
411 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
420 typedef struct tagFontSubst {
436 static struct list mappings_list = LIST_INIT( mappings_list );
438 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
440 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
443 /****************************************
444 * Notes on .fon files
446 * The fonts System, FixedSys and Terminal are special. There are typically multiple
447 * versions installed for different resolutions and codepages. Windows stores which one to use
448 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
450 * FIXEDFON.FON FixedSys
452 * OEMFONT.FON Terminal
453 * LogPixels Current dpi set by the display control panel applet
454 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
455 * also has a LogPixels value that appears to mirror this)
457 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
458 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
459 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
460 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
461 * so that makes sense.
463 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
464 * to be mapped into the registry on Windows 2000 at least).
467 * ega80woa.fon=ega80850.fon
468 * ega40woa.fon=ega40850.fon
469 * cga80woa.fon=cga80850.fon
470 * cga40woa.fon=cga40850.fon
473 #ifdef HAVE_CARBON_CARBON_H
474 static char *find_cache_dir(void)
478 static char cached_path[MAX_PATH];
479 static const char *wine = "/Wine", *fonts = "/Fonts";
481 if(*cached_path) return cached_path;
483 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
486 WARN("can't create cached data folder\n");
489 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
492 WARN("can't create cached data path\n");
496 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
498 ERR("Could not create full path\n");
502 strcat(cached_path, wine);
504 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
506 WARN("Couldn't mkdir %s\n", cached_path);
510 strcat(cached_path, fonts);
511 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
513 WARN("Couldn't mkdir %s\n", cached_path);
520 /******************************************************************
523 * Extracts individual TrueType font files from a Mac suitcase font
524 * and saves them into the user's caches directory (see
526 * Returns a NULL terminated array of filenames.
528 * We do this because they are apps that try to read ttf files
529 * themselves and they don't like Mac suitcase files.
531 static char **expand_mac_font(const char *path)
538 const char *filename;
542 unsigned int size, max_size;
545 TRACE("path %s\n", path);
547 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
550 WARN("failed to get ref\n");
554 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
557 TRACE("no data fork, so trying resource fork\n");
558 res_ref = FSOpenResFile(&ref, fsRdPerm);
561 TRACE("unable to open resource fork\n");
568 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
571 CloseResFile(res_ref);
575 out_dir = find_cache_dir();
577 filename = strrchr(path, '/');
578 if(!filename) filename = path;
581 /* output filename has the form out_dir/filename_%04x.ttf */
582 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
589 unsigned short *num_faces_ptr, num_faces, face;
593 fond = Get1IndResource('FOND', idx);
595 TRACE("got fond resource %d\n", idx);
598 fam_rec = *(FamRec**)fond;
599 num_faces_ptr = (unsigned short *)(fam_rec + 1);
600 num_faces = GET_BE_WORD(*num_faces_ptr);
602 assoc = (AsscEntry*)(num_faces_ptr + 1);
603 TRACE("num faces %04x\n", num_faces);
604 for(face = 0; face < num_faces; face++, assoc++)
607 unsigned short size, font_id;
610 size = GET_BE_WORD(assoc->fontSize);
611 font_id = GET_BE_WORD(assoc->fontID);
614 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
618 TRACE("trying to load sfnt id %04x\n", font_id);
619 sfnt = GetResource('sfnt', font_id);
622 TRACE("can't get sfnt resource %04x\n", font_id);
626 output = HeapAlloc(GetProcessHeap(), 0, output_len);
631 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
633 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
634 if(fd != -1 || errno == EEXIST)
638 unsigned char *sfnt_data;
641 sfnt_data = *(unsigned char**)sfnt;
642 write(fd, sfnt_data, GetHandleSize(sfnt));
646 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
649 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
651 ret.array[ret.size++] = output;
655 WARN("unable to create %s\n", output);
656 HeapFree(GetProcessHeap(), 0, output);
659 ReleaseResource(sfnt);
662 ReleaseResource(fond);
665 CloseResFile(res_ref);
670 #endif /* HAVE_CARBON_CARBON_H */
672 static inline BOOL is_win9x(void)
674 return GetVersion() & 0x80000000;
677 This function builds an FT_Fixed from a float. It puts the integer part
678 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
679 It fails if the integer part of the float number is greater than SHORT_MAX.
681 static inline FT_Fixed FT_FixedFromFloat(float f)
684 unsigned short fract = (f - value) * 0xFFFF;
685 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
689 This function builds an FT_Fixed from a FIXED. It simply put f.value
690 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
692 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
694 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
698 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
703 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
704 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
706 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
707 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
709 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
711 if(face_name && strcmpiW(face_name, family->FamilyName))
713 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
715 file = strrchr(face->file, '/');
720 if(!strcasecmp(file, file_nameA))
722 HeapFree(GetProcessHeap(), 0, file_nameA);
727 HeapFree(GetProcessHeap(), 0, file_nameA);
731 static Family *find_family_from_name(const WCHAR *name)
735 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
737 if(!strcmpiW(family->FamilyName, name))
744 static void DumpSubstList(void)
748 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
750 if(psub->from.charset != -1 || psub->to.charset != -1)
751 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
752 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
754 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
755 debugstr_w(psub->to.name));
760 static LPWSTR strdupW(LPCWSTR p)
763 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
764 ret = HeapAlloc(GetProcessHeap(), 0, len);
769 static LPSTR strdupA(LPCSTR p)
772 DWORD len = (strlen(p) + 1);
773 ret = HeapAlloc(GetProcessHeap(), 0, len);
778 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
783 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
785 if(!strcmpiW(element->from.name, from_name) &&
786 (element->from.charset == from_charset ||
787 element->from.charset == -1))
794 #define ADD_FONT_SUBST_FORCE 1
796 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
798 FontSubst *from_exist, *to_exist;
800 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
802 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
804 list_remove(&from_exist->entry);
805 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
806 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
807 HeapFree(GetProcessHeap(), 0, from_exist);
813 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
817 HeapFree(GetProcessHeap(), 0, subst->to.name);
818 subst->to.name = strdupW(to_exist->to.name);
821 list_add_tail(subst_list, &subst->entry);
826 HeapFree(GetProcessHeap(), 0, subst->from.name);
827 HeapFree(GetProcessHeap(), 0, subst->to.name);
828 HeapFree(GetProcessHeap(), 0, subst);
832 static void split_subst_info(NameCs *nc, LPSTR str)
834 CHAR *p = strrchr(str, ',');
839 nc->charset = strtol(p+1, NULL, 10);
842 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
843 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
844 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
847 static void LoadSubstList(void)
851 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
855 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
856 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
857 &hkey) == ERROR_SUCCESS) {
859 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
860 &valuelen, &datalen, NULL, NULL);
862 valuelen++; /* returned value doesn't include room for '\0' */
863 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
864 data = HeapAlloc(GetProcessHeap(), 0, datalen);
868 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
869 &dlen) == ERROR_SUCCESS) {
870 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
872 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
873 split_subst_info(&psub->from, value);
874 split_subst_info(&psub->to, data);
876 /* Win 2000 doesn't allow mapping between different charsets
877 or mapping of DEFAULT_CHARSET */
878 if((psub->to.charset != psub->from.charset) ||
879 psub->to.charset == DEFAULT_CHARSET) {
880 HeapFree(GetProcessHeap(), 0, psub->to.name);
881 HeapFree(GetProcessHeap(), 0, psub->from.name);
882 HeapFree(GetProcessHeap(), 0, psub);
884 add_font_subst(&font_subst_list, psub, 0);
886 /* reset dlen and vlen */
890 HeapFree(GetProcessHeap(), 0, data);
891 HeapFree(GetProcessHeap(), 0, value);
896 static WCHAR *get_familyname(FT_Face ft_face)
898 WCHAR *family = NULL;
900 FT_UInt num_names, name_index, i;
902 if(FT_IS_SFNT(ft_face))
904 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
906 for(name_index = 0; name_index < num_names; name_index++)
908 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
910 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
911 (name.language_id == GetUserDefaultLCID()) &&
912 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
913 (name.encoding_id == TT_MS_ID_UNICODE_CS))
915 /* String is not nul terminated and string_len is a byte length. */
916 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
917 for(i = 0; i < name.string_len / 2; i++)
919 WORD *tmp = (WORD *)&name.string[i * 2];
920 family[i] = GET_BE_WORD(*tmp);
924 TRACE("Got localised name %s\n", debugstr_w(family));
935 #define ADDFONT_EXTERNAL_FONT 0x01
936 #define ADDFONT_FORCE_BITMAP 0x02
937 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
941 TT_Header *pHeader = NULL;
942 WCHAR *english_family, *localised_family, *StyleW;
946 struct list *family_elem_ptr, *face_elem_ptr;
948 FT_Long face_index = 0, num_faces;
949 #ifdef HAVE_FREETYPE_FTWINFNT_H
950 FT_WinFNT_HeaderRec winfnt_header;
952 int i, bitmap_num, internal_leading;
955 #ifdef HAVE_CARBON_CARBON_H
958 char **mac_list = expand_mac_font(file);
961 BOOL had_one = FALSE;
963 for(cursor = mac_list; *cursor; cursor++)
966 AddFontFileToList(*cursor, NULL, flags);
967 HeapFree(GetProcessHeap(), 0, *cursor);
969 HeapFree(GetProcessHeap(), 0, mac_list);
974 #endif /* HAVE_CARBON_CARBON_H */
977 char *family_name = fake_family;
979 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
980 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
981 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
985 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*/
986 WARN("Ignoring font %s\n", debugstr_a(file));
987 pFT_Done_Face(ft_face);
991 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
992 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
993 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file));
994 pFT_Done_Face(ft_face);
998 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
999 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1000 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
1001 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
1002 "Skipping this font.\n", debugstr_a(file));
1003 pFT_Done_Face(ft_face);
1007 if(!ft_face->family_name || !ft_face->style_name) {
1008 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
1009 pFT_Done_Face(ft_face);
1014 family_name = ft_face->family_name;
1018 My_FT_Bitmap_Size *size = NULL;
1020 if(!FT_IS_SCALABLE(ft_face))
1021 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1023 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1024 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1025 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1027 localised_family = NULL;
1029 localised_family = get_familyname(ft_face);
1030 if(localised_family && !strcmpW(localised_family, english_family)) {
1031 HeapFree(GetProcessHeap(), 0, localised_family);
1032 localised_family = NULL;
1037 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1038 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1039 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1044 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1045 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1046 list_init(&family->faces);
1047 list_add_tail(&font_list, &family->entry);
1049 if(localised_family) {
1050 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1051 subst->from.name = strdupW(english_family);
1052 subst->from.charset = -1;
1053 subst->to.name = strdupW(localised_family);
1054 subst->to.charset = -1;
1055 add_font_subst(&font_subst_list, subst, 0);
1058 HeapFree(GetProcessHeap(), 0, localised_family);
1059 HeapFree(GetProcessHeap(), 0, english_family);
1061 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1062 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1063 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1065 internal_leading = 0;
1066 memset(&fs, 0, sizeof(fs));
1068 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1070 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1071 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1072 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1073 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1074 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1075 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1076 if(pOS2->version == 0) {
1079 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1082 fs.fsCsb[0] |= 1L << 31;
1085 #ifdef HAVE_FREETYPE_FTWINFNT_H
1086 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1088 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1089 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1090 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1091 memcpy(&fs, &csi.fs, sizeof(csi.fs));
1092 internal_leading = winfnt_header.internal_leading;
1096 face_elem_ptr = list_head(&family->faces);
1097 while(face_elem_ptr) {
1098 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1099 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1100 if(!strcmpW(face->StyleName, StyleW) &&
1101 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1102 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1103 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1104 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1107 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1108 HeapFree(GetProcessHeap(), 0, StyleW);
1109 pFT_Done_Face(ft_face);
1112 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1113 TRACE("Original font is newer so skipping this one\n");
1114 HeapFree(GetProcessHeap(), 0, StyleW);
1115 pFT_Done_Face(ft_face);
1118 TRACE("Replacing original with this one\n");
1119 list_remove(&face->entry);
1120 HeapFree(GetProcessHeap(), 0, face->file);
1121 HeapFree(GetProcessHeap(), 0, face->StyleName);
1122 HeapFree(GetProcessHeap(), 0, face);
1127 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1128 list_add_tail(&family->faces, &face->entry);
1129 face->StyleName = StyleW;
1130 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
1131 strcpy(face->file, file);
1132 face->face_index = face_index;
1133 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
1134 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
1135 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1136 face->family = family;
1137 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1138 memcpy(&face->fs, &fs, sizeof(face->fs));
1139 memset(&face->fs_links, 0, sizeof(face->fs_links));
1141 if(FT_IS_SCALABLE(ft_face)) {
1142 memset(&face->size, 0, sizeof(face->size));
1143 face->scalable = TRUE;
1145 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1146 size->height, size->width, size->size >> 6,
1147 size->x_ppem >> 6, size->y_ppem >> 6);
1148 face->size.height = size->height;
1149 face->size.width = size->width;
1150 face->size.size = size->size;
1151 face->size.x_ppem = size->x_ppem;
1152 face->size.y_ppem = size->y_ppem;
1153 face->size.internal_leading = internal_leading;
1154 face->scalable = FALSE;
1157 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1158 face->fs.fsCsb[0], face->fs.fsCsb[1],
1159 face->fs.fsUsb[0], face->fs.fsUsb[1],
1160 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1163 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1164 for(i = 0; i < ft_face->num_charmaps; i++) {
1165 switch(ft_face->charmaps[i]->encoding) {
1166 case FT_ENCODING_UNICODE:
1167 case FT_ENCODING_APPLE_ROMAN:
1168 face->fs.fsCsb[0] |= 1;
1170 case FT_ENCODING_MS_SYMBOL:
1171 face->fs.fsCsb[0] |= 1L << 31;
1179 if(face->fs.fsCsb[0] & ~(1L << 31))
1180 have_installed_roman_font = TRUE;
1181 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1183 num_faces = ft_face->num_faces;
1184 pFT_Done_Face(ft_face);
1185 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1186 debugstr_w(StyleW));
1187 } while(num_faces > ++face_index);
1191 static void DumpFontList(void)
1195 struct list *family_elem_ptr, *face_elem_ptr;
1197 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1198 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1199 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1200 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1201 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1202 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1204 TRACE(" %d", face->size.height);
1211 /***********************************************************
1212 * The replacement list is a way to map an entire font
1213 * family onto another family. For example adding
1215 * [HKCU\Software\Wine\Fonts\Replacements]
1216 * "Wingdings"="Winedings"
1218 * would enumerate the Winedings font both as Winedings and
1219 * Wingdings. However if a real Wingdings font is present the
1220 * replacement does not take place.
1223 static void LoadReplaceList(void)
1226 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1231 struct list *family_elem_ptr, *face_elem_ptr;
1232 WCHAR old_nameW[200];
1234 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1235 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1237 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1238 &valuelen, &datalen, NULL, NULL);
1240 valuelen++; /* returned value doesn't include room for '\0' */
1241 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1242 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1246 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1247 &dlen) == ERROR_SUCCESS) {
1248 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1249 /* "NewName"="Oldname" */
1250 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)/sizeof(WCHAR)))
1253 /* Find the old family and hence all of the font files
1255 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1256 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1257 if(!strcmpiW(family->FamilyName, old_nameW)) {
1258 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1259 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1260 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1261 debugstr_w(face->StyleName), value);
1262 /* Now add a new entry with the new family name */
1263 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1268 /* reset dlen and vlen */
1272 HeapFree(GetProcessHeap(), 0, data);
1273 HeapFree(GetProcessHeap(), 0, value);
1278 /*************************************************************
1281 static BOOL init_system_links(void)
1283 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1284 'W','i','n','d','o','w','s',' ','N','T','\\',
1285 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1286 'S','y','s','t','e','m','L','i','n','k',0};
1289 DWORD type, max_val, max_data, val_len, data_len, index;
1290 WCHAR *value, *data;
1291 WCHAR *entry, *next;
1292 SYSTEM_LINKS *font_link, *system_font_link;
1293 CHILD_FONT *child_font;
1294 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1295 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1296 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1302 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1304 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1305 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1306 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1307 val_len = max_val + 1;
1308 data_len = max_data;
1310 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1312 TRACE("%s:\n", debugstr_w(value));
1314 memset(&fs, 0, sizeof(fs));
1315 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1316 psub = get_font_subst(&font_subst_list, value, -1);
1317 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1318 list_init(&font_link->links);
1319 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1322 CHILD_FONT *child_font;
1324 TRACE("\t%s\n", debugstr_w(entry));
1326 next = entry + strlenW(entry) + 1;
1328 face_name = strchrW(entry, ',');
1332 while(isspaceW(*face_name))
1335 psub = get_font_subst(&font_subst_list, face_name, -1);
1337 face_name = psub->to.name;
1339 face = find_face_from_filename(entry, face_name);
1342 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1346 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1347 child_font->file_name = strdupA(face->file);
1348 child_font->index = face->face_index;
1349 child_font->font = NULL;
1350 fs.fsCsb[0] |= face->fs.fsCsb[0];
1351 fs.fsCsb[1] |= face->fs.fsCsb[1];
1352 TRACE("Adding file %s index %d\n", child_font->file_name, child_font->index);
1353 list_add_tail(&font_link->links, &child_font->entry);
1355 family = find_family_from_name(font_link->font_name);
1358 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1360 memcpy(&face->fs_links, &fs, sizeof(fs));
1363 list_add_tail(&system_links, &font_link->entry);
1364 val_len = max_val + 1;
1365 data_len = max_data;
1368 HeapFree(GetProcessHeap(), 0, value);
1369 HeapFree(GetProcessHeap(), 0, data);
1373 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1376 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1377 system_font_link->font_name = strdupW(System);
1378 list_init(&system_font_link->links);
1380 face = find_face_from_filename(tahoma_ttf, Tahoma);
1383 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1384 child_font->file_name = strdupA(face->file);
1385 child_font->index = face->face_index;
1386 child_font->font = NULL;
1387 TRACE("Found Tahoma in %s index %d\n", child_font->file_name, child_font->index);
1388 list_add_tail(&system_font_link->links, &child_font->entry);
1390 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1392 if(!strcmpiW(font_link->font_name, Tahoma))
1394 CHILD_FONT *font_link_entry;
1395 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1397 CHILD_FONT *new_child;
1398 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1399 new_child->file_name = strdupA(font_link_entry->file_name);
1400 new_child->index = font_link_entry->index;
1401 new_child->font = NULL;
1402 list_add_tail(&system_font_link->links, &new_child->entry);
1407 list_add_tail(&system_links, &system_font_link->entry);
1411 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1414 struct dirent *dent;
1415 char path[MAX_PATH];
1417 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1419 dir = opendir(dirname);
1421 WARN("Can't open directory %s\n", debugstr_a(dirname));
1424 while((dent = readdir(dir)) != NULL) {
1425 struct stat statbuf;
1427 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1430 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1432 sprintf(path, "%s/%s", dirname, dent->d_name);
1434 if(stat(path, &statbuf) == -1)
1436 WARN("Can't stat %s\n", debugstr_a(path));
1439 if(S_ISDIR(statbuf.st_mode))
1440 ReadFontDir(path, external_fonts);
1442 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1448 static void load_fontconfig_fonts(void)
1450 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1451 void *fc_handle = NULL;
1460 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1462 TRACE("Wine cannot find the fontconfig library (%s).\n",
1463 SONAME_LIBFONTCONFIG);
1466 #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;}
1467 LOAD_FUNCPTR(FcConfigGetCurrent);
1468 LOAD_FUNCPTR(FcFontList);
1469 LOAD_FUNCPTR(FcFontSetDestroy);
1470 LOAD_FUNCPTR(FcInit);
1471 LOAD_FUNCPTR(FcObjectSetAdd);
1472 LOAD_FUNCPTR(FcObjectSetCreate);
1473 LOAD_FUNCPTR(FcObjectSetDestroy);
1474 LOAD_FUNCPTR(FcPatternCreate);
1475 LOAD_FUNCPTR(FcPatternDestroy);
1476 LOAD_FUNCPTR(FcPatternGetBool);
1477 LOAD_FUNCPTR(FcPatternGetString);
1480 if(!pFcInit()) return;
1482 config = pFcConfigGetCurrent();
1483 pat = pFcPatternCreate();
1484 os = pFcObjectSetCreate();
1485 pFcObjectSetAdd(os, FC_FILE);
1486 pFcObjectSetAdd(os, FC_SCALABLE);
1487 fontset = pFcFontList(config, pat, os);
1488 if(!fontset) return;
1489 for(i = 0; i < fontset->nfont; i++) {
1492 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1494 TRACE("fontconfig: %s\n", file);
1496 /* We're just interested in OT/TT fonts for now, so this hack just
1497 picks up the scalable fonts without extensions .pf[ab] to save time
1498 loading every other font */
1500 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1502 TRACE("not scalable\n");
1506 len = strlen( file );
1507 if(len < 4) continue;
1508 ext = &file[ len - 3 ];
1509 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1510 AddFontFileToList(file, NULL, ADDFONT_EXTERNAL_FONT);
1512 pFcFontSetDestroy(fontset);
1513 pFcObjectSetDestroy(os);
1514 pFcPatternDestroy(pat);
1520 static BOOL load_font_from_data_dir(LPCWSTR file)
1523 const char *data_dir = wine_get_data_dir();
1525 if (!data_dir) data_dir = wine_get_build_dir();
1532 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1534 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1536 strcpy(unix_name, data_dir);
1537 strcat(unix_name, "/fonts/");
1539 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1541 ret = AddFontFileToList(unix_name, NULL, ADDFONT_FORCE_BITMAP);
1542 HeapFree(GetProcessHeap(), 0, unix_name);
1547 static void load_system_fonts(void)
1550 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1551 const WCHAR * const *value;
1553 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1556 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1557 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1558 strcatW(windowsdir, fontsW);
1559 for(value = SystemFontValues; *value; value++) {
1560 dlen = sizeof(data);
1561 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1565 sprintfW(pathW, fmtW, windowsdir, data);
1566 if((unixname = wine_get_unix_file_name(pathW))) {
1567 added = AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1568 HeapFree(GetProcessHeap(), 0, unixname);
1571 load_font_from_data_dir(data);
1578 /*************************************************************
1580 * This adds registry entries for any externally loaded fonts
1581 * (fonts from fontconfig or FontDirs). It also deletes entries
1582 * of no longer existing fonts.
1585 static void update_reg_entries(void)
1587 HKEY winkey = 0, externalkey = 0;
1590 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1593 struct list *family_elem_ptr, *face_elem_ptr;
1595 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1596 static const WCHAR spaceW[] = {' ', '\0'};
1599 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1600 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1601 ERR("Can't create Windows font reg key\n");
1604 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1605 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1606 ERR("Can't create external font reg key\n");
1610 /* Delete all external fonts added last time */
1612 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1613 &valuelen, &datalen, NULL, NULL);
1614 valuelen++; /* returned value doesn't include room for '\0' */
1615 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1616 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1618 dlen = datalen * sizeof(WCHAR);
1621 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1622 &dlen) == ERROR_SUCCESS) {
1624 RegDeleteValueW(winkey, valueW);
1625 /* reset dlen and vlen */
1629 HeapFree(GetProcessHeap(), 0, data);
1630 HeapFree(GetProcessHeap(), 0, valueW);
1632 /* Delete the old external fonts key */
1633 RegCloseKey(externalkey);
1635 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1637 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1638 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1639 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1640 ERR("Can't create external font reg key\n");
1644 /* enumerate the fonts and add external ones to the two keys */
1646 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1647 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1648 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1649 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1650 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1651 if(!face->external) continue;
1653 if(strcmpiW(face->StyleName, RegularW))
1654 len = len_fam + strlenW(face->StyleName) + 1;
1655 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1656 strcpyW(valueW, family->FamilyName);
1657 if(len != len_fam) {
1658 strcatW(valueW, spaceW);
1659 strcatW(valueW, face->StyleName);
1661 strcatW(valueW, TrueType);
1662 if((path = strrchr(face->file, '/')) == NULL)
1666 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1668 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1669 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1670 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1671 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1673 HeapFree(GetProcessHeap(), 0, file);
1674 HeapFree(GetProcessHeap(), 0, valueW);
1679 RegCloseKey(externalkey);
1681 RegCloseKey(winkey);
1686 /*************************************************************
1687 * WineEngAddFontResourceEx
1690 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1692 if (ft_handle) /* do it only if we have freetype up and running */
1697 FIXME("Ignoring flags %x\n", flags);
1699 if((unixname = wine_get_unix_file_name(file)))
1701 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1702 HeapFree(GetProcessHeap(), 0, unixname);
1708 /*************************************************************
1709 * WineEngRemoveFontResourceEx
1712 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1718 static const struct nls_update_font_list
1720 UINT ansi_cp, oem_cp;
1721 const char *oem, *fixed, *system;
1722 const char *courier, *serif, *small, *sserif;
1723 } nls_update_font_list[] =
1725 /* Latin 1 (United States) */
1726 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1727 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1729 /* Latin 1 (Multilingual) */
1730 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1731 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1733 /* Eastern Europe */
1734 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1735 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1738 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1739 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1742 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1743 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1746 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1747 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1750 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1751 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1754 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1755 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1758 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1759 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1762 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1763 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1766 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1767 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1770 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1771 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1773 /* Chinese Simplified */
1774 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1775 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1778 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1779 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1781 /* Chinese Traditional */
1782 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1783 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1787 inline static HKEY create_fonts_NT_registry_key(void)
1791 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1792 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1796 inline static HKEY create_fonts_9x_registry_key(void)
1800 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1801 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1805 inline static HKEY create_config_fonts_registry_key(void)
1809 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1810 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1814 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1816 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1817 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1818 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1819 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1822 static void update_font_info(void)
1824 char buf[40], cpbuf[40];
1827 UINT i, ansi_cp = 0, oem_cp = 0;
1829 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
1832 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1833 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1834 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1835 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1836 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
1839 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1841 if (!strcmp( buf, cpbuf )) /* already set correctly */
1846 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
1848 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
1850 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
1853 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1855 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1856 nls_update_font_list[i].oem_cp == oem_cp)
1860 hkey = create_config_fonts_registry_key();
1861 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1862 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1863 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1866 hkey = create_fonts_NT_registry_key();
1867 add_font_list(hkey, &nls_update_font_list[i]);
1870 hkey = create_fonts_9x_registry_key();
1871 add_font_list(hkey, &nls_update_font_list[i]);
1877 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
1880 /*************************************************************
1883 * Initialize FreeType library and create a list of available faces
1885 BOOL WineEngInit(void)
1887 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1888 static const WCHAR pathW[] = {'P','a','t','h',0};
1890 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1892 WCHAR windowsdir[MAX_PATH];
1895 const char *data_dir;
1899 /* update locale dependent font info in registry */
1902 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1905 "Wine cannot find the FreeType font library. To enable Wine to\n"
1906 "use TrueType fonts please install a version of FreeType greater than\n"
1907 "or equal to 2.0.5.\n"
1908 "http://www.freetype.org\n");
1912 #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;}
1914 LOAD_FUNCPTR(FT_Vector_Unit)
1915 LOAD_FUNCPTR(FT_Done_Face)
1916 LOAD_FUNCPTR(FT_Get_Char_Index)
1917 LOAD_FUNCPTR(FT_Get_Module)
1918 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1919 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1920 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1921 LOAD_FUNCPTR(FT_Init_FreeType)
1922 LOAD_FUNCPTR(FT_Load_Glyph)
1923 LOAD_FUNCPTR(FT_Matrix_Multiply)
1924 LOAD_FUNCPTR(FT_MulFix)
1925 LOAD_FUNCPTR(FT_New_Face)
1926 LOAD_FUNCPTR(FT_New_Memory_Face)
1927 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1928 LOAD_FUNCPTR(FT_Outline_Transform)
1929 LOAD_FUNCPTR(FT_Outline_Translate)
1930 LOAD_FUNCPTR(FT_Select_Charmap)
1931 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1932 LOAD_FUNCPTR(FT_Vector_Transform)
1935 /* Don't warn if this one is missing */
1936 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1937 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1938 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1939 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
1940 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
1941 #ifdef HAVE_FREETYPE_FTWINFNT_H
1942 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1944 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1945 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1946 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1947 <= 2.0.3 has FT_Sqrt64 */
1951 if(pFT_Init_FreeType(&library) != 0) {
1952 ERR("Can't init FreeType library\n");
1953 wine_dlclose(ft_handle, NULL, 0);
1957 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1958 if (pFT_Library_Version)
1960 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1962 if (FT_Version.major<=0)
1968 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1969 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1970 ((FT_Version.minor << 8) & 0x00ff00) |
1971 ((FT_Version.patch ) & 0x0000ff);
1973 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1974 ERR("Failed to create font mutex\n");
1977 WaitForSingleObject(font_mutex, INFINITE);
1979 /* load the system bitmap fonts */
1980 load_system_fonts();
1982 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1983 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1984 strcatW(windowsdir, fontsW);
1985 if((unixname = wine_get_unix_file_name(windowsdir)))
1987 ReadFontDir(unixname, FALSE);
1988 HeapFree(GetProcessHeap(), 0, unixname);
1991 /* load the system truetype fonts */
1992 data_dir = wine_get_data_dir();
1993 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
1994 strcpy(unixname, data_dir);
1995 strcat(unixname, "/fonts/");
1996 ReadFontDir(unixname, FALSE);
1997 HeapFree(GetProcessHeap(), 0, unixname);
2000 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2001 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2002 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2004 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2005 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2006 &hkey) == ERROR_SUCCESS) {
2008 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2009 &valuelen, &datalen, NULL, NULL);
2011 valuelen++; /* returned value doesn't include room for '\0' */
2012 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2013 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2016 dlen = datalen * sizeof(WCHAR);
2018 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2019 &dlen) == ERROR_SUCCESS) {
2020 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2022 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2024 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
2025 HeapFree(GetProcessHeap(), 0, unixname);
2028 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2030 WCHAR pathW[MAX_PATH];
2031 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2034 sprintfW(pathW, fmtW, windowsdir, data);
2035 if((unixname = wine_get_unix_file_name(pathW)))
2037 added = AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
2038 HeapFree(GetProcessHeap(), 0, unixname);
2041 load_font_from_data_dir(data);
2043 /* reset dlen and vlen */
2048 HeapFree(GetProcessHeap(), 0, data);
2049 HeapFree(GetProcessHeap(), 0, valueW);
2053 load_fontconfig_fonts();
2055 /* then look in any directories that we've specified in the config file */
2056 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2057 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2063 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2065 len += sizeof(WCHAR);
2066 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2067 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2069 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2070 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2071 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2072 TRACE( "got font path %s\n", debugstr_a(valueA) );
2076 LPSTR next = strchr( ptr, ':' );
2077 if (next) *next++ = 0;
2078 ReadFontDir( ptr, TRUE );
2081 HeapFree( GetProcessHeap(), 0, valueA );
2083 HeapFree( GetProcessHeap(), 0, valueW );
2092 update_reg_entries();
2094 init_system_links();
2096 ReleaseMutex(font_mutex);
2100 "Wine cannot find certain functions that it needs inside the FreeType\n"
2101 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2102 "FreeType to at least version 2.0.5.\n"
2103 "http://www.freetype.org\n");
2104 wine_dlclose(ft_handle, NULL, 0);
2110 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2113 TT_HoriHeader *pHori;
2117 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2118 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2120 if(height == 0) height = 16;
2122 /* Calc. height of EM square:
2124 * For +ve lfHeight we have
2125 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2126 * Re-arranging gives:
2127 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2129 * For -ve lfHeight we have
2131 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2132 * with il = winAscent + winDescent - units_per_em]
2137 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2138 ppem = ft_face->units_per_EM * height /
2139 (pHori->Ascender - pHori->Descender);
2141 ppem = ft_face->units_per_EM * height /
2142 (pOS2->usWinAscent + pOS2->usWinDescent);
2150 static struct font_mapping *map_font( const char *name )
2152 #ifndef __APPLE__ /* Mac OS fonts use resource forks, we can't simply mmap them */
2153 struct font_mapping *mapping;
2157 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2158 if (fstat( fd, &st ) == -1) goto error;
2160 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2162 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2164 mapping->refcount++;
2169 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2172 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2175 if (mapping->data == MAP_FAILED)
2177 HeapFree( GetProcessHeap(), 0, mapping );
2180 mapping->refcount = 1;
2181 mapping->dev = st.st_dev;
2182 mapping->ino = st.st_ino;
2183 mapping->size = st.st_size;
2184 list_add_tail( &mappings_list, &mapping->entry );
2193 static void unmap_font( struct font_mapping *mapping )
2195 if (!--mapping->refcount)
2197 list_remove( &mapping->entry );
2198 munmap( mapping->data, mapping->size );
2199 HeapFree( GetProcessHeap(), 0, mapping );
2203 static LONG load_VDMX(GdiFont*, LONG);
2205 static FT_Face OpenFontFile(GdiFont *font, char *file, FT_Long face_index, LONG width, LONG height)
2210 TRACE("%s, %ld, %d x %d\n", debugstr_a(file), face_index, width, height);
2212 if ((font->mapping = map_font( file )))
2213 err = pFT_New_Memory_Face(library, font->mapping->data, font->mapping->size, face_index, &ft_face);
2215 err = pFT_New_Face(library, file, face_index, &ft_face);
2218 ERR("FT_New_Face rets %d\n", err);
2222 /* set it here, as load_VDMX needs it */
2223 font->ft_face = ft_face;
2225 if(FT_IS_SCALABLE(ft_face)) {
2226 /* load the VDMX table if we have one */
2227 font->ppem = load_VDMX(font, height);
2229 font->ppem = calc_ppem_for_height(ft_face, height);
2231 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2232 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2234 font->ppem = height;
2235 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2236 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2242 static int get_nearest_charset(Face *face, int *cp)
2244 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2245 a single face with the requested charset. The idea is to check if
2246 the selected font supports the current ANSI codepage, if it does
2247 return the corresponding charset, else return the first charset */
2250 int acp = GetACP(), i;
2254 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2255 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2256 return csi.ciCharset;
2258 for(i = 0; i < 32; i++) {
2260 if(face->fs.fsCsb[0] & fs0) {
2261 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2263 return csi.ciCharset;
2266 FIXME("TCI failing on %x\n", fs0);
2270 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2271 face->fs.fsCsb[0], face->file);
2273 return DEFAULT_CHARSET;
2276 static GdiFont *alloc_font(void)
2278 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2279 ret->gmsize = INIT_GM_SIZE;
2280 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2281 ret->gmsize * sizeof(*ret->gm));
2283 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2284 ret->total_kern_pairs = (DWORD)-1;
2285 ret->kern_pairs = NULL;
2286 list_init(&ret->hfontlist);
2287 list_init(&ret->child_fonts);
2291 static void free_font(GdiFont *font)
2293 struct list *cursor, *cursor2;
2295 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2297 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2298 struct list *first_hfont;
2299 HFONTLIST *hfontlist;
2300 list_remove(cursor);
2303 first_hfont = list_head(&child->font->hfontlist);
2304 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2305 DeleteObject(hfontlist->hfont);
2306 HeapFree(GetProcessHeap(), 0, hfontlist);
2307 free_font(child->font);
2309 HeapFree(GetProcessHeap(), 0, child->file_name);
2310 HeapFree(GetProcessHeap(), 0, child);
2313 if (font->ft_face) pFT_Done_Face(font->ft_face);
2314 if (font->mapping) unmap_font( font->mapping );
2315 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2316 HeapFree(GetProcessHeap(), 0, font->potm);
2317 HeapFree(GetProcessHeap(), 0, font->name);
2318 HeapFree(GetProcessHeap(), 0, font->gm);
2319 HeapFree(GetProcessHeap(), 0, font);
2323 /*************************************************************
2326 * load the vdmx entry for the specified height
2329 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2330 ( ( (FT_ULong)_x4 << 24 ) | \
2331 ( (FT_ULong)_x3 << 16 ) | \
2332 ( (FT_ULong)_x2 << 8 ) | \
2335 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2350 static LONG load_VDMX(GdiFont *font, LONG height)
2354 BYTE devXRatio, devYRatio;
2355 USHORT numRecs, numRatios;
2356 DWORD result, offset = -1;
2360 /* For documentation on VDMX records, see
2361 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2364 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2366 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2369 /* FIXME: need the real device aspect ratio */
2373 numRecs = GET_BE_WORD(hdr[1]);
2374 numRatios = GET_BE_WORD(hdr[2]);
2376 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2377 for(i = 0; i < numRatios; i++) {
2380 offset = (3 * 2) + (i * sizeof(Ratios));
2381 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2384 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2386 if((ratio.xRatio == 0 &&
2387 ratio.yStartRatio == 0 &&
2388 ratio.yEndRatio == 0) ||
2389 (devXRatio == ratio.xRatio &&
2390 devYRatio >= ratio.yStartRatio &&
2391 devYRatio <= ratio.yEndRatio))
2393 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2394 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2395 offset = GET_BE_WORD(tmp);
2401 FIXME("No suitable ratio found\n");
2405 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2407 BYTE startsz, endsz;
2410 recs = GET_BE_WORD(group.recs);
2411 startsz = group.startsz;
2412 endsz = group.endsz;
2414 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2416 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2417 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2418 if(result == GDI_ERROR) {
2419 FIXME("Failed to retrieve vTable\n");
2424 for(i = 0; i < recs; i++) {
2425 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2426 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2427 ppem = GET_BE_WORD(vTable[i * 3]);
2429 if(yMax + -yMin == height) {
2432 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2435 if(yMax + -yMin > height) {
2438 goto end; /* failed */
2440 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2441 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2442 ppem = GET_BE_WORD(vTable[i * 3]);
2443 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2449 TRACE("ppem not found for height %d\n", height);
2453 if(ppem < startsz || ppem > endsz)
2456 for(i = 0; i < recs; i++) {
2458 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2460 if(yPelHeight > ppem)
2463 if(yPelHeight == ppem) {
2464 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2465 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2466 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2472 HeapFree(GetProcessHeap(), 0, vTable);
2478 static BOOL fontcmp(GdiFont *font, FONT_DESC *fd)
2480 if(font->font_desc.hash != fd->hash) return TRUE;
2481 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2482 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2483 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2484 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2487 static void calc_hash(FONT_DESC *pfd)
2489 DWORD hash = 0, *ptr, two_chars;
2493 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2495 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2497 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2499 pwc = (WCHAR *)&two_chars;
2501 *pwc = toupperW(*pwc);
2503 *pwc = toupperW(*pwc);
2507 hash ^= !pfd->can_use_bitmap;
2512 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2517 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2519 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2520 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2521 fd.can_use_bitmap = can_use_bitmap;
2524 /* try the in-use list */
2525 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2526 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2527 if(!fontcmp(ret, &fd)) {
2528 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2529 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2530 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2531 if(hflist->hfont == hfont)
2534 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2535 hflist->hfont = hfont;
2536 list_add_head(&ret->hfontlist, &hflist->entry);
2541 /* then the unused list */
2542 font_elem_ptr = list_head(&unused_gdi_font_list);
2543 while(font_elem_ptr) {
2544 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2545 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2546 if(!fontcmp(ret, &fd)) {
2547 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2548 assert(list_empty(&ret->hfontlist));
2549 TRACE("Found %p in unused list\n", ret);
2550 list_remove(&ret->entry);
2551 list_add_head(&gdi_font_list, &ret->entry);
2552 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2553 hflist->hfont = hfont;
2554 list_add_head(&ret->hfontlist, &hflist->entry);
2562 /*************************************************************
2563 * create_child_font_list
2565 static BOOL create_child_font_list(GdiFont *font)
2568 SYSTEM_LINKS *font_link;
2569 CHILD_FONT *font_link_entry, *new_child;
2571 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2573 if(!strcmpW(font_link->font_name, font->name))
2575 TRACE("found entry in system list\n");
2576 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2578 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2579 new_child->file_name = strdupA(font_link_entry->file_name);
2580 new_child->index = font_link_entry->index;
2581 new_child->font = NULL;
2582 list_add_tail(&font->child_fonts, &new_child->entry);
2583 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
2593 /*************************************************************
2594 * WineEngCreateFontInstance
2597 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
2600 Face *face, *best, *best_bitmap;
2601 Family *family, *last_resort_family;
2602 struct list *family_elem_ptr, *face_elem_ptr;
2603 INT height, width = 0;
2604 unsigned int score = 0, new_score;
2605 signed int diff = 0, newdiff;
2606 BOOL bd, it, can_use_bitmap;
2611 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2613 struct list *first_hfont = list_head(&ret->hfontlist);
2614 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2615 if(hflist->hfont == hfont)
2619 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2620 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2622 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2623 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2624 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2627 /* check the cache first */
2628 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2629 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2633 TRACE("not in cache\n");
2634 if(list_empty(&font_list)) /* No fonts installed */
2636 TRACE("No fonts installed\n");
2639 if(!have_installed_roman_font)
2641 TRACE("No roman font installed\n");
2647 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2648 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2649 ret->font_desc.can_use_bitmap = can_use_bitmap;
2650 calc_hash(&ret->font_desc);
2651 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2652 hflist->hfont = hfont;
2653 list_add_head(&ret->hfontlist, &hflist->entry);
2656 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2657 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2658 original value lfCharSet. Note this is a special case for
2659 Symbol and doesn't happen at least for "Wingdings*" */
2661 if(!strcmpiW(lf.lfFaceName, SymbolW))
2662 lf.lfCharSet = SYMBOL_CHARSET;
2664 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2665 switch(lf.lfCharSet) {
2666 case DEFAULT_CHARSET:
2667 csi.fs.fsCsb[0] = 0;
2670 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2671 csi.fs.fsCsb[0] = 0;
2677 if(lf.lfFaceName[0] != '\0') {
2679 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2682 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2683 debugstr_w(psub->to.name));
2684 strcpyW(lf.lfFaceName, psub->to.name);
2687 /* We want a match on name and charset or just name if
2688 charset was DEFAULT_CHARSET. If the latter then
2689 we fixup the returned charset later in get_nearest_charset
2690 where we'll either use the charset of the current ansi codepage
2691 or if that's unavailable the first charset that the font supports.
2693 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2694 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2695 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2696 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2697 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2698 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2699 if(face->scalable || can_use_bitmap)
2706 /* If requested charset was DEFAULT_CHARSET then try using charset
2707 corresponding to the current ansi codepage */
2708 if(!csi.fs.fsCsb[0]) {
2710 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
2711 FIXME("TCI failed on codepage %d\n", acp);
2712 csi.fs.fsCsb[0] = 0;
2714 lf.lfCharSet = csi.ciCharset;
2717 /* Face families are in the top 4 bits of lfPitchAndFamily,
2718 so mask with 0xF0 before testing */
2720 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2721 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2722 strcpyW(lf.lfFaceName, defFixed);
2723 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2724 strcpyW(lf.lfFaceName, defSerif);
2725 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2726 strcpyW(lf.lfFaceName, defSans);
2728 strcpyW(lf.lfFaceName, defSans);
2729 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2730 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2731 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2732 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2733 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2734 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2735 if(face->scalable || can_use_bitmap)
2741 last_resort_family = NULL;
2742 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2743 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2744 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2745 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2746 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2749 if(can_use_bitmap && !last_resort_family)
2750 last_resort_family = family;
2755 if(last_resort_family) {
2756 family = last_resort_family;
2757 csi.fs.fsCsb[0] = 0;
2761 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2762 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2763 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2764 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2765 if(face->scalable) {
2766 csi.fs.fsCsb[0] = 0;
2767 WARN("just using first face for now\n");
2770 if(can_use_bitmap && !last_resort_family)
2771 last_resort_family = family;
2774 if(!last_resort_family) {
2775 FIXME("can't find a single appropriate font - bailing\n");
2780 WARN("could only find a bitmap font - this will probably look awful!\n");
2781 family = last_resort_family;
2782 csi.fs.fsCsb[0] = 0;
2785 it = lf.lfItalic ? 1 : 0;
2786 bd = lf.lfWeight > 550 ? 1 : 0;
2788 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2789 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2791 face = best = best_bitmap = NULL;
2792 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2794 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2796 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
2797 if(!best || new_score <= score)
2799 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
2800 face->Italic, face->Bold, it, bd);
2803 if(best->scalable && score == 0) break;
2807 newdiff = height - (signed int)(best->size.height);
2809 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
2810 if(!best_bitmap || new_score < score ||
2811 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
2813 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
2816 if(score == 0 && diff == 0) break;
2823 face = best->scalable ? best : best_bitmap;
2824 ret->fake_italic = (it && !face->Italic);
2825 ret->fake_bold = (bd && !face->Bold);
2827 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2829 if(csi.fs.fsCsb[0]) {
2830 ret->charset = lf.lfCharSet;
2831 ret->codepage = csi.ciACP;
2834 ret->charset = get_nearest_charset(face, &ret->codepage);
2836 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2837 debugstr_w(face->StyleName), face->file, face->face_index);
2839 if(!face->scalable) {
2840 width = face->size.x_ppem >> 6;
2841 height = face->size.y_ppem >> 6;
2843 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2851 if (ret->charset == SYMBOL_CHARSET &&
2852 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2855 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2859 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2862 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2863 ret->name = strdupW(family->FamilyName);
2864 ret->underline = lf.lfUnderline ? 0xff : 0;
2865 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2866 create_child_font_list(ret);
2868 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2870 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
2871 list_add_head(&gdi_font_list, &ret->entry);
2875 static void dump_gdi_font_list(void)
2878 struct list *elem_ptr;
2880 TRACE("---------- gdiFont Cache ----------\n");
2881 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2882 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2883 TRACE("gdiFont=%p %s %d\n",
2884 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2887 TRACE("---------- Unused gdiFont Cache ----------\n");
2888 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2889 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2890 TRACE("gdiFont=%p %s %d\n",
2891 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2895 /*************************************************************
2896 * WineEngDestroyFontInstance
2898 * free the gdiFont associated with this handle
2901 BOOL WineEngDestroyFontInstance(HFONT handle)
2906 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2909 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
2911 struct list *first_hfont = list_head(&gdiFont->hfontlist);
2912 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2913 if(hflist->hfont == handle)
2915 TRACE("removing child font %p from child list\n", gdiFont);
2916 list_remove(&gdiFont->entry);
2921 TRACE("destroying hfont=%p\n", handle);
2923 dump_gdi_font_list();
2925 font_elem_ptr = list_head(&gdi_font_list);
2926 while(font_elem_ptr) {
2927 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2928 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
2930 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
2931 while(hfontlist_elem_ptr) {
2932 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2933 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
2934 if(hflist->hfont == handle) {
2935 list_remove(&hflist->entry);
2936 HeapFree(GetProcessHeap(), 0, hflist);
2940 if(list_empty(&gdiFont->hfontlist)) {
2941 TRACE("Moving to Unused list\n");
2942 list_remove(&gdiFont->entry);
2943 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
2948 font_elem_ptr = list_head(&unused_gdi_font_list);
2949 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
2950 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2951 while(font_elem_ptr) {
2952 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2953 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2954 TRACE("freeing %p\n", gdiFont);
2955 list_remove(&gdiFont->entry);
2961 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2962 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
2964 OUTLINETEXTMETRICW *potm = NULL;
2966 TEXTMETRICW tm, *ptm;
2967 GdiFont *font = alloc_font();
2970 if(face->scalable) {
2974 height = face->size.y_ppem >> 6;
2975 width = face->size.x_ppem >> 6;
2978 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
2984 font->name = strdupW(face->family->FamilyName);
2986 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
2988 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
2990 potm = HeapAlloc(GetProcessHeap(), 0, size);
2991 WineEngGetOutlineTextMetrics(font, size, potm);
2992 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
2994 WineEngGetTextMetrics(font, &tm);
2998 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
2999 pntm->ntmTm.tmAscent = ptm->tmAscent;
3000 pntm->ntmTm.tmDescent = ptm->tmDescent;
3001 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
3002 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
3003 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
3004 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
3005 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
3006 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
3007 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
3008 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
3009 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
3010 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
3011 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
3012 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
3013 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
3014 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
3015 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
3016 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
3017 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
3018 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
3019 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3020 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3021 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3023 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
3024 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
3025 *ptype |= RASTER_FONTTYPE;
3027 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
3028 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
3029 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
3031 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3032 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3033 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
3036 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
3038 lstrcpynW(pelf->elfLogFont.lfFaceName,
3039 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
3041 lstrcpynW(pelf->elfFullName,
3042 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
3044 lstrcpynW(pelf->elfStyle,
3045 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
3048 HeapFree(GetProcessHeap(), 0, potm);
3050 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3052 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3053 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
3054 pelf->elfStyle[0] = '\0';
3057 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3062 /*************************************************************
3066 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3070 struct list *family_elem_ptr, *face_elem_ptr;
3072 NEWTEXTMETRICEXW ntm;
3073 DWORD type, ret = 1;
3079 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3081 if(plf->lfFaceName[0]) {
3083 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3086 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3087 debugstr_w(psub->to.name));
3088 memcpy(&lf, plf, sizeof(lf));
3089 strcpyW(lf.lfFaceName, psub->to.name);
3093 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3094 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3095 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3096 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3097 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3098 GetEnumStructs(face, &elf, &ntm, &type);
3099 for(i = 0; i < 32; i++) {
3100 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3101 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3102 strcpyW(elf.elfScript, OEM_DOSW);
3103 i = 32; /* break out of loop */
3104 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3107 fs.fsCsb[0] = 1L << i;
3109 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3111 csi.ciCharset = DEFAULT_CHARSET;
3112 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3113 if(csi.ciCharset != DEFAULT_CHARSET) {
3114 elf.elfLogFont.lfCharSet =
3115 ntm.ntmTm.tmCharSet = csi.ciCharset;
3117 strcpyW(elf.elfScript, ElfScriptsW[i]);
3119 FIXME("Unknown elfscript for bit %d\n", i);
3122 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3123 debugstr_w(elf.elfLogFont.lfFaceName),
3124 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3125 csi.ciCharset, type, debugstr_w(elf.elfScript),
3126 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3127 ntm.ntmTm.ntmFlags);
3128 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3135 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3136 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3137 face_elem_ptr = list_head(&family->faces);
3138 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3139 GetEnumStructs(face, &elf, &ntm, &type);
3140 for(i = 0; i < 32; i++) {
3141 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3142 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3143 strcpyW(elf.elfScript, OEM_DOSW);
3144 i = 32; /* break out of loop */
3145 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3148 fs.fsCsb[0] = 1L << i;
3150 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3152 csi.ciCharset = DEFAULT_CHARSET;
3153 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3154 if(csi.ciCharset != DEFAULT_CHARSET) {
3155 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3158 strcpyW(elf.elfScript, ElfScriptsW[i]);
3160 FIXME("Unknown elfscript for bit %d\n", i);
3163 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3164 debugstr_w(elf.elfLogFont.lfFaceName),
3165 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3166 csi.ciCharset, type, debugstr_w(elf.elfScript),
3167 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3168 ntm.ntmTm.ntmFlags);
3169 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3178 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3180 pt->x.value = vec->x >> 6;
3181 pt->x.fract = (vec->x & 0x3f) << 10;
3182 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3183 pt->y.value = vec->y >> 6;
3184 pt->y.fract = (vec->y & 0x3f) << 10;
3185 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3189 /***************************************************
3190 * According to the MSDN documentation on WideCharToMultiByte,
3191 * certain codepages cannot set the default_used parameter.
3192 * This returns TRUE if the codepage can set that parameter, false else
3193 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3195 static BOOL codepage_sets_default_used(UINT codepage)
3208 static FT_UInt get_glyph_index(GdiFont *font, UINT glyph)
3210 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
3211 WCHAR wc = (WCHAR)glyph;
3213 BOOL *default_used_pointer;
3216 default_used_pointer = NULL;
3217 default_used = FALSE;
3218 if (codepage_sets_default_used(font->codepage))
3219 default_used_pointer = &default_used;
3220 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
3223 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
3224 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
3228 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
3229 glyph = glyph + 0xf000;
3230 return pFT_Get_Char_Index(font->ft_face, glyph);
3233 /*************************************************************
3234 * WineEngGetGlyphIndices
3236 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3238 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
3239 LPWORD pgi, DWORD flags)
3242 WCHAR default_char = 0;
3245 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
3247 for(i = 0; i < count; i++)
3249 pgi[i] = get_glyph_index(font, lpstr[i]);
3254 WineEngGetTextMetrics(font, &textm);
3255 default_char = textm.tmDefaultChar;
3257 pgi[i] = default_char;
3263 /*************************************************************
3264 * WineEngGetGlyphOutline
3266 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3267 * except that the first parameter is the HWINEENGFONT of the font in
3268 * question rather than an HDC.
3271 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
3272 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3275 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3276 FT_Face ft_face = font->ft_face;
3277 FT_UInt glyph_index;
3278 DWORD width, height, pitch, needed = 0;
3279 FT_Bitmap ft_bitmap;
3281 INT left, right, top = 0, bottom = 0;
3283 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3284 float widthRatio = 1.0;
3285 FT_Matrix transMat = identityMat;
3286 BOOL needsTransform = FALSE;
3289 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
3290 buflen, buf, lpmat);
3292 if(format & GGO_GLYPH_INDEX) {
3293 glyph_index = glyph;
3294 format &= ~GGO_GLYPH_INDEX;
3296 glyph_index = get_glyph_index(font, glyph);
3298 if(glyph_index >= font->gmsize) {
3299 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
3300 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
3301 font->gmsize * sizeof(*font->gm));
3303 if(format == GGO_METRICS && font->gm[glyph_index].init) {
3304 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
3305 return 1; /* FIXME */
3309 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
3310 load_flags |= FT_LOAD_NO_BITMAP;
3312 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
3315 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
3319 /* Scaling factor */
3320 if (font->aveWidth && font->potm) {
3321 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
3324 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3325 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3327 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3328 font->gm[glyph_index].lsb = left >> 6;
3329 font->gm[glyph_index].bbx = (right - left) >> 6;
3331 /* Scaling transform */
3332 if(font->aveWidth) {
3334 scaleMat.xx = FT_FixedFromFloat(widthRatio);
3337 scaleMat.yy = (1 << 16);
3339 pFT_Matrix_Multiply(&scaleMat, &transMat);
3340 needsTransform = TRUE;
3343 /* Slant transform */
3344 if (font->fake_italic) {
3347 slantMat.xx = (1 << 16);
3348 slantMat.xy = ((1 << 16) >> 2);
3350 slantMat.yy = (1 << 16);
3351 pFT_Matrix_Multiply(&slantMat, &transMat);
3352 needsTransform = TRUE;
3355 /* Rotation transform */
3356 if(font->orientation) {
3357 FT_Matrix rotationMat;
3359 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3360 pFT_Vector_Unit(&vecAngle, angle);
3361 rotationMat.xx = vecAngle.x;
3362 rotationMat.xy = -vecAngle.y;
3363 rotationMat.yx = -rotationMat.xy;
3364 rotationMat.yy = rotationMat.xx;
3366 pFT_Matrix_Multiply(&rotationMat, &transMat);
3367 needsTransform = TRUE;
3370 /* Extra transformation specified by caller */
3373 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3374 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3375 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3376 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3377 pFT_Matrix_Multiply(&extraMat, &transMat);
3378 needsTransform = TRUE;
3381 if(!needsTransform) {
3382 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3383 bottom = (ft_face->glyph->metrics.horiBearingY -
3384 ft_face->glyph->metrics.height) & -64;
3385 lpgm->gmCellIncX = font->gm[glyph_index].adv;
3386 lpgm->gmCellIncY = 0;
3390 for(xc = 0; xc < 2; xc++) {
3391 for(yc = 0; yc < 2; yc++) {
3392 vec.x = (ft_face->glyph->metrics.horiBearingX +
3393 xc * ft_face->glyph->metrics.width);
3394 vec.y = ft_face->glyph->metrics.horiBearingY -
3395 yc * ft_face->glyph->metrics.height;
3396 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3397 pFT_Vector_Transform(&vec, &transMat);
3398 if(xc == 0 && yc == 0) {
3399 left = right = vec.x;
3400 top = bottom = vec.y;
3402 if(vec.x < left) left = vec.x;
3403 else if(vec.x > right) right = vec.x;
3404 if(vec.y < bottom) bottom = vec.y;
3405 else if(vec.y > top) top = vec.y;
3410 right = (right + 63) & -64;
3411 bottom = bottom & -64;
3412 top = (top + 63) & -64;
3414 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3415 vec.x = ft_face->glyph->metrics.horiAdvance;
3417 pFT_Vector_Transform(&vec, &transMat);
3418 lpgm->gmCellIncX = (vec.x+63) >> 6;
3419 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3421 lpgm->gmBlackBoxX = (right - left) >> 6;
3422 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3423 lpgm->gmptGlyphOrigin.x = left >> 6;
3424 lpgm->gmptGlyphOrigin.y = top >> 6;
3426 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
3427 font->gm[glyph_index].init = TRUE;
3429 if(format == GGO_METRICS)
3430 return 1; /* FIXME */
3432 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
3433 TRACE("loaded a bitmap\n");
3439 width = lpgm->gmBlackBoxX;
3440 height = lpgm->gmBlackBoxY;
3441 pitch = ((width + 31) >> 5) << 2;
3442 needed = pitch * height;
3444 if(!buf || !buflen) break;
3446 switch(ft_face->glyph->format) {
3447 case ft_glyph_format_bitmap:
3449 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3450 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3451 INT h = ft_face->glyph->bitmap.rows;
3453 memcpy(dst, src, w);
3454 src += ft_face->glyph->bitmap.pitch;
3460 case ft_glyph_format_outline:
3461 ft_bitmap.width = width;
3462 ft_bitmap.rows = height;
3463 ft_bitmap.pitch = pitch;
3464 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3465 ft_bitmap.buffer = buf;
3467 if(needsTransform) {
3468 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3471 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3473 /* Note: FreeType will only set 'black' bits for us. */
3474 memset(buf, 0, needed);
3475 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3479 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3484 case GGO_GRAY2_BITMAP:
3485 case GGO_GRAY4_BITMAP:
3486 case GGO_GRAY8_BITMAP:
3487 case WINE_GGO_GRAY16_BITMAP:
3489 unsigned int mult, row, col;
3492 width = lpgm->gmBlackBoxX;
3493 height = lpgm->gmBlackBoxY;
3494 pitch = (width + 3) / 4 * 4;
3495 needed = pitch * height;
3497 if(!buf || !buflen) break;
3498 ft_bitmap.width = width;
3499 ft_bitmap.rows = height;
3500 ft_bitmap.pitch = pitch;
3501 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3502 ft_bitmap.buffer = buf;
3504 if(needsTransform) {
3505 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3508 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3510 memset(ft_bitmap.buffer, 0, buflen);
3512 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3514 if(format == GGO_GRAY2_BITMAP)
3516 else if(format == GGO_GRAY4_BITMAP)
3518 else if(format == GGO_GRAY8_BITMAP)
3520 else if(format == WINE_GGO_GRAY16_BITMAP)
3528 for(row = 0; row < height; row++) {
3530 for(col = 0; col < width; col++, ptr++) {
3531 *ptr = (((int)*ptr) * mult + 128) / 256;
3540 int contour, point = 0, first_pt;
3541 FT_Outline *outline = &ft_face->glyph->outline;
3542 TTPOLYGONHEADER *pph;
3544 DWORD pph_start, cpfx, type;
3546 if(buflen == 0) buf = NULL;
3548 if (needsTransform && buf) {
3549 pFT_Outline_Transform(outline, &transMat);
3552 for(contour = 0; contour < outline->n_contours; contour++) {
3554 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3557 pph->dwType = TT_POLYGON_TYPE;
3558 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3560 needed += sizeof(*pph);
3562 while(point <= outline->contours[contour]) {
3563 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3564 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3565 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3569 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3572 } while(point <= outline->contours[contour] &&
3573 (outline->tags[point] & FT_Curve_Tag_On) ==
3574 (outline->tags[point-1] & FT_Curve_Tag_On));
3575 /* At the end of a contour Windows adds the start point, but
3577 if(point > outline->contours[contour] &&
3578 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3580 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3582 } else if(point <= outline->contours[contour] &&
3583 outline->tags[point] & FT_Curve_Tag_On) {
3584 /* add closing pt for bezier */
3586 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3594 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3597 pph->cb = needed - pph_start;
3603 /* Convert the quadratic Beziers to cubic Beziers.
3604 The parametric eqn for a cubic Bezier is, from PLRM:
3605 r(t) = at^3 + bt^2 + ct + r0
3606 with the control points:
3611 A quadratic Beizer has the form:
3612 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3614 So equating powers of t leads to:
3615 r1 = 2/3 p1 + 1/3 p0
3616 r2 = 2/3 p1 + 1/3 p2
3617 and of course r0 = p0, r3 = p2
3620 int contour, point = 0, first_pt;
3621 FT_Outline *outline = &ft_face->glyph->outline;
3622 TTPOLYGONHEADER *pph;
3624 DWORD pph_start, cpfx, type;
3625 FT_Vector cubic_control[4];
3626 if(buflen == 0) buf = NULL;
3628 if (needsTransform && buf) {
3629 pFT_Outline_Transform(outline, &transMat);
3632 for(contour = 0; contour < outline->n_contours; contour++) {
3634 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3637 pph->dwType = TT_POLYGON_TYPE;
3638 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3640 needed += sizeof(*pph);
3642 while(point <= outline->contours[contour]) {
3643 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3644 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3645 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3648 if(type == TT_PRIM_LINE) {
3650 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3654 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3657 /* FIXME: Possible optimization in endpoint calculation
3658 if there are two consecutive curves */
3659 cubic_control[0] = outline->points[point-1];
3660 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3661 cubic_control[0].x += outline->points[point].x + 1;
3662 cubic_control[0].y += outline->points[point].y + 1;
3663 cubic_control[0].x >>= 1;
3664 cubic_control[0].y >>= 1;
3666 if(point+1 > outline->contours[contour])
3667 cubic_control[3] = outline->points[first_pt];
3669 cubic_control[3] = outline->points[point+1];
3670 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3671 cubic_control[3].x += outline->points[point].x + 1;
3672 cubic_control[3].y += outline->points[point].y + 1;
3673 cubic_control[3].x >>= 1;
3674 cubic_control[3].y >>= 1;
3677 /* r1 = 1/3 p0 + 2/3 p1
3678 r2 = 1/3 p2 + 2/3 p1 */
3679 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3680 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3681 cubic_control[2] = cubic_control[1];
3682 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3683 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3684 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3685 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3687 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3688 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3689 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3694 } while(point <= outline->contours[contour] &&
3695 (outline->tags[point] & FT_Curve_Tag_On) ==
3696 (outline->tags[point-1] & FT_Curve_Tag_On));
3697 /* At the end of a contour Windows adds the start point,
3698 but only for Beziers and we've already done that.
3700 if(point <= outline->contours[contour] &&
3701 outline->tags[point] & FT_Curve_Tag_On) {
3702 /* This is the closing pt of a bezier, but we've already
3703 added it, so just inc point and carry on */
3710 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3713 pph->cb = needed - pph_start;
3719 FIXME("Unsupported format %d\n", format);
3725 static BOOL get_bitmap_text_metrics(GdiFont *font)
3727 FT_Face ft_face = font->ft_face;
3728 #ifdef HAVE_FREETYPE_FTWINFNT_H
3729 FT_WinFNT_HeaderRec winfnt_header;
3731 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3732 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3733 font->potm->otmSize = size;
3735 #define TM font->potm->otmTextMetrics
3736 #ifdef HAVE_FREETYPE_FTWINFNT_H
3737 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3739 TM.tmHeight = winfnt_header.pixel_height;
3740 TM.tmAscent = winfnt_header.ascent;
3741 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3742 TM.tmInternalLeading = winfnt_header.internal_leading;
3743 TM.tmExternalLeading = winfnt_header.external_leading;
3744 TM.tmAveCharWidth = winfnt_header.avg_width;
3745 TM.tmMaxCharWidth = winfnt_header.max_width;
3746 TM.tmWeight = winfnt_header.weight;
3748 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3749 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3750 TM.tmFirstChar = winfnt_header.first_char;
3751 TM.tmLastChar = winfnt_header.last_char;
3752 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3753 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3754 TM.tmItalic = winfnt_header.italic;
3755 TM.tmUnderlined = font->underline;
3756 TM.tmStruckOut = font->strikeout;
3757 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3758 TM.tmCharSet = winfnt_header.charset;
3763 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3764 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3765 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3766 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3767 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3768 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3769 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3770 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3772 TM.tmDigitizedAspectX = 96; /* FIXME */
3773 TM.tmDigitizedAspectY = 96; /* FIXME */
3775 TM.tmLastChar = 255;
3776 TM.tmDefaultChar = 32;
3777 TM.tmBreakChar = 32;
3778 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3779 TM.tmUnderlined = font->underline;
3780 TM.tmStruckOut = font->strikeout;
3781 /* NB inverted meaning of TMPF_FIXED_PITCH */
3782 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3783 TM.tmCharSet = font->charset;
3790 /*************************************************************
3791 * WineEngGetTextMetrics
3794 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
3797 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3798 if(!get_bitmap_text_metrics(font))
3801 if(!font->potm) return FALSE;
3802 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3804 if (font->aveWidth) {
3805 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3811 /*************************************************************
3812 * WineEngGetOutlineTextMetrics
3815 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
3816 OUTLINETEXTMETRICW *potm)
3818 FT_Face ft_face = font->ft_face;
3819 UINT needed, lenfam, lensty, ret;
3821 TT_HoriHeader *pHori;
3822 TT_Postscript *pPost;
3823 FT_Fixed x_scale, y_scale;
3824 WCHAR *family_nameW, *style_nameW;
3825 static const WCHAR spaceW[] = {' ', '\0'};
3827 INT ascent, descent;
3829 TRACE("font=%p\n", font);
3831 if(!FT_IS_SCALABLE(ft_face))
3835 if(cbSize >= font->potm->otmSize)
3836 memcpy(potm, font->potm, font->potm->otmSize);
3837 return font->potm->otmSize;
3841 needed = sizeof(*potm);
3843 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3844 family_nameW = strdupW(font->name);
3846 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3848 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3849 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3850 style_nameW, lensty/sizeof(WCHAR));
3852 /* These names should be read from the TT name table */
3854 /* length of otmpFamilyName */
3857 /* length of otmpFaceName */
3858 if(!strcasecmp(ft_face->style_name, "regular")) {
3859 needed += lenfam; /* just the family name */
3861 needed += lenfam + lensty; /* family + " " + style */
3864 /* length of otmpStyleName */
3867 /* length of otmpFullName */
3868 needed += lenfam + lensty;
3871 x_scale = ft_face->size->metrics.x_scale;
3872 y_scale = ft_face->size->metrics.y_scale;
3874 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3876 FIXME("Can't find OS/2 table - not TT font?\n");
3881 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3883 FIXME("Can't find HHEA table - not TT font?\n");
3888 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3890 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",
3891 pOS2->usWinAscent, pOS2->usWinDescent,
3892 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3893 ft_face->ascender, ft_face->descender, ft_face->height,
3894 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3895 ft_face->bbox.yMax, ft_face->bbox.yMin);
3897 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3898 font->potm->otmSize = needed;
3900 #define TM font->potm->otmTextMetrics
3902 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3903 ascent = pHori->Ascender;
3904 descent = -pHori->Descender;
3906 ascent = pOS2->usWinAscent;
3907 descent = pOS2->usWinDescent;
3911 TM.tmAscent = font->yMax;
3912 TM.tmDescent = -font->yMin;
3913 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3915 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
3916 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
3917 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
3918 - ft_face->units_per_EM, y_scale) + 32) >> 6;
3921 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3924 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3926 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
3927 ((ascent + descent) -
3928 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
3930 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
3931 if (TM.tmAveCharWidth == 0) {
3932 TM.tmAveCharWidth = 1;
3934 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
3935 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
3937 TM.tmDigitizedAspectX = 300;
3938 TM.tmDigitizedAspectY = 300;
3939 TM.tmFirstChar = pOS2->usFirstCharIndex;
3940 TM.tmLastChar = pOS2->usLastCharIndex;
3941 TM.tmDefaultChar = pOS2->usDefaultChar;
3942 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
3943 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3944 TM.tmUnderlined = font->underline;
3945 TM.tmStruckOut = font->strikeout;
3947 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3948 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3949 (pOS2->version == 0xFFFFU ||
3950 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3951 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3953 TM.tmPitchAndFamily = 0;
3955 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
3956 case PAN_FAMILY_SCRIPT:
3957 TM.tmPitchAndFamily |= FF_SCRIPT;
3959 case PAN_FAMILY_DECORATIVE:
3960 case PAN_FAMILY_PICTORIAL:
3961 TM.tmPitchAndFamily |= FF_DECORATIVE;
3963 case PAN_FAMILY_TEXT_DISPLAY:
3964 if(TM.tmPitchAndFamily == 0) /* fixed */
3965 TM.tmPitchAndFamily = FF_MODERN;
3967 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
3968 case PAN_SERIF_NORMAL_SANS:
3969 case PAN_SERIF_OBTUSE_SANS:
3970 case PAN_SERIF_PERP_SANS:
3971 TM.tmPitchAndFamily |= FF_SWISS;
3974 TM.tmPitchAndFamily |= FF_ROMAN;
3979 TM.tmPitchAndFamily |= FF_DONTCARE;
3982 if(FT_IS_SCALABLE(ft_face))
3983 TM.tmPitchAndFamily |= TMPF_VECTOR;
3984 if(FT_IS_SFNT(ft_face))
3985 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3987 TM.tmCharSet = font->charset;
3990 font->potm->otmFiller = 0;
3991 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3992 font->potm->otmfsSelection = pOS2->fsSelection;
3993 font->potm->otmfsType = pOS2->fsType;
3994 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
3995 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
3996 font->potm->otmItalicAngle = 0; /* POST table */
3997 font->potm->otmEMSquare = ft_face->units_per_EM;
3998 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
3999 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4000 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4001 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
4002 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4003 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
4004 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
4005 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
4006 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4007 font->potm->otmMacAscent = 0; /* where do these come from ? */
4008 font->potm->otmMacDescent = 0;
4009 font->potm->otmMacLineGap = 0;
4010 font->potm->otmusMinimumPPEM = 0; /* TT Header */
4011 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
4012 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
4013 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
4014 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
4015 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
4016 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
4017 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
4018 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
4019 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
4020 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4022 font->potm->otmsUnderscoreSize = 0;
4023 font->potm->otmsUnderscorePosition = 0;
4025 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
4026 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
4029 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4030 cp = (char*)font->potm + sizeof(*font->potm);
4031 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4032 strcpyW((WCHAR*)cp, family_nameW);
4034 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4035 strcpyW((WCHAR*)cp, style_nameW);
4037 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4038 strcpyW((WCHAR*)cp, family_nameW);
4039 if(strcasecmp(ft_face->style_name, "regular")) {
4040 strcatW((WCHAR*)cp, spaceW);
4041 strcatW((WCHAR*)cp, style_nameW);
4042 cp += lenfam + lensty;
4045 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
4046 strcpyW((WCHAR*)cp, family_nameW);
4047 strcatW((WCHAR*)cp, spaceW);
4048 strcatW((WCHAR*)cp, style_nameW);
4051 if(potm && needed <= cbSize)
4052 memcpy(potm, font->potm, font->potm->otmSize);
4055 HeapFree(GetProcessHeap(), 0, style_nameW);
4056 HeapFree(GetProcessHeap(), 0, family_nameW);
4061 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
4063 HFONTLIST *hfontlist;
4064 child->font = alloc_font();
4065 child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem);
4066 if(!child->font->ft_face)
4068 free_font(child->font);
4073 child->font->orientation = font->orientation;
4074 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
4075 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
4076 list_add_head(&child->font->hfontlist, &hfontlist->entry);
4077 child->font->base_font = font;
4078 list_add_head(&child_font_list, &child->font->entry);
4079 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
4083 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
4086 CHILD_FONT *child_font;
4089 font = font->base_font;
4091 *linked_font = font;
4093 if((*glyph = get_glyph_index(font, c)))
4096 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
4098 if(!child_font->font)
4099 if(!load_child_font(font, child_font))
4102 if(!child_font->font->ft_face)
4104 g = get_glyph_index(child_font->font, c);
4108 *linked_font = child_font->font;
4115 /*************************************************************
4116 * WineEngGetCharWidth
4119 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4124 FT_UInt glyph_index;
4125 GdiFont *linked_font;
4127 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4129 for(c = firstChar; c <= lastChar; c++) {
4130 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4131 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4132 &gm, 0, NULL, NULL);
4133 buffer[c - firstChar] = linked_font->gm[glyph_index].adv;
4138 /*************************************************************
4139 * WineEngGetCharABCWidths
4142 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4147 FT_UInt glyph_index;
4148 GdiFont *linked_font;
4150 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4152 if(!FT_IS_SCALABLE(font->ft_face))
4155 for(c = firstChar; c <= lastChar; c++) {
4156 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4157 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4158 &gm, 0, NULL, NULL);
4159 buffer[c - firstChar].abcA = linked_font->gm[glyph_index].lsb;
4160 buffer[c - firstChar].abcB = linked_font->gm[glyph_index].bbx;
4161 buffer[c - firstChar].abcC = linked_font->gm[glyph_index].adv - linked_font->gm[glyph_index].lsb -
4162 linked_font->gm[glyph_index].bbx;
4167 /*************************************************************
4168 * WineEngGetCharABCWidthsI
4171 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4176 FT_UInt glyph_index;
4177 GdiFont *linked_font;
4179 if(!FT_IS_SCALABLE(font->ft_face))
4182 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
4184 for(c = firstChar; c < firstChar+count; c++) {
4185 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
4186 &gm, 0, NULL, NULL);
4187 buffer[c - firstChar].abcA = linked_font->gm[c].lsb;
4188 buffer[c - firstChar].abcB = linked_font->gm[c].bbx;
4189 buffer[c - firstChar].abcC = linked_font->gm[c].adv - linked_font->gm[c].lsb
4190 - linked_font->gm[c].bbx;
4193 for(c = 0; c < count; c++) {
4194 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
4195 &gm, 0, NULL, NULL);
4196 buffer[c].abcA = linked_font->gm[pgi[c]].lsb;
4197 buffer[c].abcB = linked_font->gm[pgi[c]].bbx;
4198 buffer[c].abcC = linked_font->gm[pgi[c]].adv
4199 - linked_font->gm[pgi[c]].lsb - linked_font->gm[pgi[c]].bbx;
4205 /*************************************************************
4206 * WineEngGetTextExtentExPoint
4209 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4210 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4216 FT_UInt glyph_index;
4217 GdiFont *linked_font;
4219 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
4223 WineEngGetTextMetrics(font, &tm);
4224 size->cy = tm.tmHeight;
4226 for(idx = 0; idx < count; idx++) {
4227 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
4228 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4229 &gm, 0, NULL, NULL);
4230 size->cx += linked_font->gm[glyph_index].adv;
4232 if (! pnfit || ext <= max_ext) {
4242 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4246 /*************************************************************
4247 * WineEngGetTextExtentPointI
4250 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4257 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
4260 WineEngGetTextMetrics(font, &tm);
4261 size->cy = tm.tmHeight;
4263 for(idx = 0; idx < count; idx++) {
4264 WineEngGetGlyphOutline(font, indices[idx],
4265 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
4267 size->cx += font->gm[indices[idx]].adv;
4269 TRACE("return %d,%d\n", size->cx, size->cy);
4273 /*************************************************************
4274 * WineEngGetFontData
4277 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4280 FT_Face ft_face = font->ft_face;
4284 TRACE("font=%p, table=%08x, offset=%08x, buf=%p, cbData=%x\n",
4285 font, table, offset, buf, cbData);
4287 if(!FT_IS_SFNT(ft_face))
4295 if(table) { /* MS tags differ in endidness from FT ones */
4296 table = table >> 24 | table << 24 |
4297 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
4300 /* If the FT_Load_Sfnt_Table function is there we'll use it */
4301 if(pFT_Load_Sfnt_Table) {
4302 /* make sure value of len is the value freetype says it needs */
4304 FT_ULong needed = 0;
4305 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4306 if( !err && needed < len) len = needed;
4308 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4310 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
4311 else { /* Do it the hard way */
4312 TT_Face tt_face = (TT_Face) ft_face;
4313 SFNT_Interface *sfnt;
4314 if (FT_Version.major==2 && FT_Version.minor==0)
4317 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
4321 /* A field was added in the middle of the structure in 2.1.x */
4322 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
4324 /* make sure value of len is the value freetype says it needs */
4326 FT_ULong needed = 0;
4327 err = sfnt->load_any(tt_face, table, offset, NULL, &needed);
4328 if( !err && needed < len) len = needed;
4330 err = sfnt->load_any(tt_face, table, offset, buf, &len);
4336 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
4337 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
4338 "Please upgrade your freetype library.\n");
4341 err = FT_Err_Unimplemented_Feature;
4345 TRACE("Can't find table %08x.\n", table);
4351 /*************************************************************
4352 * WineEngGetTextFace
4355 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4358 lstrcpynW(str, font->name, count);
4359 return strlenW(font->name);
4361 return strlenW(font->name) + 1;
4364 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4366 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4367 return font->charset;
4370 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4372 GdiFont *font = dc->gdiFont, *linked_font;
4373 struct list *first_hfont;
4376 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4377 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4378 if(font == linked_font)
4379 *new_hfont = dc->hFont;
4382 first_hfont = list_head(&linked_font->hfontlist);
4383 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4390 /*************************************************************
4393 BOOL WINAPI FontIsLinked(HDC hdc)
4395 DC *dc = DC_GetDCPtr(hdc);
4398 if(!dc) return FALSE;
4399 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
4401 GDI_ReleaseObj(hdc);
4402 TRACE("returning %d\n", ret);
4406 static BOOL is_hinting_enabled(void)
4408 /* Use the >= 2.2.0 function if available */
4409 if(pFT_Get_TrueType_Engine_Type)
4411 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4412 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4414 #ifdef FT_DRIVER_HAS_HINTER
4419 /* otherwise if we've been compiled with < 2.2.0 headers
4420 use the internal macro */
4421 mod = pFT_Get_Module(library, "truetype");
4422 if(mod && FT_DRIVER_HAS_HINTER(mod))
4430 /*************************************************************************
4431 * GetRasterizerCaps (GDI32.@)
4433 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4435 static int hinting = -1;
4439 hinting = is_hinting_enabled();
4440 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
4443 lprs->nSize = sizeof(RASTERIZER_STATUS);
4444 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4445 lprs->nLanguageID = 0;
4449 /*************************************************************************
4450 * Kerning support for TrueType fonts
4452 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4454 struct TT_kern_table
4460 struct TT_kern_subtable
4469 USHORT horizontal : 1;
4471 USHORT cross_stream: 1;
4472 USHORT override : 1;
4473 USHORT reserved1 : 4;
4479 struct TT_format0_kern_subtable
4483 USHORT entrySelector;
4494 static DWORD parse_format0_kern_subtable(GdiFont *font,
4495 const struct TT_format0_kern_subtable *tt_f0_ks,
4496 const USHORT *glyph_to_char,
4497 KERNINGPAIR *kern_pair, DWORD cPairs)
4500 const struct TT_kern_pair *tt_kern_pair;
4502 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
4504 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4506 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4507 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4508 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4510 if (!kern_pair || !cPairs)
4513 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4515 nPairs = min(nPairs, cPairs);
4517 for (i = 0; i < nPairs; i++)
4519 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4520 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4521 /* this algorithm appears to better match what Windows does */
4522 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4523 if (kern_pair->iKernAmount < 0)
4525 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
4526 kern_pair->iKernAmount -= font->ppem;
4528 else if (kern_pair->iKernAmount > 0)
4530 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
4531 kern_pair->iKernAmount += font->ppem;
4533 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
4535 TRACE("left %u right %u value %d\n",
4536 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
4540 TRACE("copied %u entries\n", nPairs);
4544 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4548 const struct TT_kern_table *tt_kern_table;
4549 const struct TT_kern_subtable *tt_kern_subtable;
4551 USHORT *glyph_to_char;
4553 if (font->total_kern_pairs != (DWORD)-1)
4555 if (cPairs && kern_pair)
4557 cPairs = min(cPairs, font->total_kern_pairs);
4558 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4561 return font->total_kern_pairs;
4564 font->total_kern_pairs = 0;
4566 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
4568 if (length == GDI_ERROR)
4570 TRACE("no kerning data in the font\n");
4574 buf = HeapAlloc(GetProcessHeap(), 0, length);
4577 WARN("Out of memory\n");
4581 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
4583 /* build a glyph index to char code map */
4584 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
4587 WARN("Out of memory allocating a glyph index to char code map\n");
4588 HeapFree(GetProcessHeap(), 0, buf);
4592 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4598 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
4600 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4601 font->ft_face->num_glyphs, glyph_code, char_code);
4605 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4607 /* FIXME: This doesn't match what Windows does: it does some fancy
4608 * things with duplicate glyph index to char code mappings, while
4609 * we just avoid overriding existing entries.
4611 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
4612 glyph_to_char[glyph_code] = (USHORT)char_code;
4614 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
4621 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
4622 for (n = 0; n <= 65535; n++)
4623 glyph_to_char[n] = (USHORT)n;
4626 tt_kern_table = buf;
4627 nTables = GET_BE_WORD(tt_kern_table->nTables);
4628 TRACE("version %u, nTables %u\n",
4629 GET_BE_WORD(tt_kern_table->version), nTables);
4631 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
4633 for (i = 0; i < nTables; i++)
4635 struct TT_kern_subtable tt_kern_subtable_copy;
4637 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
4638 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
4639 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
4641 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4642 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
4643 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
4645 /* According to the TrueType specification this is the only format
4646 * that will be properly interpreted by Windows and OS/2
4648 if (tt_kern_subtable_copy.coverage.bits.format == 0)
4650 DWORD new_chunk, old_total = font->total_kern_pairs;
4652 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4653 glyph_to_char, NULL, 0);
4654 font->total_kern_pairs += new_chunk;
4656 if (!font->kern_pairs)
4657 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
4658 font->total_kern_pairs * sizeof(*font->kern_pairs));
4660 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
4661 font->total_kern_pairs * sizeof(*font->kern_pairs));
4663 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4664 glyph_to_char, font->kern_pairs + old_total, new_chunk);
4667 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
4669 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
4672 HeapFree(GetProcessHeap(), 0, glyph_to_char);
4673 HeapFree(GetProcessHeap(), 0, buf);
4675 if (cPairs && kern_pair)
4677 cPairs = min(cPairs, font->total_kern_pairs);
4678 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4681 return font->total_kern_pairs;
4684 #else /* HAVE_FREETYPE */
4686 /*************************************************************************/
4688 BOOL WineEngInit(void)
4692 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
4696 BOOL WineEngDestroyFontInstance(HFONT hfont)
4701 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4706 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4707 LPWORD pgi, DWORD flags)
4712 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
4713 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4716 ERR("called but we don't have FreeType\n");
4720 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4722 ERR("called but we don't have FreeType\n");
4726 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4727 OUTLINETEXTMETRICW *potm)
4729 ERR("called but we don't have FreeType\n");
4733 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4736 ERR("called but we don't have FreeType\n");
4740 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4743 ERR("called but we don't have FreeType\n");
4747 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4750 ERR("called but we don't have FreeType\n");
4754 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4755 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
4757 ERR("called but we don't have FreeType\n");
4761 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4764 ERR("called but we don't have FreeType\n");
4768 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4771 ERR("called but we don't have FreeType\n");
4775 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4777 ERR("called but we don't have FreeType\n");
4781 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4787 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4793 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4796 return DEFAULT_CHARSET;
4799 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4804 BOOL WINAPI FontIsLinked(HDC hdc)
4809 /*************************************************************************
4810 * GetRasterizerCaps (GDI32.@)
4812 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4814 lprs->nSize = sizeof(RASTERIZER_STATUS);
4816 lprs->nLanguageID = 0;
4820 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4822 ERR("called but we don't have FreeType\n");
4826 #endif /* HAVE_FREETYPE */