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',' ',
343 'R','o','m','a','n','\0'};
344 static const WCHAR defSans[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
345 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
347 static const WCHAR defSystem[] = {'S','y','s','t','e','m','\0'};
348 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
349 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
350 'S','e','r','i','f','\0'};
351 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
352 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
354 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
355 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
356 'W','i','n','d','o','w','s','\\',
357 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
358 'F','o','n','t','s','\0'};
360 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
361 'W','i','n','d','o','w','s',' ','N','T','\\',
362 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
363 'F','o','n','t','s','\0'};
365 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
366 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
367 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
368 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
370 static const WCHAR * const SystemFontValues[4] = {
377 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
378 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
380 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
381 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
382 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
383 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
384 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
385 'E','u','r','o','p','e','a','n','\0'};
386 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
387 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
388 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
389 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
390 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
391 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
392 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
393 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
394 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
395 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
396 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
397 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
399 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
409 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
417 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
426 typedef struct tagFontSubst {
442 static struct list mappings_list = LIST_INIT( mappings_list );
444 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
446 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
449 /****************************************
450 * Notes on .fon files
452 * The fonts System, FixedSys and Terminal are special. There are typically multiple
453 * versions installed for different resolutions and codepages. Windows stores which one to use
454 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
456 * FIXEDFON.FON FixedSys
458 * OEMFONT.FON Terminal
459 * LogPixels Current dpi set by the display control panel applet
460 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
461 * also has a LogPixels value that appears to mirror this)
463 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
464 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
465 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
466 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
467 * so that makes sense.
469 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
470 * to be mapped into the registry on Windows 2000 at least).
473 * ega80woa.fon=ega80850.fon
474 * ega40woa.fon=ega40850.fon
475 * cga80woa.fon=cga80850.fon
476 * cga40woa.fon=cga40850.fon
479 #ifdef HAVE_CARBON_CARBON_H
480 static char *find_cache_dir(void)
484 static char cached_path[MAX_PATH];
485 static const char *wine = "/Wine", *fonts = "/Fonts";
487 if(*cached_path) return cached_path;
489 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
492 WARN("can't create cached data folder\n");
495 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
498 WARN("can't create cached data path\n");
502 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
504 ERR("Could not create full path\n");
508 strcat(cached_path, wine);
510 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
512 WARN("Couldn't mkdir %s\n", cached_path);
516 strcat(cached_path, fonts);
517 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
519 WARN("Couldn't mkdir %s\n", cached_path);
526 /******************************************************************
529 * Extracts individual TrueType font files from a Mac suitcase font
530 * and saves them into the user's caches directory (see
532 * Returns a NULL terminated array of filenames.
534 * We do this because they are apps that try to read ttf files
535 * themselves and they don't like Mac suitcase files.
537 static char **expand_mac_font(const char *path)
544 const char *filename;
548 unsigned int size, max_size;
551 TRACE("path %s\n", path);
553 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
556 WARN("failed to get ref\n");
560 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
563 TRACE("no data fork, so trying resource fork\n");
564 res_ref = FSOpenResFile(&ref, fsRdPerm);
567 TRACE("unable to open resource fork\n");
574 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
577 CloseResFile(res_ref);
581 out_dir = find_cache_dir();
583 filename = strrchr(path, '/');
584 if(!filename) filename = path;
587 /* output filename has the form out_dir/filename_%04x.ttf */
588 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
595 unsigned short *num_faces_ptr, num_faces, face;
599 fond = Get1IndResource('FOND', idx);
601 TRACE("got fond resource %d\n", idx);
604 fam_rec = *(FamRec**)fond;
605 num_faces_ptr = (unsigned short *)(fam_rec + 1);
606 num_faces = GET_BE_WORD(*num_faces_ptr);
608 assoc = (AsscEntry*)(num_faces_ptr + 1);
609 TRACE("num faces %04x\n", num_faces);
610 for(face = 0; face < num_faces; face++, assoc++)
613 unsigned short size, font_id;
616 size = GET_BE_WORD(assoc->fontSize);
617 font_id = GET_BE_WORD(assoc->fontID);
620 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
624 TRACE("trying to load sfnt id %04x\n", font_id);
625 sfnt = GetResource('sfnt', font_id);
628 TRACE("can't get sfnt resource %04x\n", font_id);
632 output = HeapAlloc(GetProcessHeap(), 0, output_len);
637 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
639 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
640 if(fd != -1 || errno == EEXIST)
644 unsigned char *sfnt_data;
647 sfnt_data = *(unsigned char**)sfnt;
648 write(fd, sfnt_data, GetHandleSize(sfnt));
652 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
655 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
657 ret.array[ret.size++] = output;
661 WARN("unable to create %s\n", output);
662 HeapFree(GetProcessHeap(), 0, output);
665 ReleaseResource(sfnt);
668 ReleaseResource(fond);
671 CloseResFile(res_ref);
676 #endif /* HAVE_CARBON_CARBON_H */
678 static inline BOOL is_win9x(void)
680 return GetVersion() & 0x80000000;
683 This function builds an FT_Fixed from a float. It puts the integer part
684 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
685 It fails if the integer part of the float number is greater than SHORT_MAX.
687 static inline FT_Fixed FT_FixedFromFloat(float f)
690 unsigned short fract = (f - value) * 0xFFFF;
691 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
695 This function builds an FT_Fixed from a FIXED. It simply put f.value
696 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
698 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
700 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
704 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
709 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
710 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
712 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
713 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
715 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
717 if(face_name && strcmpiW(face_name, family->FamilyName))
719 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
721 file = strrchr(face->file, '/');
726 if(!strcasecmp(file, file_nameA))
728 HeapFree(GetProcessHeap(), 0, file_nameA);
733 HeapFree(GetProcessHeap(), 0, file_nameA);
737 static Family *find_family_from_name(const WCHAR *name)
741 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
743 if(!strcmpiW(family->FamilyName, name))
750 static void DumpSubstList(void)
754 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
756 if(psub->from.charset != -1 || psub->to.charset != -1)
757 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
758 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
760 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
761 debugstr_w(psub->to.name));
766 static LPWSTR strdupW(LPCWSTR p)
769 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
770 ret = HeapAlloc(GetProcessHeap(), 0, len);
775 static LPSTR strdupA(LPCSTR p)
778 DWORD len = (strlen(p) + 1);
779 ret = HeapAlloc(GetProcessHeap(), 0, len);
784 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
789 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
791 if(!strcmpiW(element->from.name, from_name) &&
792 (element->from.charset == from_charset ||
793 element->from.charset == -1))
800 #define ADD_FONT_SUBST_FORCE 1
802 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
804 FontSubst *from_exist, *to_exist;
806 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
808 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
810 list_remove(&from_exist->entry);
811 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
812 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
813 HeapFree(GetProcessHeap(), 0, from_exist);
819 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
823 HeapFree(GetProcessHeap(), 0, subst->to.name);
824 subst->to.name = strdupW(to_exist->to.name);
827 list_add_tail(subst_list, &subst->entry);
832 HeapFree(GetProcessHeap(), 0, subst->from.name);
833 HeapFree(GetProcessHeap(), 0, subst->to.name);
834 HeapFree(GetProcessHeap(), 0, subst);
838 static void split_subst_info(NameCs *nc, LPSTR str)
840 CHAR *p = strrchr(str, ',');
845 nc->charset = strtol(p+1, NULL, 10);
848 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
849 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
850 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
853 static void LoadSubstList(void)
857 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
861 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
862 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
863 &hkey) == ERROR_SUCCESS) {
865 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
866 &valuelen, &datalen, NULL, NULL);
868 valuelen++; /* returned value doesn't include room for '\0' */
869 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
870 data = HeapAlloc(GetProcessHeap(), 0, datalen);
874 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
875 &dlen) == ERROR_SUCCESS) {
876 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
878 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
879 split_subst_info(&psub->from, value);
880 split_subst_info(&psub->to, data);
882 /* Win 2000 doesn't allow mapping between different charsets
883 or mapping of DEFAULT_CHARSET */
884 if((psub->to.charset != psub->from.charset) ||
885 psub->to.charset == DEFAULT_CHARSET) {
886 HeapFree(GetProcessHeap(), 0, psub->to.name);
887 HeapFree(GetProcessHeap(), 0, psub->from.name);
888 HeapFree(GetProcessHeap(), 0, psub);
890 add_font_subst(&font_subst_list, psub, 0);
892 /* reset dlen and vlen */
896 HeapFree(GetProcessHeap(), 0, data);
897 HeapFree(GetProcessHeap(), 0, value);
902 static WCHAR *get_familyname(FT_Face ft_face)
904 WCHAR *family = NULL;
906 FT_UInt num_names, name_index, i;
908 if(FT_IS_SFNT(ft_face))
910 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
912 for(name_index = 0; name_index < num_names; name_index++)
914 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
916 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
917 (name.language_id == GetUserDefaultLCID()) &&
918 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
919 (name.encoding_id == TT_MS_ID_UNICODE_CS))
921 /* String is not nul terminated and string_len is a byte length. */
922 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
923 for(i = 0; i < name.string_len / 2; i++)
925 WORD *tmp = (WORD *)&name.string[i * 2];
926 family[i] = GET_BE_WORD(*tmp);
930 TRACE("Got localised name %s\n", debugstr_w(family));
941 #define ADDFONT_EXTERNAL_FONT 0x01
942 #define ADDFONT_FORCE_BITMAP 0x02
943 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
947 TT_Header *pHeader = NULL;
948 WCHAR *english_family, *localised_family, *StyleW;
952 struct list *family_elem_ptr, *face_elem_ptr;
954 FT_Long face_index = 0, num_faces;
955 #ifdef HAVE_FREETYPE_FTWINFNT_H
956 FT_WinFNT_HeaderRec winfnt_header;
958 int i, bitmap_num, internal_leading;
961 #ifdef HAVE_CARBON_CARBON_H
964 char **mac_list = expand_mac_font(file);
967 BOOL had_one = FALSE;
969 for(cursor = mac_list; *cursor; cursor++)
972 AddFontFileToList(*cursor, NULL, flags);
973 HeapFree(GetProcessHeap(), 0, *cursor);
975 HeapFree(GetProcessHeap(), 0, mac_list);
980 #endif /* HAVE_CARBON_CARBON_H */
983 char *family_name = fake_family;
985 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
986 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
987 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
991 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*/
992 WARN("Ignoring font %s\n", debugstr_a(file));
993 pFT_Done_Face(ft_face);
997 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
998 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
999 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file));
1000 pFT_Done_Face(ft_face);
1004 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
1005 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1006 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
1007 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
1008 "Skipping this font.\n", debugstr_a(file));
1009 pFT_Done_Face(ft_face);
1013 if(!ft_face->family_name || !ft_face->style_name) {
1014 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
1015 pFT_Done_Face(ft_face);
1020 family_name = ft_face->family_name;
1024 My_FT_Bitmap_Size *size = NULL;
1026 if(!FT_IS_SCALABLE(ft_face))
1027 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1029 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1030 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1031 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1033 localised_family = NULL;
1035 localised_family = get_familyname(ft_face);
1036 if(localised_family && !strcmpW(localised_family, english_family)) {
1037 HeapFree(GetProcessHeap(), 0, localised_family);
1038 localised_family = NULL;
1043 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1044 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1045 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1050 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1051 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1052 list_init(&family->faces);
1053 list_add_tail(&font_list, &family->entry);
1055 if(localised_family) {
1056 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1057 subst->from.name = strdupW(english_family);
1058 subst->from.charset = -1;
1059 subst->to.name = strdupW(localised_family);
1060 subst->to.charset = -1;
1061 add_font_subst(&font_subst_list, subst, 0);
1064 HeapFree(GetProcessHeap(), 0, localised_family);
1065 HeapFree(GetProcessHeap(), 0, english_family);
1067 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1068 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1069 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1071 internal_leading = 0;
1072 memset(&fs, 0, sizeof(fs));
1074 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1076 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1077 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1078 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1079 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1080 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1081 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1082 if(pOS2->version == 0) {
1085 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1088 fs.fsCsb[0] |= 1L << 31;
1091 #ifdef HAVE_FREETYPE_FTWINFNT_H
1092 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1094 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1095 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1096 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1097 memcpy(&fs, &csi.fs, sizeof(csi.fs));
1098 internal_leading = winfnt_header.internal_leading;
1102 face_elem_ptr = list_head(&family->faces);
1103 while(face_elem_ptr) {
1104 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1105 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1106 if(!strcmpW(face->StyleName, StyleW) &&
1107 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1108 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1109 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1110 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1113 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1114 HeapFree(GetProcessHeap(), 0, StyleW);
1115 pFT_Done_Face(ft_face);
1118 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1119 TRACE("Original font is newer so skipping this one\n");
1120 HeapFree(GetProcessHeap(), 0, StyleW);
1121 pFT_Done_Face(ft_face);
1124 TRACE("Replacing original with this one\n");
1125 list_remove(&face->entry);
1126 HeapFree(GetProcessHeap(), 0, face->file);
1127 HeapFree(GetProcessHeap(), 0, face->StyleName);
1128 HeapFree(GetProcessHeap(), 0, face);
1133 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1134 list_add_tail(&family->faces, &face->entry);
1135 face->StyleName = StyleW;
1136 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
1137 strcpy(face->file, file);
1138 face->face_index = face_index;
1139 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
1140 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
1141 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1142 face->family = family;
1143 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1144 memcpy(&face->fs, &fs, sizeof(face->fs));
1145 memset(&face->fs_links, 0, sizeof(face->fs_links));
1147 if(FT_IS_SCALABLE(ft_face)) {
1148 memset(&face->size, 0, sizeof(face->size));
1149 face->scalable = TRUE;
1151 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1152 size->height, size->width, size->size >> 6,
1153 size->x_ppem >> 6, size->y_ppem >> 6);
1154 face->size.height = size->height;
1155 face->size.width = size->width;
1156 face->size.size = size->size;
1157 face->size.x_ppem = size->x_ppem;
1158 face->size.y_ppem = size->y_ppem;
1159 face->size.internal_leading = internal_leading;
1160 face->scalable = FALSE;
1163 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1164 face->fs.fsCsb[0], face->fs.fsCsb[1],
1165 face->fs.fsUsb[0], face->fs.fsUsb[1],
1166 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1169 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1170 for(i = 0; i < ft_face->num_charmaps; i++) {
1171 switch(ft_face->charmaps[i]->encoding) {
1172 case FT_ENCODING_UNICODE:
1173 case FT_ENCODING_APPLE_ROMAN:
1174 face->fs.fsCsb[0] |= 1;
1176 case FT_ENCODING_MS_SYMBOL:
1177 face->fs.fsCsb[0] |= 1L << 31;
1185 if(face->fs.fsCsb[0] & ~(1L << 31))
1186 have_installed_roman_font = TRUE;
1187 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1189 num_faces = ft_face->num_faces;
1190 pFT_Done_Face(ft_face);
1191 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1192 debugstr_w(StyleW));
1193 } while(num_faces > ++face_index);
1197 static void DumpFontList(void)
1201 struct list *family_elem_ptr, *face_elem_ptr;
1203 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1204 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1205 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1206 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1207 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1208 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1210 TRACE(" %d", face->size.height);
1217 /***********************************************************
1218 * The replacement list is a way to map an entire font
1219 * family onto another family. For example adding
1221 * [HKCU\Software\Wine\Fonts\Replacements]
1222 * "Wingdings"="Winedings"
1224 * would enumerate the Winedings font both as Winedings and
1225 * Wingdings. However if a real Wingdings font is present the
1226 * replacement does not take place.
1229 static void LoadReplaceList(void)
1232 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1237 struct list *family_elem_ptr, *face_elem_ptr;
1238 WCHAR old_nameW[200];
1240 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1241 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1243 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1244 &valuelen, &datalen, NULL, NULL);
1246 valuelen++; /* returned value doesn't include room for '\0' */
1247 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1248 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1252 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1253 &dlen) == ERROR_SUCCESS) {
1254 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1255 /* "NewName"="Oldname" */
1256 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)/sizeof(WCHAR)))
1259 /* Find the old family and hence all of the font files
1261 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1262 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1263 if(!strcmpiW(family->FamilyName, old_nameW)) {
1264 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1265 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1266 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1267 debugstr_w(face->StyleName), value);
1268 /* Now add a new entry with the new family name */
1269 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1274 /* reset dlen and vlen */
1278 HeapFree(GetProcessHeap(), 0, data);
1279 HeapFree(GetProcessHeap(), 0, value);
1284 /*************************************************************
1287 static BOOL init_system_links(void)
1289 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1290 'W','i','n','d','o','w','s',' ','N','T','\\',
1291 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1292 'S','y','s','t','e','m','L','i','n','k',0};
1295 DWORD type, max_val, max_data, val_len, data_len, index;
1296 WCHAR *value, *data;
1297 WCHAR *entry, *next;
1298 SYSTEM_LINKS *font_link, *system_font_link;
1299 CHILD_FONT *child_font;
1300 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1301 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1302 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1308 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1310 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1311 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1312 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1313 val_len = max_val + 1;
1314 data_len = max_data;
1316 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1318 TRACE("%s:\n", debugstr_w(value));
1320 memset(&fs, 0, sizeof(fs));
1321 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1322 psub = get_font_subst(&font_subst_list, value, -1);
1323 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1324 list_init(&font_link->links);
1325 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1328 CHILD_FONT *child_font;
1330 TRACE("\t%s\n", debugstr_w(entry));
1332 next = entry + strlenW(entry) + 1;
1334 face_name = strchrW(entry, ',');
1338 while(isspaceW(*face_name))
1341 psub = get_font_subst(&font_subst_list, face_name, -1);
1343 face_name = psub->to.name;
1345 face = find_face_from_filename(entry, face_name);
1348 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1352 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1353 child_font->file_name = strdupA(face->file);
1354 child_font->index = face->face_index;
1355 child_font->font = NULL;
1356 fs.fsCsb[0] |= face->fs.fsCsb[0];
1357 fs.fsCsb[1] |= face->fs.fsCsb[1];
1358 TRACE("Adding file %s index %d\n", child_font->file_name, child_font->index);
1359 list_add_tail(&font_link->links, &child_font->entry);
1361 family = find_family_from_name(font_link->font_name);
1364 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1366 memcpy(&face->fs_links, &fs, sizeof(fs));
1369 list_add_tail(&system_links, &font_link->entry);
1370 val_len = max_val + 1;
1371 data_len = max_data;
1374 HeapFree(GetProcessHeap(), 0, value);
1375 HeapFree(GetProcessHeap(), 0, data);
1379 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1382 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1383 system_font_link->font_name = strdupW(System);
1384 list_init(&system_font_link->links);
1386 face = find_face_from_filename(tahoma_ttf, Tahoma);
1389 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1390 child_font->file_name = strdupA(face->file);
1391 child_font->index = face->face_index;
1392 child_font->font = NULL;
1393 TRACE("Found Tahoma in %s index %d\n", child_font->file_name, child_font->index);
1394 list_add_tail(&system_font_link->links, &child_font->entry);
1396 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1398 if(!strcmpiW(font_link->font_name, Tahoma))
1400 CHILD_FONT *font_link_entry;
1401 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1403 CHILD_FONT *new_child;
1404 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1405 new_child->file_name = strdupA(font_link_entry->file_name);
1406 new_child->index = font_link_entry->index;
1407 new_child->font = NULL;
1408 list_add_tail(&system_font_link->links, &new_child->entry);
1413 list_add_tail(&system_links, &system_font_link->entry);
1417 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1420 struct dirent *dent;
1421 char path[MAX_PATH];
1423 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1425 dir = opendir(dirname);
1427 WARN("Can't open directory %s\n", debugstr_a(dirname));
1430 while((dent = readdir(dir)) != NULL) {
1431 struct stat statbuf;
1433 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1436 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1438 sprintf(path, "%s/%s", dirname, dent->d_name);
1440 if(stat(path, &statbuf) == -1)
1442 WARN("Can't stat %s\n", debugstr_a(path));
1445 if(S_ISDIR(statbuf.st_mode))
1446 ReadFontDir(path, external_fonts);
1448 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1454 static void load_fontconfig_fonts(void)
1456 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1457 void *fc_handle = NULL;
1466 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1468 TRACE("Wine cannot find the fontconfig library (%s).\n",
1469 SONAME_LIBFONTCONFIG);
1472 #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;}
1473 LOAD_FUNCPTR(FcConfigGetCurrent);
1474 LOAD_FUNCPTR(FcFontList);
1475 LOAD_FUNCPTR(FcFontSetDestroy);
1476 LOAD_FUNCPTR(FcInit);
1477 LOAD_FUNCPTR(FcObjectSetAdd);
1478 LOAD_FUNCPTR(FcObjectSetCreate);
1479 LOAD_FUNCPTR(FcObjectSetDestroy);
1480 LOAD_FUNCPTR(FcPatternCreate);
1481 LOAD_FUNCPTR(FcPatternDestroy);
1482 LOAD_FUNCPTR(FcPatternGetBool);
1483 LOAD_FUNCPTR(FcPatternGetString);
1486 if(!pFcInit()) return;
1488 config = pFcConfigGetCurrent();
1489 pat = pFcPatternCreate();
1490 os = pFcObjectSetCreate();
1491 pFcObjectSetAdd(os, FC_FILE);
1492 pFcObjectSetAdd(os, FC_SCALABLE);
1493 fontset = pFcFontList(config, pat, os);
1494 if(!fontset) return;
1495 for(i = 0; i < fontset->nfont; i++) {
1498 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1500 TRACE("fontconfig: %s\n", file);
1502 /* We're just interested in OT/TT fonts for now, so this hack just
1503 picks up the scalable fonts without extensions .pf[ab] to save time
1504 loading every other font */
1506 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1508 TRACE("not scalable\n");
1512 len = strlen( file );
1513 if(len < 4) continue;
1514 ext = &file[ len - 3 ];
1515 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1516 AddFontFileToList(file, NULL, ADDFONT_EXTERNAL_FONT);
1518 pFcFontSetDestroy(fontset);
1519 pFcObjectSetDestroy(os);
1520 pFcPatternDestroy(pat);
1526 static BOOL load_font_from_data_dir(LPCWSTR file)
1529 const char *data_dir = wine_get_data_dir();
1531 if (!data_dir) data_dir = wine_get_build_dir();
1538 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1540 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1542 strcpy(unix_name, data_dir);
1543 strcat(unix_name, "/fonts/");
1545 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1547 ret = AddFontFileToList(unix_name, NULL, ADDFONT_FORCE_BITMAP);
1548 HeapFree(GetProcessHeap(), 0, unix_name);
1553 static void load_system_fonts(void)
1556 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1557 const WCHAR * const *value;
1559 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1562 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1563 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1564 strcatW(windowsdir, fontsW);
1565 for(value = SystemFontValues; *value; value++) {
1566 dlen = sizeof(data);
1567 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1571 sprintfW(pathW, fmtW, windowsdir, data);
1572 if((unixname = wine_get_unix_file_name(pathW))) {
1573 added = AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1574 HeapFree(GetProcessHeap(), 0, unixname);
1577 load_font_from_data_dir(data);
1584 /*************************************************************
1586 * This adds registry entries for any externally loaded fonts
1587 * (fonts from fontconfig or FontDirs). It also deletes entries
1588 * of no longer existing fonts.
1591 static void update_reg_entries(void)
1593 HKEY winkey = 0, externalkey = 0;
1596 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1599 struct list *family_elem_ptr, *face_elem_ptr;
1601 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1602 static const WCHAR spaceW[] = {' ', '\0'};
1605 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1606 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1607 ERR("Can't create Windows font reg key\n");
1610 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1611 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1612 ERR("Can't create external font reg key\n");
1616 /* Delete all external fonts added last time */
1618 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1619 &valuelen, &datalen, NULL, NULL);
1620 valuelen++; /* returned value doesn't include room for '\0' */
1621 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1622 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1624 dlen = datalen * sizeof(WCHAR);
1627 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1628 &dlen) == ERROR_SUCCESS) {
1630 RegDeleteValueW(winkey, valueW);
1631 /* reset dlen and vlen */
1635 HeapFree(GetProcessHeap(), 0, data);
1636 HeapFree(GetProcessHeap(), 0, valueW);
1638 /* Delete the old external fonts key */
1639 RegCloseKey(externalkey);
1641 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1643 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1644 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1645 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1646 ERR("Can't create external font reg key\n");
1650 /* enumerate the fonts and add external ones to the two keys */
1652 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1653 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1654 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1655 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1656 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1657 if(!face->external) continue;
1659 if(strcmpiW(face->StyleName, RegularW))
1660 len = len_fam + strlenW(face->StyleName) + 1;
1661 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1662 strcpyW(valueW, family->FamilyName);
1663 if(len != len_fam) {
1664 strcatW(valueW, spaceW);
1665 strcatW(valueW, face->StyleName);
1667 strcatW(valueW, TrueType);
1668 if((path = strrchr(face->file, '/')) == NULL)
1672 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1674 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1675 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1676 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1677 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1679 HeapFree(GetProcessHeap(), 0, file);
1680 HeapFree(GetProcessHeap(), 0, valueW);
1685 RegCloseKey(externalkey);
1687 RegCloseKey(winkey);
1692 /*************************************************************
1693 * WineEngAddFontResourceEx
1696 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1698 if (ft_handle) /* do it only if we have freetype up and running */
1703 FIXME("Ignoring flags %x\n", flags);
1705 if((unixname = wine_get_unix_file_name(file)))
1707 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1708 HeapFree(GetProcessHeap(), 0, unixname);
1714 /*************************************************************
1715 * WineEngRemoveFontResourceEx
1718 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1724 static const struct nls_update_font_list
1726 UINT ansi_cp, oem_cp;
1727 const char *oem, *fixed, *system;
1728 const char *courier, *serif, *small, *sserif;
1729 } nls_update_font_list[] =
1731 /* Latin 1 (United States) */
1732 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1733 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1735 /* Latin 1 (Multilingual) */
1736 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1737 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1739 /* Eastern Europe */
1740 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1741 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1744 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1745 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1748 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1749 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1752 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1753 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1756 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1757 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1760 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1761 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1764 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1765 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1768 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1769 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1772 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1773 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1776 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1777 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1779 /* Chinese Simplified */
1780 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1781 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1784 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1785 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1787 /* Chinese Traditional */
1788 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1789 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1793 inline static HKEY create_fonts_NT_registry_key(void)
1797 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1798 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1802 inline static HKEY create_fonts_9x_registry_key(void)
1806 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1807 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1811 inline static HKEY create_config_fonts_registry_key(void)
1815 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1816 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1820 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1822 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1823 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1824 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1825 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1828 static void update_font_info(void)
1830 char buf[40], cpbuf[40];
1833 UINT i, ansi_cp = 0, oem_cp = 0;
1835 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
1838 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1839 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1840 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1841 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1842 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
1845 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1847 if (!strcmp( buf, cpbuf )) /* already set correctly */
1852 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
1854 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
1856 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
1859 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1861 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1862 nls_update_font_list[i].oem_cp == oem_cp)
1866 hkey = create_config_fonts_registry_key();
1867 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1868 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1869 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1872 hkey = create_fonts_NT_registry_key();
1873 add_font_list(hkey, &nls_update_font_list[i]);
1876 hkey = create_fonts_9x_registry_key();
1877 add_font_list(hkey, &nls_update_font_list[i]);
1883 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
1886 /*************************************************************
1889 * Initialize FreeType library and create a list of available faces
1891 BOOL WineEngInit(void)
1893 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1894 static const WCHAR pathW[] = {'P','a','t','h',0};
1896 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1898 WCHAR windowsdir[MAX_PATH];
1901 const char *data_dir;
1905 /* update locale dependent font info in registry */
1908 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1911 "Wine cannot find the FreeType font library. To enable Wine to\n"
1912 "use TrueType fonts please install a version of FreeType greater than\n"
1913 "or equal to 2.0.5.\n"
1914 "http://www.freetype.org\n");
1918 #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;}
1920 LOAD_FUNCPTR(FT_Vector_Unit)
1921 LOAD_FUNCPTR(FT_Done_Face)
1922 LOAD_FUNCPTR(FT_Get_Char_Index)
1923 LOAD_FUNCPTR(FT_Get_Module)
1924 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1925 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1926 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1927 LOAD_FUNCPTR(FT_Init_FreeType)
1928 LOAD_FUNCPTR(FT_Load_Glyph)
1929 LOAD_FUNCPTR(FT_Matrix_Multiply)
1930 LOAD_FUNCPTR(FT_MulFix)
1931 LOAD_FUNCPTR(FT_New_Face)
1932 LOAD_FUNCPTR(FT_New_Memory_Face)
1933 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1934 LOAD_FUNCPTR(FT_Outline_Transform)
1935 LOAD_FUNCPTR(FT_Outline_Translate)
1936 LOAD_FUNCPTR(FT_Select_Charmap)
1937 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1938 LOAD_FUNCPTR(FT_Vector_Transform)
1941 /* Don't warn if this one is missing */
1942 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1943 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1944 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1945 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
1946 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
1947 #ifdef HAVE_FREETYPE_FTWINFNT_H
1948 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1950 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1951 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1952 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1953 <= 2.0.3 has FT_Sqrt64 */
1957 if(pFT_Init_FreeType(&library) != 0) {
1958 ERR("Can't init FreeType library\n");
1959 wine_dlclose(ft_handle, NULL, 0);
1963 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1964 if (pFT_Library_Version)
1966 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1968 if (FT_Version.major<=0)
1974 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1975 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1976 ((FT_Version.minor << 8) & 0x00ff00) |
1977 ((FT_Version.patch ) & 0x0000ff);
1979 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1980 ERR("Failed to create font mutex\n");
1983 WaitForSingleObject(font_mutex, INFINITE);
1985 /* load the system bitmap fonts */
1986 load_system_fonts();
1988 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1989 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1990 strcatW(windowsdir, fontsW);
1991 if((unixname = wine_get_unix_file_name(windowsdir)))
1993 ReadFontDir(unixname, FALSE);
1994 HeapFree(GetProcessHeap(), 0, unixname);
1997 /* load the system truetype fonts */
1998 data_dir = wine_get_data_dir();
1999 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2000 strcpy(unixname, data_dir);
2001 strcat(unixname, "/fonts/");
2002 ReadFontDir(unixname, FALSE);
2003 HeapFree(GetProcessHeap(), 0, unixname);
2006 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2007 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2008 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2010 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2011 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2012 &hkey) == ERROR_SUCCESS) {
2014 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2015 &valuelen, &datalen, NULL, NULL);
2017 valuelen++; /* returned value doesn't include room for '\0' */
2018 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2019 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2022 dlen = datalen * sizeof(WCHAR);
2024 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2025 &dlen) == ERROR_SUCCESS) {
2026 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2028 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2030 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
2031 HeapFree(GetProcessHeap(), 0, unixname);
2034 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2036 WCHAR pathW[MAX_PATH];
2037 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2040 sprintfW(pathW, fmtW, windowsdir, data);
2041 if((unixname = wine_get_unix_file_name(pathW)))
2043 added = AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
2044 HeapFree(GetProcessHeap(), 0, unixname);
2047 load_font_from_data_dir(data);
2049 /* reset dlen and vlen */
2054 HeapFree(GetProcessHeap(), 0, data);
2055 HeapFree(GetProcessHeap(), 0, valueW);
2059 load_fontconfig_fonts();
2061 /* then look in any directories that we've specified in the config file */
2062 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2063 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2069 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2071 len += sizeof(WCHAR);
2072 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2073 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2075 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2076 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2077 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2078 TRACE( "got font path %s\n", debugstr_a(valueA) );
2082 LPSTR next = strchr( ptr, ':' );
2083 if (next) *next++ = 0;
2084 ReadFontDir( ptr, TRUE );
2087 HeapFree( GetProcessHeap(), 0, valueA );
2089 HeapFree( GetProcessHeap(), 0, valueW );
2098 update_reg_entries();
2100 init_system_links();
2102 ReleaseMutex(font_mutex);
2106 "Wine cannot find certain functions that it needs inside the FreeType\n"
2107 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2108 "FreeType to at least version 2.0.5.\n"
2109 "http://www.freetype.org\n");
2110 wine_dlclose(ft_handle, NULL, 0);
2116 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2119 TT_HoriHeader *pHori;
2123 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2124 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2126 if(height == 0) height = 16;
2128 /* Calc. height of EM square:
2130 * For +ve lfHeight we have
2131 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2132 * Re-arranging gives:
2133 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2135 * For -ve lfHeight we have
2137 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2138 * with il = winAscent + winDescent - units_per_em]
2143 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2144 ppem = ft_face->units_per_EM * height /
2145 (pHori->Ascender - pHori->Descender);
2147 ppem = ft_face->units_per_EM * height /
2148 (pOS2->usWinAscent + pOS2->usWinDescent);
2156 static struct font_mapping *map_font( const char *name )
2158 #ifndef __APPLE__ /* Mac OS fonts use resource forks, we can't simply mmap them */
2159 struct font_mapping *mapping;
2163 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2164 if (fstat( fd, &st ) == -1) goto error;
2166 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2168 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2170 mapping->refcount++;
2175 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2178 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2181 if (mapping->data == MAP_FAILED)
2183 HeapFree( GetProcessHeap(), 0, mapping );
2186 mapping->refcount = 1;
2187 mapping->dev = st.st_dev;
2188 mapping->ino = st.st_ino;
2189 mapping->size = st.st_size;
2190 list_add_tail( &mappings_list, &mapping->entry );
2199 static void unmap_font( struct font_mapping *mapping )
2201 if (!--mapping->refcount)
2203 list_remove( &mapping->entry );
2204 munmap( mapping->data, mapping->size );
2205 HeapFree( GetProcessHeap(), 0, mapping );
2209 static LONG load_VDMX(GdiFont*, LONG);
2211 static FT_Face OpenFontFile(GdiFont *font, char *file, FT_Long face_index, LONG width, LONG height)
2216 TRACE("%s, %ld, %d x %d\n", debugstr_a(file), face_index, width, height);
2218 if ((font->mapping = map_font( file )))
2219 err = pFT_New_Memory_Face(library, font->mapping->data, font->mapping->size, face_index, &ft_face);
2221 err = pFT_New_Face(library, file, face_index, &ft_face);
2224 ERR("FT_New_Face rets %d\n", err);
2228 /* set it here, as load_VDMX needs it */
2229 font->ft_face = ft_face;
2231 if(FT_IS_SCALABLE(ft_face)) {
2232 /* load the VDMX table if we have one */
2233 font->ppem = load_VDMX(font, height);
2235 font->ppem = calc_ppem_for_height(ft_face, height);
2237 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2238 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2240 font->ppem = height;
2241 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2242 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2248 static int get_nearest_charset(Face *face, int *cp)
2250 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2251 a single face with the requested charset. The idea is to check if
2252 the selected font supports the current ANSI codepage, if it does
2253 return the corresponding charset, else return the first charset */
2256 int acp = GetACP(), i;
2260 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2261 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2262 return csi.ciCharset;
2264 for(i = 0; i < 32; i++) {
2266 if(face->fs.fsCsb[0] & fs0) {
2267 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2269 return csi.ciCharset;
2272 FIXME("TCI failing on %x\n", fs0);
2276 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2277 face->fs.fsCsb[0], face->file);
2279 return DEFAULT_CHARSET;
2282 static GdiFont *alloc_font(void)
2284 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2285 ret->gmsize = INIT_GM_SIZE;
2286 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2287 ret->gmsize * sizeof(*ret->gm));
2289 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2290 ret->total_kern_pairs = (DWORD)-1;
2291 ret->kern_pairs = NULL;
2292 list_init(&ret->hfontlist);
2293 list_init(&ret->child_fonts);
2297 static void free_font(GdiFont *font)
2299 struct list *cursor, *cursor2;
2301 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2303 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2304 struct list *first_hfont;
2305 HFONTLIST *hfontlist;
2306 list_remove(cursor);
2309 first_hfont = list_head(&child->font->hfontlist);
2310 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2311 DeleteObject(hfontlist->hfont);
2312 HeapFree(GetProcessHeap(), 0, hfontlist);
2313 free_font(child->font);
2315 HeapFree(GetProcessHeap(), 0, child->file_name);
2316 HeapFree(GetProcessHeap(), 0, child);
2319 if (font->ft_face) pFT_Done_Face(font->ft_face);
2320 if (font->mapping) unmap_font( font->mapping );
2321 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2322 HeapFree(GetProcessHeap(), 0, font->potm);
2323 HeapFree(GetProcessHeap(), 0, font->name);
2324 HeapFree(GetProcessHeap(), 0, font->gm);
2325 HeapFree(GetProcessHeap(), 0, font);
2329 /*************************************************************
2332 * load the vdmx entry for the specified height
2335 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2336 ( ( (FT_ULong)_x4 << 24 ) | \
2337 ( (FT_ULong)_x3 << 16 ) | \
2338 ( (FT_ULong)_x2 << 8 ) | \
2341 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2356 static LONG load_VDMX(GdiFont *font, LONG height)
2360 BYTE devXRatio, devYRatio;
2361 USHORT numRecs, numRatios;
2362 DWORD result, offset = -1;
2366 /* For documentation on VDMX records, see
2367 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2370 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2372 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2375 /* FIXME: need the real device aspect ratio */
2379 numRecs = GET_BE_WORD(hdr[1]);
2380 numRatios = GET_BE_WORD(hdr[2]);
2382 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2383 for(i = 0; i < numRatios; i++) {
2386 offset = (3 * 2) + (i * sizeof(Ratios));
2387 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2390 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2392 if((ratio.xRatio == 0 &&
2393 ratio.yStartRatio == 0 &&
2394 ratio.yEndRatio == 0) ||
2395 (devXRatio == ratio.xRatio &&
2396 devYRatio >= ratio.yStartRatio &&
2397 devYRatio <= ratio.yEndRatio))
2399 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2400 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2401 offset = GET_BE_WORD(tmp);
2407 FIXME("No suitable ratio found\n");
2411 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2413 BYTE startsz, endsz;
2416 recs = GET_BE_WORD(group.recs);
2417 startsz = group.startsz;
2418 endsz = group.endsz;
2420 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2422 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2423 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2424 if(result == GDI_ERROR) {
2425 FIXME("Failed to retrieve vTable\n");
2430 for(i = 0; i < recs; i++) {
2431 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2432 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2433 ppem = GET_BE_WORD(vTable[i * 3]);
2435 if(yMax + -yMin == height) {
2438 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2441 if(yMax + -yMin > height) {
2444 goto end; /* failed */
2446 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2447 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2448 ppem = GET_BE_WORD(vTable[i * 3]);
2449 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2455 TRACE("ppem not found for height %d\n", height);
2459 if(ppem < startsz || ppem > endsz)
2462 for(i = 0; i < recs; i++) {
2464 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2466 if(yPelHeight > ppem)
2469 if(yPelHeight == ppem) {
2470 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2471 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2472 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2478 HeapFree(GetProcessHeap(), 0, vTable);
2484 static BOOL fontcmp(GdiFont *font, FONT_DESC *fd)
2486 if(font->font_desc.hash != fd->hash) return TRUE;
2487 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2488 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2489 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2490 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2493 static void calc_hash(FONT_DESC *pfd)
2495 DWORD hash = 0, *ptr, two_chars;
2499 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2501 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2503 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2505 pwc = (WCHAR *)&two_chars;
2507 *pwc = toupperW(*pwc);
2509 *pwc = toupperW(*pwc);
2513 hash ^= !pfd->can_use_bitmap;
2518 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2523 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2525 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2526 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2527 fd.can_use_bitmap = can_use_bitmap;
2530 /* try the in-use list */
2531 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2532 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2533 if(!fontcmp(ret, &fd)) {
2534 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2535 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2536 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2537 if(hflist->hfont == hfont)
2540 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2541 hflist->hfont = hfont;
2542 list_add_head(&ret->hfontlist, &hflist->entry);
2547 /* then the unused list */
2548 font_elem_ptr = list_head(&unused_gdi_font_list);
2549 while(font_elem_ptr) {
2550 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2551 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2552 if(!fontcmp(ret, &fd)) {
2553 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2554 assert(list_empty(&ret->hfontlist));
2555 TRACE("Found %p in unused list\n", ret);
2556 list_remove(&ret->entry);
2557 list_add_head(&gdi_font_list, &ret->entry);
2558 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2559 hflist->hfont = hfont;
2560 list_add_head(&ret->hfontlist, &hflist->entry);
2568 /*************************************************************
2569 * create_child_font_list
2571 static BOOL create_child_font_list(GdiFont *font)
2574 SYSTEM_LINKS *font_link;
2575 CHILD_FONT *font_link_entry, *new_child;
2577 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2579 if(!strcmpW(font_link->font_name, font->name))
2581 TRACE("found entry in system list\n");
2582 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2584 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2585 new_child->file_name = strdupA(font_link_entry->file_name);
2586 new_child->index = font_link_entry->index;
2587 new_child->font = NULL;
2588 list_add_tail(&font->child_fonts, &new_child->entry);
2589 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
2599 /*************************************************************
2600 * WineEngCreateFontInstance
2603 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
2606 Face *face, *best, *best_bitmap;
2607 Family *family, *last_resort_family;
2608 struct list *family_elem_ptr, *face_elem_ptr;
2609 INT height, width = 0;
2610 unsigned int score = 0, new_score;
2611 signed int diff = 0, newdiff;
2612 BOOL bd, it, can_use_bitmap;
2617 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2619 struct list *first_hfont = list_head(&ret->hfontlist);
2620 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2621 if(hflist->hfont == hfont)
2625 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2626 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2628 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2629 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2630 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2633 /* check the cache first */
2634 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2635 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2639 TRACE("not in cache\n");
2640 if(list_empty(&font_list)) /* No fonts installed */
2642 TRACE("No fonts installed\n");
2645 if(!have_installed_roman_font)
2647 TRACE("No roman font installed\n");
2653 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2654 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2655 ret->font_desc.can_use_bitmap = can_use_bitmap;
2656 calc_hash(&ret->font_desc);
2657 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2658 hflist->hfont = hfont;
2659 list_add_head(&ret->hfontlist, &hflist->entry);
2662 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2663 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2664 original value lfCharSet. Note this is a special case for
2665 Symbol and doesn't happen at least for "Wingdings*" */
2667 if(!strcmpiW(lf.lfFaceName, SymbolW))
2668 lf.lfCharSet = SYMBOL_CHARSET;
2670 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2671 switch(lf.lfCharSet) {
2672 case DEFAULT_CHARSET:
2673 csi.fs.fsCsb[0] = 0;
2676 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2677 csi.fs.fsCsb[0] = 0;
2683 if(lf.lfFaceName[0] != '\0') {
2685 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2688 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2689 debugstr_w(psub->to.name));
2690 strcpyW(lf.lfFaceName, psub->to.name);
2693 /* We want a match on name and charset or just name if
2694 charset was DEFAULT_CHARSET. If the latter then
2695 we fixup the returned charset later in get_nearest_charset
2696 where we'll either use the charset of the current ansi codepage
2697 or if that's unavailable the first charset that the font supports.
2699 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2700 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2701 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2702 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2703 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2704 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2705 if(face->scalable || can_use_bitmap)
2712 /* If requested charset was DEFAULT_CHARSET then try using charset
2713 corresponding to the current ansi codepage */
2714 if(!csi.fs.fsCsb[0]) {
2716 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
2717 FIXME("TCI failed on codepage %d\n", acp);
2718 csi.fs.fsCsb[0] = 0;
2720 lf.lfCharSet = csi.ciCharset;
2723 /* Face families are in the top 4 bits of lfPitchAndFamily,
2724 so mask with 0xF0 before testing */
2726 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2727 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2728 strcpyW(lf.lfFaceName, defFixed);
2729 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2730 strcpyW(lf.lfFaceName, defSerif);
2731 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2732 strcpyW(lf.lfFaceName, defSans);
2734 strcpyW(lf.lfFaceName, defSans);
2735 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2736 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2737 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2738 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2739 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2740 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2741 if(face->scalable || can_use_bitmap)
2747 last_resort_family = NULL;
2748 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2749 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2750 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2751 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2752 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2755 if(can_use_bitmap && !last_resort_family)
2756 last_resort_family = family;
2761 if(last_resort_family) {
2762 family = last_resort_family;
2763 csi.fs.fsCsb[0] = 0;
2767 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2768 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2769 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2770 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2771 if(face->scalable) {
2772 csi.fs.fsCsb[0] = 0;
2773 WARN("just using first face for now\n");
2776 if(can_use_bitmap && !last_resort_family)
2777 last_resort_family = family;
2780 if(!last_resort_family) {
2781 FIXME("can't find a single appropriate font - bailing\n");
2786 WARN("could only find a bitmap font - this will probably look awful!\n");
2787 family = last_resort_family;
2788 csi.fs.fsCsb[0] = 0;
2791 it = lf.lfItalic ? 1 : 0;
2792 bd = lf.lfWeight > 550 ? 1 : 0;
2794 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2795 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2797 face = best = best_bitmap = NULL;
2798 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2800 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2802 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
2803 if(!best || new_score <= score)
2805 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
2806 face->Italic, face->Bold, it, bd);
2809 if(best->scalable && score == 0) break;
2813 newdiff = height - (signed int)(best->size.height);
2815 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
2816 if(!best_bitmap || new_score < score ||
2817 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
2819 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
2822 if(score == 0 && diff == 0) break;
2829 face = best->scalable ? best : best_bitmap;
2830 ret->fake_italic = (it && !face->Italic);
2831 ret->fake_bold = (bd && !face->Bold);
2833 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2835 if(csi.fs.fsCsb[0]) {
2836 ret->charset = lf.lfCharSet;
2837 ret->codepage = csi.ciACP;
2840 ret->charset = get_nearest_charset(face, &ret->codepage);
2842 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2843 debugstr_w(face->StyleName), face->file, face->face_index);
2845 if(!face->scalable) {
2846 width = face->size.x_ppem >> 6;
2847 height = face->size.y_ppem >> 6;
2849 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2857 if (ret->charset == SYMBOL_CHARSET &&
2858 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2861 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2865 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2868 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2869 ret->name = strdupW(family->FamilyName);
2870 ret->underline = lf.lfUnderline ? 0xff : 0;
2871 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2872 create_child_font_list(ret);
2874 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2876 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
2877 list_add_head(&gdi_font_list, &ret->entry);
2881 static void dump_gdi_font_list(void)
2884 struct list *elem_ptr;
2886 TRACE("---------- gdiFont Cache ----------\n");
2887 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2888 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2889 TRACE("gdiFont=%p %s %d\n",
2890 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2893 TRACE("---------- Unused gdiFont Cache ----------\n");
2894 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2895 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2896 TRACE("gdiFont=%p %s %d\n",
2897 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2901 /*************************************************************
2902 * WineEngDestroyFontInstance
2904 * free the gdiFont associated with this handle
2907 BOOL WineEngDestroyFontInstance(HFONT handle)
2912 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2915 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
2917 struct list *first_hfont = list_head(&gdiFont->hfontlist);
2918 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2919 if(hflist->hfont == handle)
2921 TRACE("removing child font %p from child list\n", gdiFont);
2922 list_remove(&gdiFont->entry);
2927 TRACE("destroying hfont=%p\n", handle);
2929 dump_gdi_font_list();
2931 font_elem_ptr = list_head(&gdi_font_list);
2932 while(font_elem_ptr) {
2933 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2934 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
2936 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
2937 while(hfontlist_elem_ptr) {
2938 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2939 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
2940 if(hflist->hfont == handle) {
2941 list_remove(&hflist->entry);
2942 HeapFree(GetProcessHeap(), 0, hflist);
2946 if(list_empty(&gdiFont->hfontlist)) {
2947 TRACE("Moving to Unused list\n");
2948 list_remove(&gdiFont->entry);
2949 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
2954 font_elem_ptr = list_head(&unused_gdi_font_list);
2955 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
2956 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2957 while(font_elem_ptr) {
2958 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2959 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2960 TRACE("freeing %p\n", gdiFont);
2961 list_remove(&gdiFont->entry);
2967 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2968 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
2970 OUTLINETEXTMETRICW *potm = NULL;
2972 TEXTMETRICW tm, *ptm;
2973 GdiFont *font = alloc_font();
2976 if(face->scalable) {
2980 height = face->size.y_ppem >> 6;
2981 width = face->size.x_ppem >> 6;
2984 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
2990 font->name = strdupW(face->family->FamilyName);
2992 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
2994 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
2996 potm = HeapAlloc(GetProcessHeap(), 0, size);
2997 WineEngGetOutlineTextMetrics(font, size, potm);
2998 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
3000 WineEngGetTextMetrics(font, &tm);
3004 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
3005 pntm->ntmTm.tmAscent = ptm->tmAscent;
3006 pntm->ntmTm.tmDescent = ptm->tmDescent;
3007 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
3008 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
3009 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
3010 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
3011 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
3012 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
3013 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
3014 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
3015 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
3016 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
3017 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
3018 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
3019 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
3020 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
3021 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
3022 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
3023 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
3024 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
3025 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3026 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3027 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3029 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
3030 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
3031 *ptype |= RASTER_FONTTYPE;
3033 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
3034 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
3035 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
3037 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3038 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3039 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
3042 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
3044 lstrcpynW(pelf->elfLogFont.lfFaceName,
3045 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
3047 lstrcpynW(pelf->elfFullName,
3048 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
3050 lstrcpynW(pelf->elfStyle,
3051 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
3054 HeapFree(GetProcessHeap(), 0, potm);
3056 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3058 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3059 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
3060 pelf->elfStyle[0] = '\0';
3063 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3068 /*************************************************************
3072 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3076 struct list *family_elem_ptr, *face_elem_ptr;
3078 NEWTEXTMETRICEXW ntm;
3079 DWORD type, ret = 1;
3085 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3087 if(plf->lfFaceName[0]) {
3089 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3092 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3093 debugstr_w(psub->to.name));
3094 memcpy(&lf, plf, sizeof(lf));
3095 strcpyW(lf.lfFaceName, psub->to.name);
3099 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3100 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3101 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3102 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3103 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3104 GetEnumStructs(face, &elf, &ntm, &type);
3105 for(i = 0; i < 32; i++) {
3106 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3107 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3108 strcpyW(elf.elfScript, OEM_DOSW);
3109 i = 32; /* break out of loop */
3110 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3113 fs.fsCsb[0] = 1L << i;
3115 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3117 csi.ciCharset = DEFAULT_CHARSET;
3118 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3119 if(csi.ciCharset != DEFAULT_CHARSET) {
3120 elf.elfLogFont.lfCharSet =
3121 ntm.ntmTm.tmCharSet = csi.ciCharset;
3123 strcpyW(elf.elfScript, ElfScriptsW[i]);
3125 FIXME("Unknown elfscript for bit %d\n", i);
3128 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3129 debugstr_w(elf.elfLogFont.lfFaceName),
3130 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3131 csi.ciCharset, type, debugstr_w(elf.elfScript),
3132 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3133 ntm.ntmTm.ntmFlags);
3134 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3141 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3142 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3143 face_elem_ptr = list_head(&family->faces);
3144 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3145 GetEnumStructs(face, &elf, &ntm, &type);
3146 for(i = 0; i < 32; i++) {
3147 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3148 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3149 strcpyW(elf.elfScript, OEM_DOSW);
3150 i = 32; /* break out of loop */
3151 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3154 fs.fsCsb[0] = 1L << i;
3156 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3158 csi.ciCharset = DEFAULT_CHARSET;
3159 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3160 if(csi.ciCharset != DEFAULT_CHARSET) {
3161 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3164 strcpyW(elf.elfScript, ElfScriptsW[i]);
3166 FIXME("Unknown elfscript for bit %d\n", i);
3169 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3170 debugstr_w(elf.elfLogFont.lfFaceName),
3171 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3172 csi.ciCharset, type, debugstr_w(elf.elfScript),
3173 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3174 ntm.ntmTm.ntmFlags);
3175 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3184 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3186 pt->x.value = vec->x >> 6;
3187 pt->x.fract = (vec->x & 0x3f) << 10;
3188 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3189 pt->y.value = vec->y >> 6;
3190 pt->y.fract = (vec->y & 0x3f) << 10;
3191 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3195 /***************************************************
3196 * According to the MSDN documentation on WideCharToMultiByte,
3197 * certain codepages cannot set the default_used parameter.
3198 * This returns TRUE if the codepage can set that parameter, false else
3199 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3201 static BOOL codepage_sets_default_used(UINT codepage)
3214 static FT_UInt get_glyph_index(GdiFont *font, UINT glyph)
3216 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
3217 WCHAR wc = (WCHAR)glyph;
3219 BOOL *default_used_pointer;
3222 default_used_pointer = NULL;
3223 default_used = FALSE;
3224 if (codepage_sets_default_used(font->codepage))
3225 default_used_pointer = &default_used;
3226 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
3229 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
3230 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
3234 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
3235 glyph = glyph + 0xf000;
3236 return pFT_Get_Char_Index(font->ft_face, glyph);
3239 /*************************************************************
3240 * WineEngGetGlyphIndices
3242 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3244 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
3245 LPWORD pgi, DWORD flags)
3248 WCHAR default_char = 0;
3251 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
3253 for(i = 0; i < count; i++)
3255 pgi[i] = get_glyph_index(font, lpstr[i]);
3260 WineEngGetTextMetrics(font, &textm);
3261 default_char = textm.tmDefaultChar;
3263 pgi[i] = default_char;
3269 /*************************************************************
3270 * WineEngGetGlyphOutline
3272 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3273 * except that the first parameter is the HWINEENGFONT of the font in
3274 * question rather than an HDC.
3277 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
3278 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3281 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3282 FT_Face ft_face = font->ft_face;
3283 FT_UInt glyph_index;
3284 DWORD width, height, pitch, needed = 0;
3285 FT_Bitmap ft_bitmap;
3287 INT left, right, top = 0, bottom = 0;
3289 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3290 float widthRatio = 1.0;
3291 FT_Matrix transMat = identityMat;
3292 BOOL needsTransform = FALSE;
3295 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
3296 buflen, buf, lpmat);
3298 if(format & GGO_GLYPH_INDEX) {
3299 glyph_index = glyph;
3300 format &= ~GGO_GLYPH_INDEX;
3302 glyph_index = get_glyph_index(font, glyph);
3304 if(glyph_index >= font->gmsize) {
3305 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
3306 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
3307 font->gmsize * sizeof(*font->gm));
3309 if(format == GGO_METRICS && font->gm[glyph_index].init) {
3310 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
3311 return 1; /* FIXME */
3315 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
3316 load_flags |= FT_LOAD_NO_BITMAP;
3318 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
3321 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
3325 /* Scaling factor */
3326 if (font->aveWidth && font->potm) {
3327 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
3330 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3331 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3333 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3334 font->gm[glyph_index].lsb = left >> 6;
3335 font->gm[glyph_index].bbx = (right - left) >> 6;
3337 /* Scaling transform */
3338 if(font->aveWidth) {
3340 scaleMat.xx = FT_FixedFromFloat(widthRatio);
3343 scaleMat.yy = (1 << 16);
3345 pFT_Matrix_Multiply(&scaleMat, &transMat);
3346 needsTransform = TRUE;
3349 /* Slant transform */
3350 if (font->fake_italic) {
3353 slantMat.xx = (1 << 16);
3354 slantMat.xy = ((1 << 16) >> 2);
3356 slantMat.yy = (1 << 16);
3357 pFT_Matrix_Multiply(&slantMat, &transMat);
3358 needsTransform = TRUE;
3361 /* Rotation transform */
3362 if(font->orientation) {
3363 FT_Matrix rotationMat;
3365 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3366 pFT_Vector_Unit(&vecAngle, angle);
3367 rotationMat.xx = vecAngle.x;
3368 rotationMat.xy = -vecAngle.y;
3369 rotationMat.yx = -rotationMat.xy;
3370 rotationMat.yy = rotationMat.xx;
3372 pFT_Matrix_Multiply(&rotationMat, &transMat);
3373 needsTransform = TRUE;
3376 /* Extra transformation specified by caller */
3379 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3380 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3381 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3382 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3383 pFT_Matrix_Multiply(&extraMat, &transMat);
3384 needsTransform = TRUE;
3387 if(!needsTransform) {
3388 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3389 bottom = (ft_face->glyph->metrics.horiBearingY -
3390 ft_face->glyph->metrics.height) & -64;
3391 lpgm->gmCellIncX = font->gm[glyph_index].adv;
3392 lpgm->gmCellIncY = 0;
3396 for(xc = 0; xc < 2; xc++) {
3397 for(yc = 0; yc < 2; yc++) {
3398 vec.x = (ft_face->glyph->metrics.horiBearingX +
3399 xc * ft_face->glyph->metrics.width);
3400 vec.y = ft_face->glyph->metrics.horiBearingY -
3401 yc * ft_face->glyph->metrics.height;
3402 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3403 pFT_Vector_Transform(&vec, &transMat);
3404 if(xc == 0 && yc == 0) {
3405 left = right = vec.x;
3406 top = bottom = vec.y;
3408 if(vec.x < left) left = vec.x;
3409 else if(vec.x > right) right = vec.x;
3410 if(vec.y < bottom) bottom = vec.y;
3411 else if(vec.y > top) top = vec.y;
3416 right = (right + 63) & -64;
3417 bottom = bottom & -64;
3418 top = (top + 63) & -64;
3420 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3421 vec.x = ft_face->glyph->metrics.horiAdvance;
3423 pFT_Vector_Transform(&vec, &transMat);
3424 lpgm->gmCellIncX = (vec.x+63) >> 6;
3425 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3427 lpgm->gmBlackBoxX = (right - left) >> 6;
3428 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3429 lpgm->gmptGlyphOrigin.x = left >> 6;
3430 lpgm->gmptGlyphOrigin.y = top >> 6;
3432 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
3433 font->gm[glyph_index].init = TRUE;
3435 if(format == GGO_METRICS)
3436 return 1; /* FIXME */
3438 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
3439 TRACE("loaded a bitmap\n");
3445 width = lpgm->gmBlackBoxX;
3446 height = lpgm->gmBlackBoxY;
3447 pitch = ((width + 31) >> 5) << 2;
3448 needed = pitch * height;
3450 if(!buf || !buflen) break;
3452 switch(ft_face->glyph->format) {
3453 case ft_glyph_format_bitmap:
3455 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3456 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3457 INT h = ft_face->glyph->bitmap.rows;
3459 memcpy(dst, src, w);
3460 src += ft_face->glyph->bitmap.pitch;
3466 case ft_glyph_format_outline:
3467 ft_bitmap.width = width;
3468 ft_bitmap.rows = height;
3469 ft_bitmap.pitch = pitch;
3470 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3471 ft_bitmap.buffer = buf;
3473 if(needsTransform) {
3474 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3477 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3479 /* Note: FreeType will only set 'black' bits for us. */
3480 memset(buf, 0, needed);
3481 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3485 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3490 case GGO_GRAY2_BITMAP:
3491 case GGO_GRAY4_BITMAP:
3492 case GGO_GRAY8_BITMAP:
3493 case WINE_GGO_GRAY16_BITMAP:
3495 unsigned int mult, row, col;
3498 width = lpgm->gmBlackBoxX;
3499 height = lpgm->gmBlackBoxY;
3500 pitch = (width + 3) / 4 * 4;
3501 needed = pitch * height;
3503 if(!buf || !buflen) break;
3504 ft_bitmap.width = width;
3505 ft_bitmap.rows = height;
3506 ft_bitmap.pitch = pitch;
3507 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3508 ft_bitmap.buffer = buf;
3510 if(needsTransform) {
3511 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3514 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3516 memset(ft_bitmap.buffer, 0, buflen);
3518 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3520 if(format == GGO_GRAY2_BITMAP)
3522 else if(format == GGO_GRAY4_BITMAP)
3524 else if(format == GGO_GRAY8_BITMAP)
3526 else if(format == WINE_GGO_GRAY16_BITMAP)
3534 for(row = 0; row < height; row++) {
3536 for(col = 0; col < width; col++, ptr++) {
3537 *ptr = (((int)*ptr) * mult + 128) / 256;
3546 int contour, point = 0, first_pt;
3547 FT_Outline *outline = &ft_face->glyph->outline;
3548 TTPOLYGONHEADER *pph;
3550 DWORD pph_start, cpfx, type;
3552 if(buflen == 0) buf = NULL;
3554 if (needsTransform && buf) {
3555 pFT_Outline_Transform(outline, &transMat);
3558 for(contour = 0; contour < outline->n_contours; contour++) {
3560 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3563 pph->dwType = TT_POLYGON_TYPE;
3564 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3566 needed += sizeof(*pph);
3568 while(point <= outline->contours[contour]) {
3569 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3570 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3571 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3575 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3578 } while(point <= outline->contours[contour] &&
3579 (outline->tags[point] & FT_Curve_Tag_On) ==
3580 (outline->tags[point-1] & FT_Curve_Tag_On));
3581 /* At the end of a contour Windows adds the start point, but
3583 if(point > outline->contours[contour] &&
3584 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3586 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3588 } else if(point <= outline->contours[contour] &&
3589 outline->tags[point] & FT_Curve_Tag_On) {
3590 /* add closing pt for bezier */
3592 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3600 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3603 pph->cb = needed - pph_start;
3609 /* Convert the quadratic Beziers to cubic Beziers.
3610 The parametric eqn for a cubic Bezier is, from PLRM:
3611 r(t) = at^3 + bt^2 + ct + r0
3612 with the control points:
3617 A quadratic Beizer has the form:
3618 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3620 So equating powers of t leads to:
3621 r1 = 2/3 p1 + 1/3 p0
3622 r2 = 2/3 p1 + 1/3 p2
3623 and of course r0 = p0, r3 = p2
3626 int contour, point = 0, first_pt;
3627 FT_Outline *outline = &ft_face->glyph->outline;
3628 TTPOLYGONHEADER *pph;
3630 DWORD pph_start, cpfx, type;
3631 FT_Vector cubic_control[4];
3632 if(buflen == 0) buf = NULL;
3634 if (needsTransform && buf) {
3635 pFT_Outline_Transform(outline, &transMat);
3638 for(contour = 0; contour < outline->n_contours; contour++) {
3640 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3643 pph->dwType = TT_POLYGON_TYPE;
3644 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3646 needed += sizeof(*pph);
3648 while(point <= outline->contours[contour]) {
3649 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3650 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3651 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3654 if(type == TT_PRIM_LINE) {
3656 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3660 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3663 /* FIXME: Possible optimization in endpoint calculation
3664 if there are two consecutive curves */
3665 cubic_control[0] = outline->points[point-1];
3666 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3667 cubic_control[0].x += outline->points[point].x + 1;
3668 cubic_control[0].y += outline->points[point].y + 1;
3669 cubic_control[0].x >>= 1;
3670 cubic_control[0].y >>= 1;
3672 if(point+1 > outline->contours[contour])
3673 cubic_control[3] = outline->points[first_pt];
3675 cubic_control[3] = outline->points[point+1];
3676 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3677 cubic_control[3].x += outline->points[point].x + 1;
3678 cubic_control[3].y += outline->points[point].y + 1;
3679 cubic_control[3].x >>= 1;
3680 cubic_control[3].y >>= 1;
3683 /* r1 = 1/3 p0 + 2/3 p1
3684 r2 = 1/3 p2 + 2/3 p1 */
3685 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3686 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3687 cubic_control[2] = cubic_control[1];
3688 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3689 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3690 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3691 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3693 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3694 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3695 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3700 } while(point <= outline->contours[contour] &&
3701 (outline->tags[point] & FT_Curve_Tag_On) ==
3702 (outline->tags[point-1] & FT_Curve_Tag_On));
3703 /* At the end of a contour Windows adds the start point,
3704 but only for Beziers and we've already done that.
3706 if(point <= outline->contours[contour] &&
3707 outline->tags[point] & FT_Curve_Tag_On) {
3708 /* This is the closing pt of a bezier, but we've already
3709 added it, so just inc point and carry on */
3716 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3719 pph->cb = needed - pph_start;
3725 FIXME("Unsupported format %d\n", format);
3731 static BOOL get_bitmap_text_metrics(GdiFont *font)
3733 FT_Face ft_face = font->ft_face;
3734 #ifdef HAVE_FREETYPE_FTWINFNT_H
3735 FT_WinFNT_HeaderRec winfnt_header;
3737 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3738 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3739 font->potm->otmSize = size;
3741 #define TM font->potm->otmTextMetrics
3742 #ifdef HAVE_FREETYPE_FTWINFNT_H
3743 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3745 TM.tmHeight = winfnt_header.pixel_height;
3746 TM.tmAscent = winfnt_header.ascent;
3747 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3748 TM.tmInternalLeading = winfnt_header.internal_leading;
3749 TM.tmExternalLeading = winfnt_header.external_leading;
3750 TM.tmAveCharWidth = winfnt_header.avg_width;
3751 TM.tmMaxCharWidth = winfnt_header.max_width;
3752 TM.tmWeight = winfnt_header.weight;
3754 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3755 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3756 TM.tmFirstChar = winfnt_header.first_char;
3757 TM.tmLastChar = winfnt_header.last_char;
3758 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3759 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3760 TM.tmItalic = winfnt_header.italic;
3761 TM.tmUnderlined = font->underline;
3762 TM.tmStruckOut = font->strikeout;
3763 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3764 TM.tmCharSet = winfnt_header.charset;
3769 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3770 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3771 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3772 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3773 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3774 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3775 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3776 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3778 TM.tmDigitizedAspectX = 96; /* FIXME */
3779 TM.tmDigitizedAspectY = 96; /* FIXME */
3781 TM.tmLastChar = 255;
3782 TM.tmDefaultChar = 32;
3783 TM.tmBreakChar = 32;
3784 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3785 TM.tmUnderlined = font->underline;
3786 TM.tmStruckOut = font->strikeout;
3787 /* NB inverted meaning of TMPF_FIXED_PITCH */
3788 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3789 TM.tmCharSet = font->charset;
3796 /*************************************************************
3797 * WineEngGetTextMetrics
3800 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
3803 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3804 if(!get_bitmap_text_metrics(font))
3807 if(!font->potm) return FALSE;
3808 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3810 if (font->aveWidth) {
3811 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3817 /*************************************************************
3818 * WineEngGetOutlineTextMetrics
3821 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
3822 OUTLINETEXTMETRICW *potm)
3824 FT_Face ft_face = font->ft_face;
3825 UINT needed, lenfam, lensty, ret;
3827 TT_HoriHeader *pHori;
3828 TT_Postscript *pPost;
3829 FT_Fixed x_scale, y_scale;
3830 WCHAR *family_nameW, *style_nameW;
3831 static const WCHAR spaceW[] = {' ', '\0'};
3833 INT ascent, descent;
3835 TRACE("font=%p\n", font);
3837 if(!FT_IS_SCALABLE(ft_face))
3841 if(cbSize >= font->potm->otmSize)
3842 memcpy(potm, font->potm, font->potm->otmSize);
3843 return font->potm->otmSize;
3847 needed = sizeof(*potm);
3849 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3850 family_nameW = strdupW(font->name);
3852 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3854 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3855 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3856 style_nameW, lensty/sizeof(WCHAR));
3858 /* These names should be read from the TT name table */
3860 /* length of otmpFamilyName */
3863 /* length of otmpFaceName */
3864 if(!strcasecmp(ft_face->style_name, "regular")) {
3865 needed += lenfam; /* just the family name */
3867 needed += lenfam + lensty; /* family + " " + style */
3870 /* length of otmpStyleName */
3873 /* length of otmpFullName */
3874 needed += lenfam + lensty;
3877 x_scale = ft_face->size->metrics.x_scale;
3878 y_scale = ft_face->size->metrics.y_scale;
3880 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3882 FIXME("Can't find OS/2 table - not TT font?\n");
3887 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3889 FIXME("Can't find HHEA table - not TT font?\n");
3894 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3896 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",
3897 pOS2->usWinAscent, pOS2->usWinDescent,
3898 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3899 ft_face->ascender, ft_face->descender, ft_face->height,
3900 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3901 ft_face->bbox.yMax, ft_face->bbox.yMin);
3903 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3904 font->potm->otmSize = needed;
3906 #define TM font->potm->otmTextMetrics
3908 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3909 ascent = pHori->Ascender;
3910 descent = -pHori->Descender;
3912 ascent = pOS2->usWinAscent;
3913 descent = pOS2->usWinDescent;
3917 TM.tmAscent = font->yMax;
3918 TM.tmDescent = -font->yMin;
3919 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3921 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
3922 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
3923 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
3924 - ft_face->units_per_EM, y_scale) + 32) >> 6;
3927 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3930 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3932 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
3933 ((ascent + descent) -
3934 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
3936 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
3937 if (TM.tmAveCharWidth == 0) {
3938 TM.tmAveCharWidth = 1;
3940 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
3941 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
3943 TM.tmDigitizedAspectX = 300;
3944 TM.tmDigitizedAspectY = 300;
3945 TM.tmFirstChar = pOS2->usFirstCharIndex;
3946 TM.tmLastChar = pOS2->usLastCharIndex;
3947 TM.tmDefaultChar = pOS2->usDefaultChar;
3948 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
3949 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3950 TM.tmUnderlined = font->underline;
3951 TM.tmStruckOut = font->strikeout;
3953 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3954 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3955 (pOS2->version == 0xFFFFU ||
3956 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3957 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3959 TM.tmPitchAndFamily = 0;
3961 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
3962 case PAN_FAMILY_SCRIPT:
3963 TM.tmPitchAndFamily |= FF_SCRIPT;
3965 case PAN_FAMILY_DECORATIVE:
3966 case PAN_FAMILY_PICTORIAL:
3967 TM.tmPitchAndFamily |= FF_DECORATIVE;
3969 case PAN_FAMILY_TEXT_DISPLAY:
3970 if(TM.tmPitchAndFamily == 0) /* fixed */
3971 TM.tmPitchAndFamily = FF_MODERN;
3973 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
3974 case PAN_SERIF_NORMAL_SANS:
3975 case PAN_SERIF_OBTUSE_SANS:
3976 case PAN_SERIF_PERP_SANS:
3977 TM.tmPitchAndFamily |= FF_SWISS;
3980 TM.tmPitchAndFamily |= FF_ROMAN;
3985 TM.tmPitchAndFamily |= FF_DONTCARE;
3988 if(FT_IS_SCALABLE(ft_face))
3989 TM.tmPitchAndFamily |= TMPF_VECTOR;
3990 if(FT_IS_SFNT(ft_face))
3991 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3993 TM.tmCharSet = font->charset;
3996 font->potm->otmFiller = 0;
3997 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3998 font->potm->otmfsSelection = pOS2->fsSelection;
3999 font->potm->otmfsType = pOS2->fsType;
4000 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
4001 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
4002 font->potm->otmItalicAngle = 0; /* POST table */
4003 font->potm->otmEMSquare = ft_face->units_per_EM;
4004 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
4005 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4006 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4007 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
4008 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4009 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
4010 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
4011 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
4012 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4013 font->potm->otmMacAscent = 0; /* where do these come from ? */
4014 font->potm->otmMacDescent = 0;
4015 font->potm->otmMacLineGap = 0;
4016 font->potm->otmusMinimumPPEM = 0; /* TT Header */
4017 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
4018 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
4019 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
4020 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
4021 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
4022 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
4023 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
4024 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
4025 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
4026 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4028 font->potm->otmsUnderscoreSize = 0;
4029 font->potm->otmsUnderscorePosition = 0;
4031 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
4032 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
4035 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4036 cp = (char*)font->potm + sizeof(*font->potm);
4037 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4038 strcpyW((WCHAR*)cp, family_nameW);
4040 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4041 strcpyW((WCHAR*)cp, style_nameW);
4043 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4044 strcpyW((WCHAR*)cp, family_nameW);
4045 if(strcasecmp(ft_face->style_name, "regular")) {
4046 strcatW((WCHAR*)cp, spaceW);
4047 strcatW((WCHAR*)cp, style_nameW);
4048 cp += lenfam + lensty;
4051 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
4052 strcpyW((WCHAR*)cp, family_nameW);
4053 strcatW((WCHAR*)cp, spaceW);
4054 strcatW((WCHAR*)cp, style_nameW);
4057 if(potm && needed <= cbSize)
4058 memcpy(potm, font->potm, font->potm->otmSize);
4061 HeapFree(GetProcessHeap(), 0, style_nameW);
4062 HeapFree(GetProcessHeap(), 0, family_nameW);
4067 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
4069 HFONTLIST *hfontlist;
4070 child->font = alloc_font();
4071 child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem);
4072 if(!child->font->ft_face)
4074 free_font(child->font);
4079 child->font->orientation = font->orientation;
4080 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
4081 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
4082 list_add_head(&child->font->hfontlist, &hfontlist->entry);
4083 child->font->base_font = font;
4084 list_add_head(&child_font_list, &child->font->entry);
4085 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
4089 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
4092 CHILD_FONT *child_font;
4095 font = font->base_font;
4097 *linked_font = font;
4099 if((*glyph = get_glyph_index(font, c)))
4102 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
4104 if(!child_font->font)
4105 if(!load_child_font(font, child_font))
4108 if(!child_font->font->ft_face)
4110 g = get_glyph_index(child_font->font, c);
4114 *linked_font = child_font->font;
4121 /*************************************************************
4122 * WineEngGetCharWidth
4125 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4130 FT_UInt glyph_index;
4131 GdiFont *linked_font;
4133 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4135 for(c = firstChar; c <= lastChar; c++) {
4136 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4137 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4138 &gm, 0, NULL, NULL);
4139 buffer[c - firstChar] = linked_font->gm[glyph_index].adv;
4144 /*************************************************************
4145 * WineEngGetCharABCWidths
4148 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4153 FT_UInt glyph_index;
4154 GdiFont *linked_font;
4156 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4158 if(!FT_IS_SCALABLE(font->ft_face))
4161 for(c = firstChar; c <= lastChar; c++) {
4162 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4163 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4164 &gm, 0, NULL, NULL);
4165 buffer[c - firstChar].abcA = linked_font->gm[glyph_index].lsb;
4166 buffer[c - firstChar].abcB = linked_font->gm[glyph_index].bbx;
4167 buffer[c - firstChar].abcC = linked_font->gm[glyph_index].adv - linked_font->gm[glyph_index].lsb -
4168 linked_font->gm[glyph_index].bbx;
4173 /*************************************************************
4174 * WineEngGetCharABCWidthsI
4177 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4182 FT_UInt glyph_index;
4183 GdiFont *linked_font;
4185 if(!FT_IS_SCALABLE(font->ft_face))
4188 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
4190 for(c = firstChar; c < firstChar+count; c++) {
4191 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
4192 &gm, 0, NULL, NULL);
4193 buffer[c - firstChar].abcA = linked_font->gm[c].lsb;
4194 buffer[c - firstChar].abcB = linked_font->gm[c].bbx;
4195 buffer[c - firstChar].abcC = linked_font->gm[c].adv - linked_font->gm[c].lsb
4196 - linked_font->gm[c].bbx;
4199 for(c = 0; c < count; c++) {
4200 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
4201 &gm, 0, NULL, NULL);
4202 buffer[c].abcA = linked_font->gm[pgi[c]].lsb;
4203 buffer[c].abcB = linked_font->gm[pgi[c]].bbx;
4204 buffer[c].abcC = linked_font->gm[pgi[c]].adv
4205 - linked_font->gm[pgi[c]].lsb - linked_font->gm[pgi[c]].bbx;
4211 /*************************************************************
4212 * WineEngGetTextExtentExPoint
4215 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4216 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4222 FT_UInt glyph_index;
4223 GdiFont *linked_font;
4225 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
4229 WineEngGetTextMetrics(font, &tm);
4230 size->cy = tm.tmHeight;
4232 for(idx = 0; idx < count; idx++) {
4233 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
4234 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4235 &gm, 0, NULL, NULL);
4236 size->cx += linked_font->gm[glyph_index].adv;
4238 if (! pnfit || ext <= max_ext) {
4248 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4252 /*************************************************************
4253 * WineEngGetTextExtentPointI
4256 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4263 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
4266 WineEngGetTextMetrics(font, &tm);
4267 size->cy = tm.tmHeight;
4269 for(idx = 0; idx < count; idx++) {
4270 WineEngGetGlyphOutline(font, indices[idx],
4271 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
4273 size->cx += font->gm[indices[idx]].adv;
4275 TRACE("return %d,%d\n", size->cx, size->cy);
4279 /*************************************************************
4280 * WineEngGetFontData
4283 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4286 FT_Face ft_face = font->ft_face;
4290 TRACE("font=%p, table=%08x, offset=%08x, buf=%p, cbData=%x\n",
4291 font, table, offset, buf, cbData);
4293 if(!FT_IS_SFNT(ft_face))
4301 if(table) { /* MS tags differ in endidness from FT ones */
4302 table = table >> 24 | table << 24 |
4303 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
4306 /* If the FT_Load_Sfnt_Table function is there we'll use it */
4307 if(pFT_Load_Sfnt_Table) {
4308 /* make sure value of len is the value freetype says it needs */
4310 FT_ULong needed = 0;
4311 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4312 if( !err && needed < len) len = needed;
4314 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4316 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
4317 else { /* Do it the hard way */
4318 TT_Face tt_face = (TT_Face) ft_face;
4319 SFNT_Interface *sfnt;
4320 if (FT_Version.major==2 && FT_Version.minor==0)
4323 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
4327 /* A field was added in the middle of the structure in 2.1.x */
4328 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
4330 /* make sure value of len is the value freetype says it needs */
4332 FT_ULong needed = 0;
4333 err = sfnt->load_any(tt_face, table, offset, NULL, &needed);
4334 if( !err && needed < len) len = needed;
4336 err = sfnt->load_any(tt_face, table, offset, buf, &len);
4342 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
4343 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
4344 "Please upgrade your freetype library.\n");
4347 err = FT_Err_Unimplemented_Feature;
4351 TRACE("Can't find table %08x.\n", table);
4357 /*************************************************************
4358 * WineEngGetTextFace
4361 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4364 lstrcpynW(str, font->name, count);
4365 return strlenW(font->name);
4367 return strlenW(font->name) + 1;
4370 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4372 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4373 return font->charset;
4376 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4378 GdiFont *font = dc->gdiFont, *linked_font;
4379 struct list *first_hfont;
4382 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4383 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4384 if(font == linked_font)
4385 *new_hfont = dc->hFont;
4388 first_hfont = list_head(&linked_font->hfontlist);
4389 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4396 /*************************************************************
4399 BOOL WINAPI FontIsLinked(HDC hdc)
4401 DC *dc = DC_GetDCPtr(hdc);
4404 if(!dc) return FALSE;
4405 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
4407 GDI_ReleaseObj(hdc);
4408 TRACE("returning %d\n", ret);
4412 static BOOL is_hinting_enabled(void)
4414 /* Use the >= 2.2.0 function if available */
4415 if(pFT_Get_TrueType_Engine_Type)
4417 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4418 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4420 #ifdef FT_DRIVER_HAS_HINTER
4425 /* otherwise if we've been compiled with < 2.2.0 headers
4426 use the internal macro */
4427 mod = pFT_Get_Module(library, "truetype");
4428 if(mod && FT_DRIVER_HAS_HINTER(mod))
4436 /*************************************************************************
4437 * GetRasterizerCaps (GDI32.@)
4439 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4441 static int hinting = -1;
4444 hinting = is_hinting_enabled();
4446 lprs->nSize = sizeof(RASTERIZER_STATUS);
4447 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4448 lprs->nLanguageID = 0;
4452 /*************************************************************************
4453 * Kerning support for TrueType fonts
4455 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4457 struct TT_kern_table
4463 struct TT_kern_subtable
4472 USHORT horizontal : 1;
4474 USHORT cross_stream: 1;
4475 USHORT override : 1;
4476 USHORT reserved1 : 4;
4482 struct TT_format0_kern_subtable
4486 USHORT entrySelector;
4497 static DWORD parse_format0_kern_subtable(GdiFont *font,
4498 const struct TT_format0_kern_subtable *tt_f0_ks,
4499 const USHORT *glyph_to_char,
4500 KERNINGPAIR *kern_pair, DWORD cPairs)
4503 const struct TT_kern_pair *tt_kern_pair;
4505 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
4507 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4509 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4510 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4511 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4513 if (!kern_pair || !cPairs)
4516 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4518 nPairs = min(nPairs, cPairs);
4520 for (i = 0; i < nPairs; i++)
4522 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4523 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4524 /* this algorithm appears to better match what Windows does */
4525 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4526 if (kern_pair->iKernAmount < 0)
4528 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
4529 kern_pair->iKernAmount -= font->ppem;
4531 else if (kern_pair->iKernAmount > 0)
4533 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
4534 kern_pair->iKernAmount += font->ppem;
4536 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
4538 TRACE("left %u right %u value %d\n",
4539 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
4543 TRACE("copied %u entries\n", nPairs);
4547 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4551 const struct TT_kern_table *tt_kern_table;
4552 const struct TT_kern_subtable *tt_kern_subtable;
4554 USHORT *glyph_to_char;
4556 if (font->total_kern_pairs != (DWORD)-1)
4558 if (cPairs && kern_pair)
4560 cPairs = min(cPairs, font->total_kern_pairs);
4561 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4564 return font->total_kern_pairs;
4567 font->total_kern_pairs = 0;
4569 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
4571 if (length == GDI_ERROR)
4573 TRACE("no kerning data in the font\n");
4577 buf = HeapAlloc(GetProcessHeap(), 0, length);
4580 WARN("Out of memory\n");
4584 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
4586 /* build a glyph index to char code map */
4587 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
4590 WARN("Out of memory allocating a glyph index to char code map\n");
4591 HeapFree(GetProcessHeap(), 0, buf);
4595 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4601 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
4603 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4604 font->ft_face->num_glyphs, glyph_code, char_code);
4608 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4610 /* FIXME: This doesn't match what Windows does: it does some fancy
4611 * things with duplicate glyph index to char code mappings, while
4612 * we just avoid overriding existing entries.
4614 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
4615 glyph_to_char[glyph_code] = (USHORT)char_code;
4617 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
4624 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
4625 for (n = 0; n <= 65535; n++)
4626 glyph_to_char[n] = (USHORT)n;
4629 tt_kern_table = buf;
4630 nTables = GET_BE_WORD(tt_kern_table->nTables);
4631 TRACE("version %u, nTables %u\n",
4632 GET_BE_WORD(tt_kern_table->version), nTables);
4634 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
4636 for (i = 0; i < nTables; i++)
4638 struct TT_kern_subtable tt_kern_subtable_copy;
4640 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
4641 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
4642 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
4644 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4645 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
4646 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
4648 /* According to the TrueType specification this is the only format
4649 * that will be properly interpreted by Windows and OS/2
4651 if (tt_kern_subtable_copy.coverage.bits.format == 0)
4653 DWORD new_chunk, old_total = font->total_kern_pairs;
4655 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4656 glyph_to_char, NULL, 0);
4657 font->total_kern_pairs += new_chunk;
4659 if (!font->kern_pairs)
4660 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
4661 font->total_kern_pairs * sizeof(*font->kern_pairs));
4663 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
4664 font->total_kern_pairs * sizeof(*font->kern_pairs));
4666 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4667 glyph_to_char, font->kern_pairs + old_total, new_chunk);
4670 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
4672 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
4675 HeapFree(GetProcessHeap(), 0, glyph_to_char);
4676 HeapFree(GetProcessHeap(), 0, buf);
4678 if (cPairs && kern_pair)
4680 cPairs = min(cPairs, font->total_kern_pairs);
4681 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4684 return font->total_kern_pairs;
4687 #else /* HAVE_FREETYPE */
4689 /*************************************************************************/
4691 BOOL WineEngInit(void)
4695 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
4699 BOOL WineEngDestroyFontInstance(HFONT hfont)
4704 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4709 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4710 LPWORD pgi, DWORD flags)
4715 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
4716 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4719 ERR("called but we don't have FreeType\n");
4723 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4725 ERR("called but we don't have FreeType\n");
4729 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4730 OUTLINETEXTMETRICW *potm)
4732 ERR("called but we don't have FreeType\n");
4736 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4739 ERR("called but we don't have FreeType\n");
4743 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4746 ERR("called but we don't have FreeType\n");
4750 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4753 ERR("called but we don't have FreeType\n");
4757 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4758 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
4760 ERR("called but we don't have FreeType\n");
4764 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4767 ERR("called but we don't have FreeType\n");
4771 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4774 ERR("called but we don't have FreeType\n");
4778 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4780 ERR("called but we don't have FreeType\n");
4784 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4790 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4796 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4799 return DEFAULT_CHARSET;
4802 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4807 BOOL WINAPI FontIsLinked(HDC hdc)
4812 /*************************************************************************
4813 * GetRasterizerCaps (GDI32.@)
4815 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4817 lprs->nSize = sizeof(RASTERIZER_STATUS);
4819 lprs->nLanguageID = 0;
4823 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4825 ERR("called but we don't have FreeType\n");
4829 #endif /* HAVE_FREETYPE */