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, const WCHAR *target_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, 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);
1015 localised_family = get_familyname(ft_face);
1016 if (lstrcmpW(localised_family,target_family)!=0)
1018 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1019 HeapFree(GetProcessHeap(), 0, localised_family);
1020 num_faces = ft_face->num_faces;
1023 HeapFree(GetProcessHeap(), 0, localised_family);
1027 family_name = ft_face->family_name;
1031 My_FT_Bitmap_Size *size = NULL;
1033 if(!FT_IS_SCALABLE(ft_face))
1034 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1036 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1037 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1038 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1040 localised_family = NULL;
1042 localised_family = get_familyname(ft_face);
1043 if(localised_family && !strcmpW(localised_family, english_family)) {
1044 HeapFree(GetProcessHeap(), 0, localised_family);
1045 localised_family = NULL;
1050 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1051 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1052 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1057 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1058 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1059 list_init(&family->faces);
1060 list_add_tail(&font_list, &family->entry);
1062 if(localised_family) {
1063 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1064 subst->from.name = strdupW(english_family);
1065 subst->from.charset = -1;
1066 subst->to.name = strdupW(localised_family);
1067 subst->to.charset = -1;
1068 add_font_subst(&font_subst_list, subst, 0);
1071 HeapFree(GetProcessHeap(), 0, localised_family);
1072 HeapFree(GetProcessHeap(), 0, english_family);
1074 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1075 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1076 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1078 internal_leading = 0;
1079 memset(&fs, 0, sizeof(fs));
1081 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1083 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1084 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1085 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1086 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1087 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1088 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1089 if(pOS2->version == 0) {
1092 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1095 fs.fsCsb[0] |= 1L << 31;
1098 #ifdef HAVE_FREETYPE_FTWINFNT_H
1099 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1101 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1102 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1103 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1104 memcpy(&fs, &csi.fs, sizeof(csi.fs));
1105 internal_leading = winfnt_header.internal_leading;
1109 face_elem_ptr = list_head(&family->faces);
1110 while(face_elem_ptr) {
1111 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1112 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1113 if(!strcmpW(face->StyleName, StyleW) &&
1114 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1115 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1116 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1117 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1120 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1121 HeapFree(GetProcessHeap(), 0, StyleW);
1122 pFT_Done_Face(ft_face);
1125 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1126 TRACE("Original font is newer so skipping this one\n");
1127 HeapFree(GetProcessHeap(), 0, StyleW);
1128 pFT_Done_Face(ft_face);
1131 TRACE("Replacing original with this one\n");
1132 list_remove(&face->entry);
1133 HeapFree(GetProcessHeap(), 0, face->file);
1134 HeapFree(GetProcessHeap(), 0, face->StyleName);
1135 HeapFree(GetProcessHeap(), 0, face);
1140 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1141 list_add_tail(&family->faces, &face->entry);
1142 face->StyleName = StyleW;
1143 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
1144 strcpy(face->file, file);
1145 face->face_index = face_index;
1146 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
1147 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
1148 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1149 face->family = family;
1150 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1151 memcpy(&face->fs, &fs, sizeof(face->fs));
1152 memset(&face->fs_links, 0, sizeof(face->fs_links));
1154 if(FT_IS_SCALABLE(ft_face)) {
1155 memset(&face->size, 0, sizeof(face->size));
1156 face->scalable = TRUE;
1158 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1159 size->height, size->width, size->size >> 6,
1160 size->x_ppem >> 6, size->y_ppem >> 6);
1161 face->size.height = size->height;
1162 face->size.width = size->width;
1163 face->size.size = size->size;
1164 face->size.x_ppem = size->x_ppem;
1165 face->size.y_ppem = size->y_ppem;
1166 face->size.internal_leading = internal_leading;
1167 face->scalable = FALSE;
1170 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1171 face->fs.fsCsb[0], face->fs.fsCsb[1],
1172 face->fs.fsUsb[0], face->fs.fsUsb[1],
1173 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1176 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1177 for(i = 0; i < ft_face->num_charmaps; i++) {
1178 switch(ft_face->charmaps[i]->encoding) {
1179 case FT_ENCODING_UNICODE:
1180 case FT_ENCODING_APPLE_ROMAN:
1181 face->fs.fsCsb[0] |= 1;
1183 case FT_ENCODING_MS_SYMBOL:
1184 face->fs.fsCsb[0] |= 1L << 31;
1192 if(face->fs.fsCsb[0] & ~(1L << 31))
1193 have_installed_roman_font = TRUE;
1194 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1196 num_faces = ft_face->num_faces;
1197 pFT_Done_Face(ft_face);
1198 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1199 debugstr_w(StyleW));
1200 } while(num_faces > ++face_index);
1204 static void DumpFontList(void)
1208 struct list *family_elem_ptr, *face_elem_ptr;
1210 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1211 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1212 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1213 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1214 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1215 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1217 TRACE(" %d", face->size.height);
1224 /***********************************************************
1225 * The replacement list is a way to map an entire font
1226 * family onto another family. For example adding
1228 * [HKCU\Software\Wine\Fonts\Replacements]
1229 * "Wingdings"="Winedings"
1231 * would enumerate the Winedings font both as Winedings and
1232 * Wingdings. However if a real Wingdings font is present the
1233 * replacement does not take place.
1236 static void LoadReplaceList(void)
1239 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1244 struct list *family_elem_ptr, *face_elem_ptr;
1247 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1248 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1250 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1251 &valuelen, &datalen, NULL, NULL);
1253 valuelen++; /* returned value doesn't include room for '\0' */
1254 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1255 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1259 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1260 &dlen) == ERROR_SUCCESS) {
1261 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1262 /* "NewName"="Oldname" */
1263 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1265 /* Find the old family and hence all of the font files
1267 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1268 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1269 if(!strcmpiW(family->FamilyName, data)) {
1270 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1271 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1272 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1273 debugstr_w(face->StyleName), familyA);
1274 /* Now add a new entry with the new family name */
1275 AddFontFileToList(face->file, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1280 /* reset dlen and vlen */
1284 HeapFree(GetProcessHeap(), 0, data);
1285 HeapFree(GetProcessHeap(), 0, value);
1290 /*************************************************************
1293 static BOOL init_system_links(void)
1295 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1296 'W','i','n','d','o','w','s',' ','N','T','\\',
1297 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1298 'S','y','s','t','e','m','L','i','n','k',0};
1301 DWORD type, max_val, max_data, val_len, data_len, index;
1302 WCHAR *value, *data;
1303 WCHAR *entry, *next;
1304 SYSTEM_LINKS *font_link, *system_font_link;
1305 CHILD_FONT *child_font;
1306 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1307 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1308 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1314 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1316 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1317 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1318 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1319 val_len = max_val + 1;
1320 data_len = max_data;
1322 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1324 TRACE("%s:\n", debugstr_w(value));
1326 memset(&fs, 0, sizeof(fs));
1327 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1328 psub = get_font_subst(&font_subst_list, value, -1);
1329 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1330 list_init(&font_link->links);
1331 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1334 CHILD_FONT *child_font;
1336 TRACE("\t%s\n", debugstr_w(entry));
1338 next = entry + strlenW(entry) + 1;
1340 face_name = strchrW(entry, ',');
1344 while(isspaceW(*face_name))
1347 psub = get_font_subst(&font_subst_list, face_name, -1);
1349 face_name = psub->to.name;
1351 face = find_face_from_filename(entry, face_name);
1354 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1358 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1359 child_font->file_name = strdupA(face->file);
1360 child_font->index = face->face_index;
1361 child_font->font = NULL;
1362 fs.fsCsb[0] |= face->fs.fsCsb[0];
1363 fs.fsCsb[1] |= face->fs.fsCsb[1];
1364 TRACE("Adding file %s index %d\n", child_font->file_name, child_font->index);
1365 list_add_tail(&font_link->links, &child_font->entry);
1367 family = find_family_from_name(font_link->font_name);
1370 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1372 memcpy(&face->fs_links, &fs, sizeof(fs));
1375 list_add_tail(&system_links, &font_link->entry);
1376 val_len = max_val + 1;
1377 data_len = max_data;
1380 HeapFree(GetProcessHeap(), 0, value);
1381 HeapFree(GetProcessHeap(), 0, data);
1385 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1388 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1389 system_font_link->font_name = strdupW(System);
1390 list_init(&system_font_link->links);
1392 face = find_face_from_filename(tahoma_ttf, Tahoma);
1395 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1396 child_font->file_name = strdupA(face->file);
1397 child_font->index = face->face_index;
1398 child_font->font = NULL;
1399 TRACE("Found Tahoma in %s index %d\n", child_font->file_name, child_font->index);
1400 list_add_tail(&system_font_link->links, &child_font->entry);
1402 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1404 if(!strcmpiW(font_link->font_name, Tahoma))
1406 CHILD_FONT *font_link_entry;
1407 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1409 CHILD_FONT *new_child;
1410 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1411 new_child->file_name = strdupA(font_link_entry->file_name);
1412 new_child->index = font_link_entry->index;
1413 new_child->font = NULL;
1414 list_add_tail(&system_font_link->links, &new_child->entry);
1419 list_add_tail(&system_links, &system_font_link->entry);
1423 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1426 struct dirent *dent;
1427 char path[MAX_PATH];
1429 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1431 dir = opendir(dirname);
1433 WARN("Can't open directory %s\n", debugstr_a(dirname));
1436 while((dent = readdir(dir)) != NULL) {
1437 struct stat statbuf;
1439 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1442 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1444 sprintf(path, "%s/%s", dirname, dent->d_name);
1446 if(stat(path, &statbuf) == -1)
1448 WARN("Can't stat %s\n", debugstr_a(path));
1451 if(S_ISDIR(statbuf.st_mode))
1452 ReadFontDir(path, external_fonts);
1454 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1460 static void load_fontconfig_fonts(void)
1462 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1463 void *fc_handle = NULL;
1472 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1474 TRACE("Wine cannot find the fontconfig library (%s).\n",
1475 SONAME_LIBFONTCONFIG);
1478 #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;}
1479 LOAD_FUNCPTR(FcConfigGetCurrent);
1480 LOAD_FUNCPTR(FcFontList);
1481 LOAD_FUNCPTR(FcFontSetDestroy);
1482 LOAD_FUNCPTR(FcInit);
1483 LOAD_FUNCPTR(FcObjectSetAdd);
1484 LOAD_FUNCPTR(FcObjectSetCreate);
1485 LOAD_FUNCPTR(FcObjectSetDestroy);
1486 LOAD_FUNCPTR(FcPatternCreate);
1487 LOAD_FUNCPTR(FcPatternDestroy);
1488 LOAD_FUNCPTR(FcPatternGetBool);
1489 LOAD_FUNCPTR(FcPatternGetString);
1492 if(!pFcInit()) return;
1494 config = pFcConfigGetCurrent();
1495 pat = pFcPatternCreate();
1496 os = pFcObjectSetCreate();
1497 pFcObjectSetAdd(os, FC_FILE);
1498 pFcObjectSetAdd(os, FC_SCALABLE);
1499 fontset = pFcFontList(config, pat, os);
1500 if(!fontset) return;
1501 for(i = 0; i < fontset->nfont; i++) {
1504 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1506 TRACE("fontconfig: %s\n", file);
1508 /* We're just interested in OT/TT fonts for now, so this hack just
1509 picks up the scalable fonts without extensions .pf[ab] to save time
1510 loading every other font */
1512 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1514 TRACE("not scalable\n");
1518 len = strlen( file );
1519 if(len < 4) continue;
1520 ext = &file[ len - 3 ];
1521 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1522 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1524 pFcFontSetDestroy(fontset);
1525 pFcObjectSetDestroy(os);
1526 pFcPatternDestroy(pat);
1532 static BOOL load_font_from_data_dir(LPCWSTR file)
1535 const char *data_dir = wine_get_data_dir();
1537 if (!data_dir) data_dir = wine_get_build_dir();
1544 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1546 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1548 strcpy(unix_name, data_dir);
1549 strcat(unix_name, "/fonts/");
1551 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1553 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1554 HeapFree(GetProcessHeap(), 0, unix_name);
1559 static void load_system_fonts(void)
1562 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1563 const WCHAR * const *value;
1565 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1568 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1569 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1570 strcatW(windowsdir, fontsW);
1571 for(value = SystemFontValues; *value; value++) {
1572 dlen = sizeof(data);
1573 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1577 sprintfW(pathW, fmtW, windowsdir, data);
1578 if((unixname = wine_get_unix_file_name(pathW))) {
1579 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1580 HeapFree(GetProcessHeap(), 0, unixname);
1583 load_font_from_data_dir(data);
1590 /*************************************************************
1592 * This adds registry entries for any externally loaded fonts
1593 * (fonts from fontconfig or FontDirs). It also deletes entries
1594 * of no longer existing fonts.
1597 static void update_reg_entries(void)
1599 HKEY winkey = 0, externalkey = 0;
1602 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1605 struct list *family_elem_ptr, *face_elem_ptr;
1607 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1608 static const WCHAR spaceW[] = {' ', '\0'};
1611 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1612 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1613 ERR("Can't create Windows font reg key\n");
1616 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1617 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1618 ERR("Can't create external font reg key\n");
1622 /* Delete all external fonts added last time */
1624 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1625 &valuelen, &datalen, NULL, NULL);
1626 valuelen++; /* returned value doesn't include room for '\0' */
1627 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1628 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1630 dlen = datalen * sizeof(WCHAR);
1633 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1634 &dlen) == ERROR_SUCCESS) {
1636 RegDeleteValueW(winkey, valueW);
1637 /* reset dlen and vlen */
1641 HeapFree(GetProcessHeap(), 0, data);
1642 HeapFree(GetProcessHeap(), 0, valueW);
1644 /* Delete the old external fonts key */
1645 RegCloseKey(externalkey);
1647 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1649 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1650 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1651 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1652 ERR("Can't create external font reg key\n");
1656 /* enumerate the fonts and add external ones to the two keys */
1658 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1659 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1660 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1661 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1662 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1663 if(!face->external) continue;
1665 if(strcmpiW(face->StyleName, RegularW))
1666 len = len_fam + strlenW(face->StyleName) + 1;
1667 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1668 strcpyW(valueW, family->FamilyName);
1669 if(len != len_fam) {
1670 strcatW(valueW, spaceW);
1671 strcatW(valueW, face->StyleName);
1673 strcatW(valueW, TrueType);
1674 if((path = strrchr(face->file, '/')) == NULL)
1678 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1680 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1681 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1682 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1683 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1685 HeapFree(GetProcessHeap(), 0, file);
1686 HeapFree(GetProcessHeap(), 0, valueW);
1691 RegCloseKey(externalkey);
1693 RegCloseKey(winkey);
1698 /*************************************************************
1699 * WineEngAddFontResourceEx
1702 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1704 if (ft_handle) /* do it only if we have freetype up and running */
1709 FIXME("Ignoring flags %x\n", flags);
1711 if((unixname = wine_get_unix_file_name(file)))
1713 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1714 HeapFree(GetProcessHeap(), 0, unixname);
1720 /*************************************************************
1721 * WineEngRemoveFontResourceEx
1724 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1730 static const struct nls_update_font_list
1732 UINT ansi_cp, oem_cp;
1733 const char *oem, *fixed, *system;
1734 const char *courier, *serif, *small, *sserif;
1735 } nls_update_font_list[] =
1737 /* Latin 1 (United States) */
1738 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1739 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1741 /* Latin 1 (Multilingual) */
1742 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1743 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1745 /* Eastern Europe */
1746 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1747 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1750 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1751 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1754 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1755 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1758 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1759 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1762 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1763 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1766 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1767 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1770 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1771 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1774 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1775 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1778 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1779 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1782 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1783 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1785 /* Chinese Simplified */
1786 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1787 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1790 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1791 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1793 /* Chinese Traditional */
1794 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1795 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1799 inline static HKEY create_fonts_NT_registry_key(void)
1803 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1804 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1808 inline static HKEY create_fonts_9x_registry_key(void)
1812 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1813 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1817 inline static HKEY create_config_fonts_registry_key(void)
1821 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1822 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1826 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1828 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1829 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1830 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1831 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1834 static void update_font_info(void)
1836 char buf[40], cpbuf[40];
1839 UINT i, ansi_cp = 0, oem_cp = 0;
1841 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
1844 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1845 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1846 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1847 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1848 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
1851 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1853 if (!strcmp( buf, cpbuf )) /* already set correctly */
1858 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
1860 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
1862 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
1865 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1867 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1868 nls_update_font_list[i].oem_cp == oem_cp)
1872 hkey = create_config_fonts_registry_key();
1873 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1874 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1875 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1878 hkey = create_fonts_NT_registry_key();
1879 add_font_list(hkey, &nls_update_font_list[i]);
1882 hkey = create_fonts_9x_registry_key();
1883 add_font_list(hkey, &nls_update_font_list[i]);
1889 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
1892 /*************************************************************
1895 * Initialize FreeType library and create a list of available faces
1897 BOOL WineEngInit(void)
1899 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1900 static const WCHAR pathW[] = {'P','a','t','h',0};
1902 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1904 WCHAR windowsdir[MAX_PATH];
1907 const char *data_dir;
1911 /* update locale dependent font info in registry */
1914 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1917 "Wine cannot find the FreeType font library. To enable Wine to\n"
1918 "use TrueType fonts please install a version of FreeType greater than\n"
1919 "or equal to 2.0.5.\n"
1920 "http://www.freetype.org\n");
1924 #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;}
1926 LOAD_FUNCPTR(FT_Vector_Unit)
1927 LOAD_FUNCPTR(FT_Done_Face)
1928 LOAD_FUNCPTR(FT_Get_Char_Index)
1929 LOAD_FUNCPTR(FT_Get_Module)
1930 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1931 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1932 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1933 LOAD_FUNCPTR(FT_Init_FreeType)
1934 LOAD_FUNCPTR(FT_Load_Glyph)
1935 LOAD_FUNCPTR(FT_Matrix_Multiply)
1936 LOAD_FUNCPTR(FT_MulFix)
1937 LOAD_FUNCPTR(FT_New_Face)
1938 LOAD_FUNCPTR(FT_New_Memory_Face)
1939 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1940 LOAD_FUNCPTR(FT_Outline_Transform)
1941 LOAD_FUNCPTR(FT_Outline_Translate)
1942 LOAD_FUNCPTR(FT_Select_Charmap)
1943 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1944 LOAD_FUNCPTR(FT_Vector_Transform)
1947 /* Don't warn if this one is missing */
1948 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1949 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1950 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1951 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
1952 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
1953 #ifdef HAVE_FREETYPE_FTWINFNT_H
1954 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1956 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1957 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1958 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1959 <= 2.0.3 has FT_Sqrt64 */
1963 if(pFT_Init_FreeType(&library) != 0) {
1964 ERR("Can't init FreeType library\n");
1965 wine_dlclose(ft_handle, NULL, 0);
1969 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1970 if (pFT_Library_Version)
1972 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1974 if (FT_Version.major<=0)
1980 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1981 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1982 ((FT_Version.minor << 8) & 0x00ff00) |
1983 ((FT_Version.patch ) & 0x0000ff);
1985 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1986 ERR("Failed to create font mutex\n");
1989 WaitForSingleObject(font_mutex, INFINITE);
1991 /* load the system bitmap fonts */
1992 load_system_fonts();
1994 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1995 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1996 strcatW(windowsdir, fontsW);
1997 if((unixname = wine_get_unix_file_name(windowsdir)))
1999 ReadFontDir(unixname, FALSE);
2000 HeapFree(GetProcessHeap(), 0, unixname);
2003 /* load the system truetype fonts */
2004 data_dir = wine_get_data_dir();
2005 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2006 strcpy(unixname, data_dir);
2007 strcat(unixname, "/fonts/");
2008 ReadFontDir(unixname, FALSE);
2009 HeapFree(GetProcessHeap(), 0, unixname);
2012 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2013 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2014 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2016 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2017 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2018 &hkey) == ERROR_SUCCESS) {
2020 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2021 &valuelen, &datalen, NULL, NULL);
2023 valuelen++; /* returned value doesn't include room for '\0' */
2024 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2025 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2028 dlen = datalen * sizeof(WCHAR);
2030 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2031 &dlen) == ERROR_SUCCESS) {
2032 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2034 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2036 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2037 HeapFree(GetProcessHeap(), 0, unixname);
2040 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2042 WCHAR pathW[MAX_PATH];
2043 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2046 sprintfW(pathW, fmtW, windowsdir, data);
2047 if((unixname = wine_get_unix_file_name(pathW)))
2049 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2050 HeapFree(GetProcessHeap(), 0, unixname);
2053 load_font_from_data_dir(data);
2055 /* reset dlen and vlen */
2060 HeapFree(GetProcessHeap(), 0, data);
2061 HeapFree(GetProcessHeap(), 0, valueW);
2065 load_fontconfig_fonts();
2067 /* then look in any directories that we've specified in the config file */
2068 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2069 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2075 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2077 len += sizeof(WCHAR);
2078 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2079 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2081 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2082 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2083 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2084 TRACE( "got font path %s\n", debugstr_a(valueA) );
2088 LPSTR next = strchr( ptr, ':' );
2089 if (next) *next++ = 0;
2090 ReadFontDir( ptr, TRUE );
2093 HeapFree( GetProcessHeap(), 0, valueA );
2095 HeapFree( GetProcessHeap(), 0, valueW );
2104 update_reg_entries();
2106 init_system_links();
2108 ReleaseMutex(font_mutex);
2112 "Wine cannot find certain functions that it needs inside the FreeType\n"
2113 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2114 "FreeType to at least version 2.0.5.\n"
2115 "http://www.freetype.org\n");
2116 wine_dlclose(ft_handle, NULL, 0);
2122 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2125 TT_HoriHeader *pHori;
2129 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2130 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2132 if(height == 0) height = 16;
2134 /* Calc. height of EM square:
2136 * For +ve lfHeight we have
2137 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2138 * Re-arranging gives:
2139 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2141 * For -ve lfHeight we have
2143 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2144 * with il = winAscent + winDescent - units_per_em]
2149 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2150 ppem = ft_face->units_per_EM * height /
2151 (pHori->Ascender - pHori->Descender);
2153 ppem = ft_face->units_per_EM * height /
2154 (pOS2->usWinAscent + pOS2->usWinDescent);
2162 static struct font_mapping *map_font( const char *name )
2164 #ifndef __APPLE__ /* Mac OS fonts use resource forks, we can't simply mmap them */
2165 struct font_mapping *mapping;
2169 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2170 if (fstat( fd, &st ) == -1) goto error;
2172 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2174 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2176 mapping->refcount++;
2181 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2184 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2187 if (mapping->data == MAP_FAILED)
2189 HeapFree( GetProcessHeap(), 0, mapping );
2192 mapping->refcount = 1;
2193 mapping->dev = st.st_dev;
2194 mapping->ino = st.st_ino;
2195 mapping->size = st.st_size;
2196 list_add_tail( &mappings_list, &mapping->entry );
2205 static void unmap_font( struct font_mapping *mapping )
2207 if (!--mapping->refcount)
2209 list_remove( &mapping->entry );
2210 munmap( mapping->data, mapping->size );
2211 HeapFree( GetProcessHeap(), 0, mapping );
2215 static LONG load_VDMX(GdiFont*, LONG);
2217 static FT_Face OpenFontFile(GdiFont *font, char *file, FT_Long face_index, LONG width, LONG height)
2222 TRACE("%s, %ld, %d x %d\n", debugstr_a(file), face_index, width, height);
2224 if ((font->mapping = map_font( file )))
2225 err = pFT_New_Memory_Face(library, font->mapping->data, font->mapping->size, face_index, &ft_face);
2227 err = pFT_New_Face(library, file, face_index, &ft_face);
2230 ERR("FT_New_Face rets %d\n", err);
2234 /* set it here, as load_VDMX needs it */
2235 font->ft_face = ft_face;
2237 if(FT_IS_SCALABLE(ft_face)) {
2238 /* load the VDMX table if we have one */
2239 font->ppem = load_VDMX(font, height);
2241 font->ppem = calc_ppem_for_height(ft_face, height);
2243 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2244 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2246 font->ppem = height;
2247 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2248 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2254 static int get_nearest_charset(Face *face, int *cp)
2256 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2257 a single face with the requested charset. The idea is to check if
2258 the selected font supports the current ANSI codepage, if it does
2259 return the corresponding charset, else return the first charset */
2262 int acp = GetACP(), i;
2266 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2267 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2268 return csi.ciCharset;
2270 for(i = 0; i < 32; i++) {
2272 if(face->fs.fsCsb[0] & fs0) {
2273 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2275 return csi.ciCharset;
2278 FIXME("TCI failing on %x\n", fs0);
2282 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2283 face->fs.fsCsb[0], face->file);
2285 return DEFAULT_CHARSET;
2288 static GdiFont *alloc_font(void)
2290 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2291 ret->gmsize = INIT_GM_SIZE;
2292 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2293 ret->gmsize * sizeof(*ret->gm));
2295 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2296 ret->total_kern_pairs = (DWORD)-1;
2297 ret->kern_pairs = NULL;
2298 list_init(&ret->hfontlist);
2299 list_init(&ret->child_fonts);
2303 static void free_font(GdiFont *font)
2305 struct list *cursor, *cursor2;
2307 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2309 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2310 struct list *first_hfont;
2311 HFONTLIST *hfontlist;
2312 list_remove(cursor);
2315 first_hfont = list_head(&child->font->hfontlist);
2316 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2317 DeleteObject(hfontlist->hfont);
2318 HeapFree(GetProcessHeap(), 0, hfontlist);
2319 free_font(child->font);
2321 HeapFree(GetProcessHeap(), 0, child->file_name);
2322 HeapFree(GetProcessHeap(), 0, child);
2325 if (font->ft_face) pFT_Done_Face(font->ft_face);
2326 if (font->mapping) unmap_font( font->mapping );
2327 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2328 HeapFree(GetProcessHeap(), 0, font->potm);
2329 HeapFree(GetProcessHeap(), 0, font->name);
2330 HeapFree(GetProcessHeap(), 0, font->gm);
2331 HeapFree(GetProcessHeap(), 0, font);
2335 /*************************************************************
2338 * load the vdmx entry for the specified height
2341 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2342 ( ( (FT_ULong)_x4 << 24 ) | \
2343 ( (FT_ULong)_x3 << 16 ) | \
2344 ( (FT_ULong)_x2 << 8 ) | \
2347 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2362 static LONG load_VDMX(GdiFont *font, LONG height)
2366 BYTE devXRatio, devYRatio;
2367 USHORT numRecs, numRatios;
2368 DWORD result, offset = -1;
2372 /* For documentation on VDMX records, see
2373 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2376 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2378 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2381 /* FIXME: need the real device aspect ratio */
2385 numRecs = GET_BE_WORD(hdr[1]);
2386 numRatios = GET_BE_WORD(hdr[2]);
2388 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2389 for(i = 0; i < numRatios; i++) {
2392 offset = (3 * 2) + (i * sizeof(Ratios));
2393 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2396 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2398 if((ratio.xRatio == 0 &&
2399 ratio.yStartRatio == 0 &&
2400 ratio.yEndRatio == 0) ||
2401 (devXRatio == ratio.xRatio &&
2402 devYRatio >= ratio.yStartRatio &&
2403 devYRatio <= ratio.yEndRatio))
2405 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2406 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2407 offset = GET_BE_WORD(tmp);
2413 FIXME("No suitable ratio found\n");
2417 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2419 BYTE startsz, endsz;
2422 recs = GET_BE_WORD(group.recs);
2423 startsz = group.startsz;
2424 endsz = group.endsz;
2426 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2428 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2429 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2430 if(result == GDI_ERROR) {
2431 FIXME("Failed to retrieve vTable\n");
2436 for(i = 0; i < recs; i++) {
2437 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2438 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2439 ppem = GET_BE_WORD(vTable[i * 3]);
2441 if(yMax + -yMin == height) {
2444 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2447 if(yMax + -yMin > height) {
2450 goto end; /* failed */
2452 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2453 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2454 ppem = GET_BE_WORD(vTable[i * 3]);
2455 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2461 TRACE("ppem not found for height %d\n", height);
2465 if(ppem < startsz || ppem > endsz)
2468 for(i = 0; i < recs; i++) {
2470 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2472 if(yPelHeight > ppem)
2475 if(yPelHeight == ppem) {
2476 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2477 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2478 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2484 HeapFree(GetProcessHeap(), 0, vTable);
2490 static BOOL fontcmp(GdiFont *font, FONT_DESC *fd)
2492 if(font->font_desc.hash != fd->hash) return TRUE;
2493 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2494 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2495 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2496 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2499 static void calc_hash(FONT_DESC *pfd)
2501 DWORD hash = 0, *ptr, two_chars;
2505 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2507 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2509 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2511 pwc = (WCHAR *)&two_chars;
2513 *pwc = toupperW(*pwc);
2515 *pwc = toupperW(*pwc);
2519 hash ^= !pfd->can_use_bitmap;
2524 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2529 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2531 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2532 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2533 fd.can_use_bitmap = can_use_bitmap;
2536 /* try the in-use list */
2537 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2538 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2539 if(!fontcmp(ret, &fd)) {
2540 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2541 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2542 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2543 if(hflist->hfont == hfont)
2546 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2547 hflist->hfont = hfont;
2548 list_add_head(&ret->hfontlist, &hflist->entry);
2553 /* then the unused list */
2554 font_elem_ptr = list_head(&unused_gdi_font_list);
2555 while(font_elem_ptr) {
2556 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2557 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2558 if(!fontcmp(ret, &fd)) {
2559 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2560 assert(list_empty(&ret->hfontlist));
2561 TRACE("Found %p in unused list\n", ret);
2562 list_remove(&ret->entry);
2563 list_add_head(&gdi_font_list, &ret->entry);
2564 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2565 hflist->hfont = hfont;
2566 list_add_head(&ret->hfontlist, &hflist->entry);
2574 /*************************************************************
2575 * create_child_font_list
2577 static BOOL create_child_font_list(GdiFont *font)
2580 SYSTEM_LINKS *font_link;
2581 CHILD_FONT *font_link_entry, *new_child;
2583 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2585 if(!strcmpW(font_link->font_name, font->name))
2587 TRACE("found entry in system list\n");
2588 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2590 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2591 new_child->file_name = strdupA(font_link_entry->file_name);
2592 new_child->index = font_link_entry->index;
2593 new_child->font = NULL;
2594 list_add_tail(&font->child_fonts, &new_child->entry);
2595 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
2605 /*************************************************************
2606 * WineEngCreateFontInstance
2609 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
2612 Face *face, *best, *best_bitmap;
2613 Family *family, *last_resort_family;
2614 struct list *family_elem_ptr, *face_elem_ptr;
2615 INT height, width = 0;
2616 unsigned int score = 0, new_score;
2617 signed int diff = 0, newdiff;
2618 BOOL bd, it, can_use_bitmap;
2623 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2625 struct list *first_hfont = list_head(&ret->hfontlist);
2626 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2627 if(hflist->hfont == hfont)
2631 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2632 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2634 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2635 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2636 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2639 /* check the cache first */
2640 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2641 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2645 TRACE("not in cache\n");
2646 if(list_empty(&font_list)) /* No fonts installed */
2648 TRACE("No fonts installed\n");
2651 if(!have_installed_roman_font)
2653 TRACE("No roman font installed\n");
2659 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2660 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2661 ret->font_desc.can_use_bitmap = can_use_bitmap;
2662 calc_hash(&ret->font_desc);
2663 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2664 hflist->hfont = hfont;
2665 list_add_head(&ret->hfontlist, &hflist->entry);
2668 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2669 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2670 original value lfCharSet. Note this is a special case for
2671 Symbol and doesn't happen at least for "Wingdings*" */
2673 if(!strcmpiW(lf.lfFaceName, SymbolW))
2674 lf.lfCharSet = SYMBOL_CHARSET;
2676 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2677 switch(lf.lfCharSet) {
2678 case DEFAULT_CHARSET:
2679 csi.fs.fsCsb[0] = 0;
2682 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2683 csi.fs.fsCsb[0] = 0;
2689 if(lf.lfFaceName[0] != '\0') {
2691 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2694 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2695 debugstr_w(psub->to.name));
2696 strcpyW(lf.lfFaceName, psub->to.name);
2699 /* We want a match on name and charset or just name if
2700 charset was DEFAULT_CHARSET. If the latter then
2701 we fixup the returned charset later in get_nearest_charset
2702 where we'll either use the charset of the current ansi codepage
2703 or if that's unavailable the first charset that the font supports.
2705 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2706 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2707 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2708 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2709 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2710 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2711 if(face->scalable || can_use_bitmap)
2718 /* If requested charset was DEFAULT_CHARSET then try using charset
2719 corresponding to the current ansi codepage */
2720 if(!csi.fs.fsCsb[0]) {
2722 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
2723 FIXME("TCI failed on codepage %d\n", acp);
2724 csi.fs.fsCsb[0] = 0;
2726 lf.lfCharSet = csi.ciCharset;
2729 /* Face families are in the top 4 bits of lfPitchAndFamily,
2730 so mask with 0xF0 before testing */
2732 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2733 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2734 strcpyW(lf.lfFaceName, defFixed);
2735 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2736 strcpyW(lf.lfFaceName, defSerif);
2737 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2738 strcpyW(lf.lfFaceName, defSans);
2740 strcpyW(lf.lfFaceName, defSans);
2741 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2742 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2743 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
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]))
2747 if(face->scalable || can_use_bitmap)
2753 last_resort_family = NULL;
2754 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2755 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2756 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2757 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2758 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2761 if(can_use_bitmap && !last_resort_family)
2762 last_resort_family = family;
2767 if(last_resort_family) {
2768 family = last_resort_family;
2769 csi.fs.fsCsb[0] = 0;
2773 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2774 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2775 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2776 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2777 if(face->scalable) {
2778 csi.fs.fsCsb[0] = 0;
2779 WARN("just using first face for now\n");
2782 if(can_use_bitmap && !last_resort_family)
2783 last_resort_family = family;
2786 if(!last_resort_family) {
2787 FIXME("can't find a single appropriate font - bailing\n");
2792 WARN("could only find a bitmap font - this will probably look awful!\n");
2793 family = last_resort_family;
2794 csi.fs.fsCsb[0] = 0;
2797 it = lf.lfItalic ? 1 : 0;
2798 bd = lf.lfWeight > 550 ? 1 : 0;
2800 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2801 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2803 face = best = best_bitmap = NULL;
2804 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2806 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2808 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
2809 if(!best || new_score <= score)
2811 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
2812 face->Italic, face->Bold, it, bd);
2815 if(best->scalable && score == 0) break;
2819 newdiff = height - (signed int)(best->size.height);
2821 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
2822 if(!best_bitmap || new_score < score ||
2823 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
2825 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
2828 if(score == 0 && diff == 0) break;
2835 face = best->scalable ? best : best_bitmap;
2836 ret->fake_italic = (it && !face->Italic);
2837 ret->fake_bold = (bd && !face->Bold);
2839 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2841 if(csi.fs.fsCsb[0]) {
2842 ret->charset = lf.lfCharSet;
2843 ret->codepage = csi.ciACP;
2846 ret->charset = get_nearest_charset(face, &ret->codepage);
2848 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2849 debugstr_w(face->StyleName), face->file, face->face_index);
2851 if(!face->scalable) {
2852 width = face->size.x_ppem >> 6;
2853 height = face->size.y_ppem >> 6;
2855 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2863 if (ret->charset == SYMBOL_CHARSET &&
2864 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2867 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2871 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2874 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2875 ret->name = strdupW(family->FamilyName);
2876 ret->underline = lf.lfUnderline ? 0xff : 0;
2877 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2878 create_child_font_list(ret);
2880 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2882 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
2883 list_add_head(&gdi_font_list, &ret->entry);
2887 static void dump_gdi_font_list(void)
2890 struct list *elem_ptr;
2892 TRACE("---------- gdiFont Cache ----------\n");
2893 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2894 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2895 TRACE("gdiFont=%p %s %d\n",
2896 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2899 TRACE("---------- Unused gdiFont Cache ----------\n");
2900 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2901 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2902 TRACE("gdiFont=%p %s %d\n",
2903 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2907 /*************************************************************
2908 * WineEngDestroyFontInstance
2910 * free the gdiFont associated with this handle
2913 BOOL WineEngDestroyFontInstance(HFONT handle)
2918 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2921 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
2923 struct list *first_hfont = list_head(&gdiFont->hfontlist);
2924 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2925 if(hflist->hfont == handle)
2927 TRACE("removing child font %p from child list\n", gdiFont);
2928 list_remove(&gdiFont->entry);
2933 TRACE("destroying hfont=%p\n", handle);
2935 dump_gdi_font_list();
2937 font_elem_ptr = list_head(&gdi_font_list);
2938 while(font_elem_ptr) {
2939 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2940 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
2942 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
2943 while(hfontlist_elem_ptr) {
2944 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2945 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
2946 if(hflist->hfont == handle) {
2947 list_remove(&hflist->entry);
2948 HeapFree(GetProcessHeap(), 0, hflist);
2952 if(list_empty(&gdiFont->hfontlist)) {
2953 TRACE("Moving to Unused list\n");
2954 list_remove(&gdiFont->entry);
2955 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
2960 font_elem_ptr = list_head(&unused_gdi_font_list);
2961 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
2962 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2963 while(font_elem_ptr) {
2964 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2965 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2966 TRACE("freeing %p\n", gdiFont);
2967 list_remove(&gdiFont->entry);
2973 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2974 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
2976 OUTLINETEXTMETRICW *potm = NULL;
2978 TEXTMETRICW tm, *ptm;
2979 GdiFont *font = alloc_font();
2982 if(face->scalable) {
2986 height = face->size.y_ppem >> 6;
2987 width = face->size.x_ppem >> 6;
2990 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
2996 font->name = strdupW(face->family->FamilyName);
2998 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
3000 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
3002 potm = HeapAlloc(GetProcessHeap(), 0, size);
3003 WineEngGetOutlineTextMetrics(font, size, potm);
3004 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
3006 WineEngGetTextMetrics(font, &tm);
3010 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
3011 pntm->ntmTm.tmAscent = ptm->tmAscent;
3012 pntm->ntmTm.tmDescent = ptm->tmDescent;
3013 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
3014 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
3015 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
3016 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
3017 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
3018 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
3019 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
3020 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
3021 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
3022 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
3023 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
3024 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
3025 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
3026 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
3027 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
3028 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
3029 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
3030 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
3031 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3032 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3033 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3035 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
3036 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
3037 *ptype |= RASTER_FONTTYPE;
3039 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
3040 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
3041 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
3043 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3044 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3045 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
3048 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
3050 lstrcpynW(pelf->elfLogFont.lfFaceName,
3051 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
3053 lstrcpynW(pelf->elfFullName,
3054 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
3056 lstrcpynW(pelf->elfStyle,
3057 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
3060 HeapFree(GetProcessHeap(), 0, potm);
3062 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3064 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3065 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
3066 pelf->elfStyle[0] = '\0';
3069 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3074 /*************************************************************
3078 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3082 struct list *family_elem_ptr, *face_elem_ptr;
3084 NEWTEXTMETRICEXW ntm;
3085 DWORD type, ret = 1;
3091 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3093 if(plf->lfFaceName[0]) {
3095 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3098 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3099 debugstr_w(psub->to.name));
3100 memcpy(&lf, plf, sizeof(lf));
3101 strcpyW(lf.lfFaceName, psub->to.name);
3105 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3106 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3107 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3108 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3109 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3110 GetEnumStructs(face, &elf, &ntm, &type);
3111 for(i = 0; i < 32; i++) {
3112 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3113 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3114 strcpyW(elf.elfScript, OEM_DOSW);
3115 i = 32; /* break out of loop */
3116 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3119 fs.fsCsb[0] = 1L << i;
3121 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3123 csi.ciCharset = DEFAULT_CHARSET;
3124 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3125 if(csi.ciCharset != DEFAULT_CHARSET) {
3126 elf.elfLogFont.lfCharSet =
3127 ntm.ntmTm.tmCharSet = csi.ciCharset;
3129 strcpyW(elf.elfScript, ElfScriptsW[i]);
3131 FIXME("Unknown elfscript for bit %d\n", i);
3134 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3135 debugstr_w(elf.elfLogFont.lfFaceName),
3136 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3137 csi.ciCharset, type, debugstr_w(elf.elfScript),
3138 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3139 ntm.ntmTm.ntmFlags);
3140 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3147 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3148 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3149 face_elem_ptr = list_head(&family->faces);
3150 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3151 GetEnumStructs(face, &elf, &ntm, &type);
3152 for(i = 0; i < 32; i++) {
3153 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3154 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3155 strcpyW(elf.elfScript, OEM_DOSW);
3156 i = 32; /* break out of loop */
3157 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3160 fs.fsCsb[0] = 1L << i;
3162 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3164 csi.ciCharset = DEFAULT_CHARSET;
3165 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3166 if(csi.ciCharset != DEFAULT_CHARSET) {
3167 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3170 strcpyW(elf.elfScript, ElfScriptsW[i]);
3172 FIXME("Unknown elfscript for bit %d\n", i);
3175 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3176 debugstr_w(elf.elfLogFont.lfFaceName),
3177 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3178 csi.ciCharset, type, debugstr_w(elf.elfScript),
3179 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3180 ntm.ntmTm.ntmFlags);
3181 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3190 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3192 pt->x.value = vec->x >> 6;
3193 pt->x.fract = (vec->x & 0x3f) << 10;
3194 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3195 pt->y.value = vec->y >> 6;
3196 pt->y.fract = (vec->y & 0x3f) << 10;
3197 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3201 /***************************************************
3202 * According to the MSDN documentation on WideCharToMultiByte,
3203 * certain codepages cannot set the default_used parameter.
3204 * This returns TRUE if the codepage can set that parameter, false else
3205 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3207 static BOOL codepage_sets_default_used(UINT codepage)
3220 static FT_UInt get_glyph_index(GdiFont *font, UINT glyph)
3222 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
3223 WCHAR wc = (WCHAR)glyph;
3225 BOOL *default_used_pointer;
3228 default_used_pointer = NULL;
3229 default_used = FALSE;
3230 if (codepage_sets_default_used(font->codepage))
3231 default_used_pointer = &default_used;
3232 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
3235 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
3236 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
3240 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
3241 glyph = glyph + 0xf000;
3242 return pFT_Get_Char_Index(font->ft_face, glyph);
3245 /*************************************************************
3246 * WineEngGetGlyphIndices
3248 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3250 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
3251 LPWORD pgi, DWORD flags)
3254 WCHAR default_char = 0;
3257 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
3259 for(i = 0; i < count; i++)
3261 pgi[i] = get_glyph_index(font, lpstr[i]);
3266 WineEngGetTextMetrics(font, &textm);
3267 default_char = textm.tmDefaultChar;
3269 pgi[i] = default_char;
3275 /*************************************************************
3276 * WineEngGetGlyphOutline
3278 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3279 * except that the first parameter is the HWINEENGFONT of the font in
3280 * question rather than an HDC.
3283 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
3284 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3287 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3288 FT_Face ft_face = font->ft_face;
3289 FT_UInt glyph_index;
3290 DWORD width, height, pitch, needed = 0;
3291 FT_Bitmap ft_bitmap;
3293 INT left, right, top = 0, bottom = 0;
3295 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3296 float widthRatio = 1.0;
3297 FT_Matrix transMat = identityMat;
3298 BOOL needsTransform = FALSE;
3301 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
3302 buflen, buf, lpmat);
3304 if(format & GGO_GLYPH_INDEX) {
3305 glyph_index = glyph;
3306 format &= ~GGO_GLYPH_INDEX;
3308 glyph_index = get_glyph_index(font, glyph);
3310 if(glyph_index >= font->gmsize) {
3311 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
3312 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
3313 font->gmsize * sizeof(*font->gm));
3315 if(format == GGO_METRICS && font->gm[glyph_index].init) {
3316 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
3317 return 1; /* FIXME */
3321 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
3322 load_flags |= FT_LOAD_NO_BITMAP;
3324 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
3327 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
3331 /* Scaling factor */
3332 if (font->aveWidth && font->potm) {
3333 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
3336 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3337 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3339 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3340 font->gm[glyph_index].lsb = left >> 6;
3341 font->gm[glyph_index].bbx = (right - left) >> 6;
3343 /* Scaling transform */
3344 if(font->aveWidth) {
3346 scaleMat.xx = FT_FixedFromFloat(widthRatio);
3349 scaleMat.yy = (1 << 16);
3351 pFT_Matrix_Multiply(&scaleMat, &transMat);
3352 needsTransform = TRUE;
3355 /* Slant transform */
3356 if (font->fake_italic) {
3359 slantMat.xx = (1 << 16);
3360 slantMat.xy = ((1 << 16) >> 2);
3362 slantMat.yy = (1 << 16);
3363 pFT_Matrix_Multiply(&slantMat, &transMat);
3364 needsTransform = TRUE;
3367 /* Rotation transform */
3368 if(font->orientation) {
3369 FT_Matrix rotationMat;
3371 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3372 pFT_Vector_Unit(&vecAngle, angle);
3373 rotationMat.xx = vecAngle.x;
3374 rotationMat.xy = -vecAngle.y;
3375 rotationMat.yx = -rotationMat.xy;
3376 rotationMat.yy = rotationMat.xx;
3378 pFT_Matrix_Multiply(&rotationMat, &transMat);
3379 needsTransform = TRUE;
3382 /* Extra transformation specified by caller */
3385 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3386 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3387 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3388 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3389 pFT_Matrix_Multiply(&extraMat, &transMat);
3390 needsTransform = TRUE;
3393 if(!needsTransform) {
3394 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3395 bottom = (ft_face->glyph->metrics.horiBearingY -
3396 ft_face->glyph->metrics.height) & -64;
3397 lpgm->gmCellIncX = font->gm[glyph_index].adv;
3398 lpgm->gmCellIncY = 0;
3402 for(xc = 0; xc < 2; xc++) {
3403 for(yc = 0; yc < 2; yc++) {
3404 vec.x = (ft_face->glyph->metrics.horiBearingX +
3405 xc * ft_face->glyph->metrics.width);
3406 vec.y = ft_face->glyph->metrics.horiBearingY -
3407 yc * ft_face->glyph->metrics.height;
3408 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3409 pFT_Vector_Transform(&vec, &transMat);
3410 if(xc == 0 && yc == 0) {
3411 left = right = vec.x;
3412 top = bottom = vec.y;
3414 if(vec.x < left) left = vec.x;
3415 else if(vec.x > right) right = vec.x;
3416 if(vec.y < bottom) bottom = vec.y;
3417 else if(vec.y > top) top = vec.y;
3422 right = (right + 63) & -64;
3423 bottom = bottom & -64;
3424 top = (top + 63) & -64;
3426 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3427 vec.x = ft_face->glyph->metrics.horiAdvance;
3429 pFT_Vector_Transform(&vec, &transMat);
3430 lpgm->gmCellIncX = (vec.x+63) >> 6;
3431 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3433 lpgm->gmBlackBoxX = (right - left) >> 6;
3434 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3435 lpgm->gmptGlyphOrigin.x = left >> 6;
3436 lpgm->gmptGlyphOrigin.y = top >> 6;
3438 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
3439 font->gm[glyph_index].init = TRUE;
3441 if(format == GGO_METRICS)
3442 return 1; /* FIXME */
3444 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
3445 TRACE("loaded a bitmap\n");
3451 width = lpgm->gmBlackBoxX;
3452 height = lpgm->gmBlackBoxY;
3453 pitch = ((width + 31) >> 5) << 2;
3454 needed = pitch * height;
3456 if(!buf || !buflen) break;
3458 switch(ft_face->glyph->format) {
3459 case ft_glyph_format_bitmap:
3461 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3462 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3463 INT h = ft_face->glyph->bitmap.rows;
3465 memcpy(dst, src, w);
3466 src += ft_face->glyph->bitmap.pitch;
3472 case ft_glyph_format_outline:
3473 ft_bitmap.width = width;
3474 ft_bitmap.rows = height;
3475 ft_bitmap.pitch = pitch;
3476 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3477 ft_bitmap.buffer = buf;
3479 if(needsTransform) {
3480 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3483 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3485 /* Note: FreeType will only set 'black' bits for us. */
3486 memset(buf, 0, needed);
3487 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3491 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3496 case GGO_GRAY2_BITMAP:
3497 case GGO_GRAY4_BITMAP:
3498 case GGO_GRAY8_BITMAP:
3499 case WINE_GGO_GRAY16_BITMAP:
3501 unsigned int mult, row, col;
3504 width = lpgm->gmBlackBoxX;
3505 height = lpgm->gmBlackBoxY;
3506 pitch = (width + 3) / 4 * 4;
3507 needed = pitch * height;
3509 if(!buf || !buflen) break;
3510 ft_bitmap.width = width;
3511 ft_bitmap.rows = height;
3512 ft_bitmap.pitch = pitch;
3513 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3514 ft_bitmap.buffer = buf;
3516 if(needsTransform) {
3517 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3520 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3522 memset(ft_bitmap.buffer, 0, buflen);
3524 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3526 if(format == GGO_GRAY2_BITMAP)
3528 else if(format == GGO_GRAY4_BITMAP)
3530 else if(format == GGO_GRAY8_BITMAP)
3532 else if(format == WINE_GGO_GRAY16_BITMAP)
3540 for(row = 0; row < height; row++) {
3542 for(col = 0; col < width; col++, ptr++) {
3543 *ptr = (((int)*ptr) * mult + 128) / 256;
3552 int contour, point = 0, first_pt;
3553 FT_Outline *outline = &ft_face->glyph->outline;
3554 TTPOLYGONHEADER *pph;
3556 DWORD pph_start, cpfx, type;
3558 if(buflen == 0) buf = NULL;
3560 if (needsTransform && buf) {
3561 pFT_Outline_Transform(outline, &transMat);
3564 for(contour = 0; contour < outline->n_contours; contour++) {
3566 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3569 pph->dwType = TT_POLYGON_TYPE;
3570 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3572 needed += sizeof(*pph);
3574 while(point <= outline->contours[contour]) {
3575 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3576 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3577 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3581 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3584 } while(point <= outline->contours[contour] &&
3585 (outline->tags[point] & FT_Curve_Tag_On) ==
3586 (outline->tags[point-1] & FT_Curve_Tag_On));
3587 /* At the end of a contour Windows adds the start point, but
3589 if(point > outline->contours[contour] &&
3590 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3592 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3594 } else if(point <= outline->contours[contour] &&
3595 outline->tags[point] & FT_Curve_Tag_On) {
3596 /* add closing pt for bezier */
3598 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3606 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3609 pph->cb = needed - pph_start;
3615 /* Convert the quadratic Beziers to cubic Beziers.
3616 The parametric eqn for a cubic Bezier is, from PLRM:
3617 r(t) = at^3 + bt^2 + ct + r0
3618 with the control points:
3623 A quadratic Beizer has the form:
3624 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3626 So equating powers of t leads to:
3627 r1 = 2/3 p1 + 1/3 p0
3628 r2 = 2/3 p1 + 1/3 p2
3629 and of course r0 = p0, r3 = p2
3632 int contour, point = 0, first_pt;
3633 FT_Outline *outline = &ft_face->glyph->outline;
3634 TTPOLYGONHEADER *pph;
3636 DWORD pph_start, cpfx, type;
3637 FT_Vector cubic_control[4];
3638 if(buflen == 0) buf = NULL;
3640 if (needsTransform && buf) {
3641 pFT_Outline_Transform(outline, &transMat);
3644 for(contour = 0; contour < outline->n_contours; contour++) {
3646 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3649 pph->dwType = TT_POLYGON_TYPE;
3650 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3652 needed += sizeof(*pph);
3654 while(point <= outline->contours[contour]) {
3655 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3656 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3657 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3660 if(type == TT_PRIM_LINE) {
3662 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3666 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3669 /* FIXME: Possible optimization in endpoint calculation
3670 if there are two consecutive curves */
3671 cubic_control[0] = outline->points[point-1];
3672 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3673 cubic_control[0].x += outline->points[point].x + 1;
3674 cubic_control[0].y += outline->points[point].y + 1;
3675 cubic_control[0].x >>= 1;
3676 cubic_control[0].y >>= 1;
3678 if(point+1 > outline->contours[contour])
3679 cubic_control[3] = outline->points[first_pt];
3681 cubic_control[3] = outline->points[point+1];
3682 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3683 cubic_control[3].x += outline->points[point].x + 1;
3684 cubic_control[3].y += outline->points[point].y + 1;
3685 cubic_control[3].x >>= 1;
3686 cubic_control[3].y >>= 1;
3689 /* r1 = 1/3 p0 + 2/3 p1
3690 r2 = 1/3 p2 + 2/3 p1 */
3691 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3692 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3693 cubic_control[2] = cubic_control[1];
3694 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3695 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3696 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3697 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3699 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3700 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3701 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3706 } while(point <= outline->contours[contour] &&
3707 (outline->tags[point] & FT_Curve_Tag_On) ==
3708 (outline->tags[point-1] & FT_Curve_Tag_On));
3709 /* At the end of a contour Windows adds the start point,
3710 but only for Beziers and we've already done that.
3712 if(point <= outline->contours[contour] &&
3713 outline->tags[point] & FT_Curve_Tag_On) {
3714 /* This is the closing pt of a bezier, but we've already
3715 added it, so just inc point and carry on */
3722 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3725 pph->cb = needed - pph_start;
3731 FIXME("Unsupported format %d\n", format);
3737 static BOOL get_bitmap_text_metrics(GdiFont *font)
3739 FT_Face ft_face = font->ft_face;
3740 #ifdef HAVE_FREETYPE_FTWINFNT_H
3741 FT_WinFNT_HeaderRec winfnt_header;
3743 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3744 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3745 font->potm->otmSize = size;
3747 #define TM font->potm->otmTextMetrics
3748 #ifdef HAVE_FREETYPE_FTWINFNT_H
3749 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3751 TM.tmHeight = winfnt_header.pixel_height;
3752 TM.tmAscent = winfnt_header.ascent;
3753 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3754 TM.tmInternalLeading = winfnt_header.internal_leading;
3755 TM.tmExternalLeading = winfnt_header.external_leading;
3756 TM.tmAveCharWidth = winfnt_header.avg_width;
3757 TM.tmMaxCharWidth = winfnt_header.max_width;
3758 TM.tmWeight = winfnt_header.weight;
3760 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3761 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3762 TM.tmFirstChar = winfnt_header.first_char;
3763 TM.tmLastChar = winfnt_header.last_char;
3764 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3765 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3766 TM.tmItalic = winfnt_header.italic;
3767 TM.tmUnderlined = font->underline;
3768 TM.tmStruckOut = font->strikeout;
3769 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3770 TM.tmCharSet = winfnt_header.charset;
3775 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3776 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3777 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3778 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3779 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3780 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3781 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3782 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3784 TM.tmDigitizedAspectX = 96; /* FIXME */
3785 TM.tmDigitizedAspectY = 96; /* FIXME */
3787 TM.tmLastChar = 255;
3788 TM.tmDefaultChar = 32;
3789 TM.tmBreakChar = 32;
3790 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3791 TM.tmUnderlined = font->underline;
3792 TM.tmStruckOut = font->strikeout;
3793 /* NB inverted meaning of TMPF_FIXED_PITCH */
3794 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3795 TM.tmCharSet = font->charset;
3802 /*************************************************************
3803 * WineEngGetTextMetrics
3806 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
3809 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3810 if(!get_bitmap_text_metrics(font))
3813 if(!font->potm) return FALSE;
3814 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3816 if (font->aveWidth) {
3817 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3823 /*************************************************************
3824 * WineEngGetOutlineTextMetrics
3827 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
3828 OUTLINETEXTMETRICW *potm)
3830 FT_Face ft_face = font->ft_face;
3831 UINT needed, lenfam, lensty, ret;
3833 TT_HoriHeader *pHori;
3834 TT_Postscript *pPost;
3835 FT_Fixed x_scale, y_scale;
3836 WCHAR *family_nameW, *style_nameW;
3837 static const WCHAR spaceW[] = {' ', '\0'};
3839 INT ascent, descent;
3841 TRACE("font=%p\n", font);
3843 if(!FT_IS_SCALABLE(ft_face))
3847 if(cbSize >= font->potm->otmSize)
3848 memcpy(potm, font->potm, font->potm->otmSize);
3849 return font->potm->otmSize;
3853 needed = sizeof(*potm);
3855 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3856 family_nameW = strdupW(font->name);
3858 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3860 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3861 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3862 style_nameW, lensty/sizeof(WCHAR));
3864 /* These names should be read from the TT name table */
3866 /* length of otmpFamilyName */
3869 /* length of otmpFaceName */
3870 if(!strcasecmp(ft_face->style_name, "regular")) {
3871 needed += lenfam; /* just the family name */
3873 needed += lenfam + lensty; /* family + " " + style */
3876 /* length of otmpStyleName */
3879 /* length of otmpFullName */
3880 needed += lenfam + lensty;
3883 x_scale = ft_face->size->metrics.x_scale;
3884 y_scale = ft_face->size->metrics.y_scale;
3886 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3888 FIXME("Can't find OS/2 table - not TT font?\n");
3893 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3895 FIXME("Can't find HHEA table - not TT font?\n");
3900 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3902 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",
3903 pOS2->usWinAscent, pOS2->usWinDescent,
3904 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3905 ft_face->ascender, ft_face->descender, ft_face->height,
3906 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3907 ft_face->bbox.yMax, ft_face->bbox.yMin);
3909 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3910 font->potm->otmSize = needed;
3912 #define TM font->potm->otmTextMetrics
3914 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3915 ascent = pHori->Ascender;
3916 descent = -pHori->Descender;
3918 ascent = pOS2->usWinAscent;
3919 descent = pOS2->usWinDescent;
3923 TM.tmAscent = font->yMax;
3924 TM.tmDescent = -font->yMin;
3925 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3927 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
3928 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
3929 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
3930 - ft_face->units_per_EM, y_scale) + 32) >> 6;
3933 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3936 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3938 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
3939 ((ascent + descent) -
3940 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
3942 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
3943 if (TM.tmAveCharWidth == 0) {
3944 TM.tmAveCharWidth = 1;
3946 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
3947 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
3949 TM.tmDigitizedAspectX = 300;
3950 TM.tmDigitizedAspectY = 300;
3951 TM.tmFirstChar = pOS2->usFirstCharIndex;
3952 TM.tmLastChar = pOS2->usLastCharIndex;
3953 TM.tmDefaultChar = pOS2->usDefaultChar;
3954 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
3955 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3956 TM.tmUnderlined = font->underline;
3957 TM.tmStruckOut = font->strikeout;
3959 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3960 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3961 (pOS2->version == 0xFFFFU ||
3962 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3963 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3965 TM.tmPitchAndFamily = 0;
3967 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
3968 case PAN_FAMILY_SCRIPT:
3969 TM.tmPitchAndFamily |= FF_SCRIPT;
3971 case PAN_FAMILY_DECORATIVE:
3972 case PAN_FAMILY_PICTORIAL:
3973 TM.tmPitchAndFamily |= FF_DECORATIVE;
3975 case PAN_FAMILY_TEXT_DISPLAY:
3976 if(TM.tmPitchAndFamily == 0) /* fixed */
3977 TM.tmPitchAndFamily = FF_MODERN;
3979 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
3980 case PAN_SERIF_NORMAL_SANS:
3981 case PAN_SERIF_OBTUSE_SANS:
3982 case PAN_SERIF_PERP_SANS:
3983 TM.tmPitchAndFamily |= FF_SWISS;
3986 TM.tmPitchAndFamily |= FF_ROMAN;
3991 TM.tmPitchAndFamily |= FF_DONTCARE;
3994 if(FT_IS_SCALABLE(ft_face))
3995 TM.tmPitchAndFamily |= TMPF_VECTOR;
3996 if(FT_IS_SFNT(ft_face))
3997 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3999 TM.tmCharSet = font->charset;
4002 font->potm->otmFiller = 0;
4003 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
4004 font->potm->otmfsSelection = pOS2->fsSelection;
4005 font->potm->otmfsType = pOS2->fsType;
4006 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
4007 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
4008 font->potm->otmItalicAngle = 0; /* POST table */
4009 font->potm->otmEMSquare = ft_face->units_per_EM;
4010 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
4011 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4012 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4013 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
4014 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4015 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
4016 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
4017 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
4018 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4019 font->potm->otmMacAscent = 0; /* where do these come from ? */
4020 font->potm->otmMacDescent = 0;
4021 font->potm->otmMacLineGap = 0;
4022 font->potm->otmusMinimumPPEM = 0; /* TT Header */
4023 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
4024 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
4025 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
4026 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
4027 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
4028 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
4029 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
4030 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
4031 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
4032 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4034 font->potm->otmsUnderscoreSize = 0;
4035 font->potm->otmsUnderscorePosition = 0;
4037 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
4038 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
4041 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4042 cp = (char*)font->potm + sizeof(*font->potm);
4043 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4044 strcpyW((WCHAR*)cp, family_nameW);
4046 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4047 strcpyW((WCHAR*)cp, style_nameW);
4049 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4050 strcpyW((WCHAR*)cp, family_nameW);
4051 if(strcasecmp(ft_face->style_name, "regular")) {
4052 strcatW((WCHAR*)cp, spaceW);
4053 strcatW((WCHAR*)cp, style_nameW);
4054 cp += lenfam + lensty;
4057 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
4058 strcpyW((WCHAR*)cp, family_nameW);
4059 strcatW((WCHAR*)cp, spaceW);
4060 strcatW((WCHAR*)cp, style_nameW);
4063 if(potm && needed <= cbSize)
4064 memcpy(potm, font->potm, font->potm->otmSize);
4067 HeapFree(GetProcessHeap(), 0, style_nameW);
4068 HeapFree(GetProcessHeap(), 0, family_nameW);
4073 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
4075 HFONTLIST *hfontlist;
4076 child->font = alloc_font();
4077 child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem);
4078 if(!child->font->ft_face)
4080 free_font(child->font);
4085 child->font->orientation = font->orientation;
4086 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
4087 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
4088 list_add_head(&child->font->hfontlist, &hfontlist->entry);
4089 child->font->base_font = font;
4090 list_add_head(&child_font_list, &child->font->entry);
4091 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
4095 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
4098 CHILD_FONT *child_font;
4101 font = font->base_font;
4103 *linked_font = font;
4105 if((*glyph = get_glyph_index(font, c)))
4108 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
4110 if(!child_font->font)
4111 if(!load_child_font(font, child_font))
4114 if(!child_font->font->ft_face)
4116 g = get_glyph_index(child_font->font, c);
4120 *linked_font = child_font->font;
4127 /*************************************************************
4128 * WineEngGetCharWidth
4131 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4136 FT_UInt glyph_index;
4137 GdiFont *linked_font;
4139 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4141 for(c = firstChar; c <= lastChar; c++) {
4142 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4143 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4144 &gm, 0, NULL, NULL);
4145 buffer[c - firstChar] = linked_font->gm[glyph_index].adv;
4150 /*************************************************************
4151 * WineEngGetCharABCWidths
4154 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4159 FT_UInt glyph_index;
4160 GdiFont *linked_font;
4162 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4164 if(!FT_IS_SCALABLE(font->ft_face))
4167 for(c = firstChar; c <= lastChar; c++) {
4168 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4169 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4170 &gm, 0, NULL, NULL);
4171 buffer[c - firstChar].abcA = linked_font->gm[glyph_index].lsb;
4172 buffer[c - firstChar].abcB = linked_font->gm[glyph_index].bbx;
4173 buffer[c - firstChar].abcC = linked_font->gm[glyph_index].adv - linked_font->gm[glyph_index].lsb -
4174 linked_font->gm[glyph_index].bbx;
4179 /*************************************************************
4180 * WineEngGetCharABCWidthsI
4183 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4188 FT_UInt glyph_index;
4189 GdiFont *linked_font;
4191 if(!FT_IS_SCALABLE(font->ft_face))
4194 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
4196 for(c = firstChar; c < firstChar+count; c++) {
4197 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
4198 &gm, 0, NULL, NULL);
4199 buffer[c - firstChar].abcA = linked_font->gm[c].lsb;
4200 buffer[c - firstChar].abcB = linked_font->gm[c].bbx;
4201 buffer[c - firstChar].abcC = linked_font->gm[c].adv - linked_font->gm[c].lsb
4202 - linked_font->gm[c].bbx;
4205 for(c = 0; c < count; c++) {
4206 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
4207 &gm, 0, NULL, NULL);
4208 buffer[c].abcA = linked_font->gm[pgi[c]].lsb;
4209 buffer[c].abcB = linked_font->gm[pgi[c]].bbx;
4210 buffer[c].abcC = linked_font->gm[pgi[c]].adv
4211 - linked_font->gm[pgi[c]].lsb - linked_font->gm[pgi[c]].bbx;
4217 /*************************************************************
4218 * WineEngGetTextExtentExPoint
4221 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4222 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4228 FT_UInt glyph_index;
4229 GdiFont *linked_font;
4231 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
4235 WineEngGetTextMetrics(font, &tm);
4236 size->cy = tm.tmHeight;
4238 for(idx = 0; idx < count; idx++) {
4239 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
4240 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4241 &gm, 0, NULL, NULL);
4242 size->cx += linked_font->gm[glyph_index].adv;
4244 if (! pnfit || ext <= max_ext) {
4254 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4258 /*************************************************************
4259 * WineEngGetTextExtentPointI
4262 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4269 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
4272 WineEngGetTextMetrics(font, &tm);
4273 size->cy = tm.tmHeight;
4275 for(idx = 0; idx < count; idx++) {
4276 WineEngGetGlyphOutline(font, indices[idx],
4277 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
4279 size->cx += font->gm[indices[idx]].adv;
4281 TRACE("return %d,%d\n", size->cx, size->cy);
4285 /*************************************************************
4286 * WineEngGetFontData
4289 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4292 FT_Face ft_face = font->ft_face;
4296 TRACE("font=%p, table=%08x, offset=%08x, buf=%p, cbData=%x\n",
4297 font, table, offset, buf, cbData);
4299 if(!FT_IS_SFNT(ft_face))
4307 if(table) { /* MS tags differ in endidness from FT ones */
4308 table = table >> 24 | table << 24 |
4309 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
4312 /* If the FT_Load_Sfnt_Table function is there we'll use it */
4313 if(pFT_Load_Sfnt_Table) {
4314 /* make sure value of len is the value freetype says it needs */
4316 FT_ULong needed = 0;
4317 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4318 if( !err && needed < len) len = needed;
4320 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4322 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
4323 else { /* Do it the hard way */
4324 TT_Face tt_face = (TT_Face) ft_face;
4325 SFNT_Interface *sfnt;
4326 if (FT_Version.major==2 && FT_Version.minor==0)
4329 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
4333 /* A field was added in the middle of the structure in 2.1.x */
4334 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
4336 /* make sure value of len is the value freetype says it needs */
4338 FT_ULong needed = 0;
4339 err = sfnt->load_any(tt_face, table, offset, NULL, &needed);
4340 if( !err && needed < len) len = needed;
4342 err = sfnt->load_any(tt_face, table, offset, buf, &len);
4348 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
4349 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
4350 "Please upgrade your freetype library.\n");
4353 err = FT_Err_Unimplemented_Feature;
4357 TRACE("Can't find table %08x.\n", table);
4363 /*************************************************************
4364 * WineEngGetTextFace
4367 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4370 lstrcpynW(str, font->name, count);
4371 return strlenW(font->name);
4373 return strlenW(font->name) + 1;
4376 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4378 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4379 return font->charset;
4382 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4384 GdiFont *font = dc->gdiFont, *linked_font;
4385 struct list *first_hfont;
4388 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4389 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4390 if(font == linked_font)
4391 *new_hfont = dc->hFont;
4394 first_hfont = list_head(&linked_font->hfontlist);
4395 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4402 /*************************************************************
4405 BOOL WINAPI FontIsLinked(HDC hdc)
4407 DC *dc = DC_GetDCPtr(hdc);
4410 if(!dc) return FALSE;
4411 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
4413 GDI_ReleaseObj(hdc);
4414 TRACE("returning %d\n", ret);
4418 static BOOL is_hinting_enabled(void)
4420 /* Use the >= 2.2.0 function if available */
4421 if(pFT_Get_TrueType_Engine_Type)
4423 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4424 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4426 #ifdef FT_DRIVER_HAS_HINTER
4431 /* otherwise if we've been compiled with < 2.2.0 headers
4432 use the internal macro */
4433 mod = pFT_Get_Module(library, "truetype");
4434 if(mod && FT_DRIVER_HAS_HINTER(mod))
4442 /*************************************************************************
4443 * GetRasterizerCaps (GDI32.@)
4445 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4447 static int hinting = -1;
4451 hinting = is_hinting_enabled();
4452 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
4455 lprs->nSize = sizeof(RASTERIZER_STATUS);
4456 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4457 lprs->nLanguageID = 0;
4461 /*************************************************************************
4462 * Kerning support for TrueType fonts
4464 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4466 struct TT_kern_table
4472 struct TT_kern_subtable
4481 USHORT horizontal : 1;
4483 USHORT cross_stream: 1;
4484 USHORT override : 1;
4485 USHORT reserved1 : 4;
4491 struct TT_format0_kern_subtable
4495 USHORT entrySelector;
4506 static DWORD parse_format0_kern_subtable(GdiFont *font,
4507 const struct TT_format0_kern_subtable *tt_f0_ks,
4508 const USHORT *glyph_to_char,
4509 KERNINGPAIR *kern_pair, DWORD cPairs)
4512 const struct TT_kern_pair *tt_kern_pair;
4514 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
4516 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4518 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4519 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4520 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4522 if (!kern_pair || !cPairs)
4525 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4527 nPairs = min(nPairs, cPairs);
4529 for (i = 0; i < nPairs; i++)
4531 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4532 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4533 /* this algorithm appears to better match what Windows does */
4534 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4535 if (kern_pair->iKernAmount < 0)
4537 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
4538 kern_pair->iKernAmount -= font->ppem;
4540 else if (kern_pair->iKernAmount > 0)
4542 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
4543 kern_pair->iKernAmount += font->ppem;
4545 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
4547 TRACE("left %u right %u value %d\n",
4548 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
4552 TRACE("copied %u entries\n", nPairs);
4556 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4560 const struct TT_kern_table *tt_kern_table;
4561 const struct TT_kern_subtable *tt_kern_subtable;
4563 USHORT *glyph_to_char;
4565 if (font->total_kern_pairs != (DWORD)-1)
4567 if (cPairs && kern_pair)
4569 cPairs = min(cPairs, font->total_kern_pairs);
4570 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4573 return font->total_kern_pairs;
4576 font->total_kern_pairs = 0;
4578 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
4580 if (length == GDI_ERROR)
4582 TRACE("no kerning data in the font\n");
4586 buf = HeapAlloc(GetProcessHeap(), 0, length);
4589 WARN("Out of memory\n");
4593 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
4595 /* build a glyph index to char code map */
4596 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
4599 WARN("Out of memory allocating a glyph index to char code map\n");
4600 HeapFree(GetProcessHeap(), 0, buf);
4604 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4610 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
4612 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4613 font->ft_face->num_glyphs, glyph_code, char_code);
4617 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4619 /* FIXME: This doesn't match what Windows does: it does some fancy
4620 * things with duplicate glyph index to char code mappings, while
4621 * we just avoid overriding existing entries.
4623 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
4624 glyph_to_char[glyph_code] = (USHORT)char_code;
4626 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
4633 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
4634 for (n = 0; n <= 65535; n++)
4635 glyph_to_char[n] = (USHORT)n;
4638 tt_kern_table = buf;
4639 nTables = GET_BE_WORD(tt_kern_table->nTables);
4640 TRACE("version %u, nTables %u\n",
4641 GET_BE_WORD(tt_kern_table->version), nTables);
4643 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
4645 for (i = 0; i < nTables; i++)
4647 struct TT_kern_subtable tt_kern_subtable_copy;
4649 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
4650 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
4651 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
4653 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4654 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
4655 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
4657 /* According to the TrueType specification this is the only format
4658 * that will be properly interpreted by Windows and OS/2
4660 if (tt_kern_subtable_copy.coverage.bits.format == 0)
4662 DWORD new_chunk, old_total = font->total_kern_pairs;
4664 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4665 glyph_to_char, NULL, 0);
4666 font->total_kern_pairs += new_chunk;
4668 if (!font->kern_pairs)
4669 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
4670 font->total_kern_pairs * sizeof(*font->kern_pairs));
4672 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
4673 font->total_kern_pairs * sizeof(*font->kern_pairs));
4675 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4676 glyph_to_char, font->kern_pairs + old_total, new_chunk);
4679 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
4681 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
4684 HeapFree(GetProcessHeap(), 0, glyph_to_char);
4685 HeapFree(GetProcessHeap(), 0, buf);
4687 if (cPairs && kern_pair)
4689 cPairs = min(cPairs, font->total_kern_pairs);
4690 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4693 return font->total_kern_pairs;
4696 #else /* HAVE_FREETYPE */
4698 /*************************************************************************/
4700 BOOL WineEngInit(void)
4704 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
4708 BOOL WineEngDestroyFontInstance(HFONT hfont)
4713 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4718 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4719 LPWORD pgi, DWORD flags)
4724 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
4725 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4728 ERR("called but we don't have FreeType\n");
4732 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4734 ERR("called but we don't have FreeType\n");
4738 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4739 OUTLINETEXTMETRICW *potm)
4741 ERR("called but we don't have FreeType\n");
4745 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4748 ERR("called but we don't have FreeType\n");
4752 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4755 ERR("called but we don't have FreeType\n");
4759 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4762 ERR("called but we don't have FreeType\n");
4766 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4767 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
4769 ERR("called but we don't have FreeType\n");
4773 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4776 ERR("called but we don't have FreeType\n");
4780 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4783 ERR("called but we don't have FreeType\n");
4787 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4789 ERR("called but we don't have FreeType\n");
4793 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4799 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4805 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4808 return DEFAULT_CHARSET;
4811 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4816 BOOL WINAPI FontIsLinked(HDC hdc)
4821 /*************************************************************************
4822 * GetRasterizerCaps (GDI32.@)
4824 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4826 lprs->nSize = sizeof(RASTERIZER_STATUS);
4828 lprs->nLanguageID = 0;
4832 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4834 ERR("called but we don't have FreeType\n");
4838 #endif /* HAVE_FREETYPE */