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 HAVE_FT_TRUETYPEENGINETYPE
134 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
135 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
136 FT_TRUETYPE_ENGINE_TYPE_PATENTED
137 } FT_TrueTypeEngineType;
140 static FT_Library library = 0;
147 static FT_Version_t FT_Version;
148 static DWORD FT_SimpleVersion;
150 static void *ft_handle = NULL;
152 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
153 MAKE_FUNCPTR(FT_Vector_Unit);
154 MAKE_FUNCPTR(FT_Done_Face);
155 MAKE_FUNCPTR(FT_Get_Char_Index);
156 MAKE_FUNCPTR(FT_Get_Module);
157 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
158 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
159 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
160 MAKE_FUNCPTR(FT_Init_FreeType);
161 MAKE_FUNCPTR(FT_Load_Glyph);
162 MAKE_FUNCPTR(FT_Matrix_Multiply);
163 MAKE_FUNCPTR(FT_MulFix);
164 MAKE_FUNCPTR(FT_New_Face);
165 MAKE_FUNCPTR(FT_New_Memory_Face);
166 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
167 MAKE_FUNCPTR(FT_Outline_Transform);
168 MAKE_FUNCPTR(FT_Outline_Translate);
169 MAKE_FUNCPTR(FT_Select_Charmap);
170 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
171 MAKE_FUNCPTR(FT_Vector_Transform);
172 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
173 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
174 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
175 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
176 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
177 #ifdef HAVE_FREETYPE_FTWINFNT_H
178 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
181 #ifdef SONAME_LIBFONTCONFIG
182 #include <fontconfig/fontconfig.h>
183 MAKE_FUNCPTR(FcConfigGetCurrent);
184 MAKE_FUNCPTR(FcFontList);
185 MAKE_FUNCPTR(FcFontSetDestroy);
186 MAKE_FUNCPTR(FcInit);
187 MAKE_FUNCPTR(FcObjectSetAdd);
188 MAKE_FUNCPTR(FcObjectSetCreate);
189 MAKE_FUNCPTR(FcObjectSetDestroy);
190 MAKE_FUNCPTR(FcPatternCreate);
191 MAKE_FUNCPTR(FcPatternDestroy);
192 MAKE_FUNCPTR(FcPatternGetBool);
193 MAKE_FUNCPTR(FcPatternGetString);
198 #ifndef ft_encoding_none
199 #define FT_ENCODING_NONE ft_encoding_none
201 #ifndef ft_encoding_ms_symbol
202 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
204 #ifndef ft_encoding_unicode
205 #define FT_ENCODING_UNICODE ft_encoding_unicode
207 #ifndef ft_encoding_apple_roman
208 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
211 #ifdef WORDS_BIGENDIAN
212 #define GET_BE_WORD(x) (x)
214 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
217 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
224 FT_Short internal_leading;
227 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
228 So to let this compile on older versions of FreeType we'll define the
229 new structure here. */
231 FT_Short height, width;
232 FT_Pos size, x_ppem, y_ppem;
235 typedef struct tagFace {
243 FONTSIGNATURE fs_links;
244 FT_Fixed font_version;
246 Bitmap_Size size; /* set if face is a bitmap */
247 BOOL external; /* TRUE if we should manually add this font to the registry */
248 struct tagFamily *family;
251 typedef struct tagFamily {
253 const WCHAR *FamilyName;
259 INT adv; /* These three hold to widths of the unrotated chars */
277 typedef struct tagHFONTLIST {
292 struct font_mapping *mapping;
303 struct list hfontlist;
308 OUTLINETEXTMETRICW *potm;
309 DWORD total_kern_pairs;
310 KERNINGPAIR *kern_pairs;
313 struct list child_fonts;
319 const WCHAR *font_name;
323 #define INIT_GM_SIZE 128
325 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
326 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
327 #define UNUSED_CACHE_SIZE 10
328 static struct list child_font_list = LIST_INIT(child_font_list);
329 static struct list system_links = LIST_INIT(system_links);
331 static struct list font_subst_list = LIST_INIT(font_subst_list);
333 static struct list font_list = LIST_INIT(font_list);
335 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
336 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
337 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
339 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
341 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
342 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
343 'W','i','n','d','o','w','s','\\',
344 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
345 'F','o','n','t','s','\0'};
347 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
348 'W','i','n','d','o','w','s',' ','N','T','\\',
349 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
350 'F','o','n','t','s','\0'};
352 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
353 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
354 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
355 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
357 static const WCHAR * const SystemFontValues[4] = {
364 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
365 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
367 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
368 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
369 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
370 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
371 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
372 'E','u','r','o','p','e','a','n','\0'};
373 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
374 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
375 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
376 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
377 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
378 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
379 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
380 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
381 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
382 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
383 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
384 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
386 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
396 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
404 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
413 typedef struct tagFontSubst {
429 static struct list mappings_list = LIST_INIT( mappings_list );
431 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
433 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
435 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
437 /****************************************
438 * Notes on .fon files
440 * The fonts System, FixedSys and Terminal are special. There are typically multiple
441 * versions installed for different resolutions and codepages. Windows stores which one to use
442 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
444 * FIXEDFON.FON FixedSys
446 * OEMFONT.FON Terminal
447 * LogPixels Current dpi set by the display control panel applet
448 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
449 * also has a LogPixels value that appears to mirror this)
451 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
452 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
453 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
454 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
455 * so that makes sense.
457 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
458 * to be mapped into the registry on Windows 2000 at least).
461 * ega80woa.fon=ega80850.fon
462 * ega40woa.fon=ega40850.fon
463 * cga80woa.fon=cga80850.fon
464 * cga40woa.fon=cga40850.fon
467 #ifdef HAVE_CARBON_CARBON_H
468 static char *find_cache_dir(void)
472 static char cached_path[MAX_PATH];
473 static const char *wine = "/Wine", *fonts = "/Fonts";
475 if(*cached_path) return cached_path;
477 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
480 WARN("can't create cached data folder\n");
483 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
486 WARN("can't create cached data path\n");
490 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
492 ERR("Could not create full path\n");
496 strcat(cached_path, wine);
498 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
500 WARN("Couldn't mkdir %s\n", cached_path);
504 strcat(cached_path, fonts);
505 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
507 WARN("Couldn't mkdir %s\n", cached_path);
514 /******************************************************************
517 * Extracts individual TrueType font files from a Mac suitcase font
518 * and saves them into the user's caches directory (see
520 * Returns a NULL terminated array of filenames.
522 * We do this because they are apps that try to read ttf files
523 * themselves and they don't like Mac suitcase files.
525 static char **expand_mac_font(const char *path)
532 const char *filename;
536 unsigned int size, max_size;
539 TRACE("path %s\n", path);
541 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
544 WARN("failed to get ref\n");
548 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
551 TRACE("no data fork, so trying resource fork\n");
552 res_ref = FSOpenResFile(&ref, fsRdPerm);
555 TRACE("unable to open resource fork\n");
562 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
565 CloseResFile(res_ref);
569 out_dir = find_cache_dir();
571 filename = strrchr(path, '/');
572 if(!filename) filename = path;
575 /* output filename has the form out_dir/filename_%04x.ttf */
576 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
583 unsigned short *num_faces_ptr, num_faces, face;
586 ResType fond_res = 0x464f4e44; /* 'FOND' */
588 fond = Get1IndResource(fond_res, idx);
590 TRACE("got fond resource %d\n", idx);
593 fam_rec = *(FamRec**)fond;
594 num_faces_ptr = (unsigned short *)(fam_rec + 1);
595 num_faces = GET_BE_WORD(*num_faces_ptr);
597 assoc = (AsscEntry*)(num_faces_ptr + 1);
598 TRACE("num faces %04x\n", num_faces);
599 for(face = 0; face < num_faces; face++, assoc++)
602 ResType sfnt_res = 0x73666e74; /* 'sfnt' */
603 unsigned short size, font_id;
606 size = GET_BE_WORD(assoc->fontSize);
607 font_id = GET_BE_WORD(assoc->fontID);
610 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
614 TRACE("trying to load sfnt id %04x\n", font_id);
615 sfnt = GetResource(sfnt_res, font_id);
618 TRACE("can't get sfnt resource %04x\n", font_id);
622 output = HeapAlloc(GetProcessHeap(), 0, output_len);
627 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
629 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
630 if(fd != -1 || errno == EEXIST)
634 unsigned char *sfnt_data;
637 sfnt_data = *(unsigned char**)sfnt;
638 write(fd, sfnt_data, GetHandleSize(sfnt));
642 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
645 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
647 ret.array[ret.size++] = output;
651 WARN("unable to create %s\n", output);
652 HeapFree(GetProcessHeap(), 0, output);
655 ReleaseResource(sfnt);
658 ReleaseResource(fond);
661 CloseResFile(res_ref);
666 #endif /* HAVE_CARBON_CARBON_H */
668 static inline BOOL is_win9x(void)
670 return GetVersion() & 0x80000000;
673 This function builds an FT_Fixed from a float. It puts the integer part
674 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
675 It fails if the integer part of the float number is greater than SHORT_MAX.
677 static inline FT_Fixed FT_FixedFromFloat(float f)
680 unsigned short fract = (f - value) * 0xFFFF;
681 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
685 This function builds an FT_Fixed from a FIXED. It simply put f.value
686 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
688 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
690 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
694 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
699 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
700 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
702 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
703 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
705 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
707 if(face_name && strcmpiW(face_name, family->FamilyName))
709 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
711 file = strrchr(face->file, '/');
716 if(!strcasecmp(file, file_nameA))
718 HeapFree(GetProcessHeap(), 0, file_nameA);
723 HeapFree(GetProcessHeap(), 0, file_nameA);
727 static Family *find_family_from_name(const WCHAR *name)
731 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
733 if(!strcmpiW(family->FamilyName, name))
740 static Face *find_face_from_path_index(const CHAR *file_name, const INT index)
745 TRACE("looking for file %s index %i\n", debugstr_a(file_name), index);
747 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
749 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
751 if(!strcasecmp(face->file, file_name) && face->face_index == index)
758 static void DumpSubstList(void)
762 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
764 if(psub->from.charset != -1 || psub->to.charset != -1)
765 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
766 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
768 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
769 debugstr_w(psub->to.name));
774 static LPWSTR strdupW(LPCWSTR p)
777 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
778 ret = HeapAlloc(GetProcessHeap(), 0, len);
783 static LPSTR strdupA(LPCSTR p)
786 DWORD len = (strlen(p) + 1);
787 ret = HeapAlloc(GetProcessHeap(), 0, len);
792 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
797 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
799 if(!strcmpiW(element->from.name, from_name) &&
800 (element->from.charset == from_charset ||
801 element->from.charset == -1))
808 #define ADD_FONT_SUBST_FORCE 1
810 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
812 FontSubst *from_exist, *to_exist;
814 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
816 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
818 list_remove(&from_exist->entry);
819 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
820 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
821 HeapFree(GetProcessHeap(), 0, from_exist);
827 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
831 HeapFree(GetProcessHeap(), 0, subst->to.name);
832 subst->to.name = strdupW(to_exist->to.name);
835 list_add_tail(subst_list, &subst->entry);
840 HeapFree(GetProcessHeap(), 0, subst->from.name);
841 HeapFree(GetProcessHeap(), 0, subst->to.name);
842 HeapFree(GetProcessHeap(), 0, subst);
846 static void split_subst_info(NameCs *nc, LPSTR str)
848 CHAR *p = strrchr(str, ',');
853 nc->charset = strtol(p+1, NULL, 10);
856 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
857 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
858 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
861 static void LoadSubstList(void)
865 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
869 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
870 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
871 &hkey) == ERROR_SUCCESS) {
873 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
874 &valuelen, &datalen, NULL, NULL);
876 valuelen++; /* returned value doesn't include room for '\0' */
877 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
878 data = HeapAlloc(GetProcessHeap(), 0, datalen);
882 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
883 &dlen) == ERROR_SUCCESS) {
884 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
886 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
887 split_subst_info(&psub->from, value);
888 split_subst_info(&psub->to, data);
890 /* Win 2000 doesn't allow mapping between different charsets
891 or mapping of DEFAULT_CHARSET */
892 if((psub->to.charset != psub->from.charset) ||
893 psub->to.charset == DEFAULT_CHARSET) {
894 HeapFree(GetProcessHeap(), 0, psub->to.name);
895 HeapFree(GetProcessHeap(), 0, psub->from.name);
896 HeapFree(GetProcessHeap(), 0, psub);
898 add_font_subst(&font_subst_list, psub, 0);
900 /* reset dlen and vlen */
904 HeapFree(GetProcessHeap(), 0, data);
905 HeapFree(GetProcessHeap(), 0, value);
910 static WCHAR *get_familyname(FT_Face ft_face)
912 WCHAR *family = NULL;
914 FT_UInt num_names, name_index, i;
916 if(FT_IS_SFNT(ft_face))
918 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
920 for(name_index = 0; name_index < num_names; name_index++)
922 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
924 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
925 (name.language_id == GetUserDefaultLCID()) &&
926 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
927 (name.encoding_id == TT_MS_ID_UNICODE_CS))
929 /* String is not nul terminated and string_len is a byte length. */
930 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
931 for(i = 0; i < name.string_len / 2; i++)
933 WORD *tmp = (WORD *)&name.string[i * 2];
934 family[i] = GET_BE_WORD(*tmp);
938 TRACE("Got localised name %s\n", debugstr_w(family));
949 #define ADDFONT_EXTERNAL_FONT 0x01
950 #define ADDFONT_FORCE_BITMAP 0x02
951 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
955 TT_Header *pHeader = NULL;
956 WCHAR *english_family, *localised_family, *StyleW;
960 struct list *family_elem_ptr, *face_elem_ptr;
962 FT_Long face_index = 0, num_faces;
963 #ifdef HAVE_FREETYPE_FTWINFNT_H
964 FT_WinFNT_HeaderRec winfnt_header;
966 int i, bitmap_num, internal_leading;
969 #ifdef HAVE_CARBON_CARBON_H
972 char **mac_list = expand_mac_font(file);
975 BOOL had_one = FALSE;
977 for(cursor = mac_list; *cursor; cursor++)
980 AddFontFileToList(*cursor, NULL, NULL, flags);
981 HeapFree(GetProcessHeap(), 0, *cursor);
983 HeapFree(GetProcessHeap(), 0, mac_list);
988 #endif /* HAVE_CARBON_CARBON_H */
991 char *family_name = fake_family;
993 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
994 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
995 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
999 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*/
1000 WARN("Ignoring font %s\n", debugstr_a(file));
1001 pFT_Done_Face(ft_face);
1005 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1006 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1007 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file));
1008 pFT_Done_Face(ft_face);
1012 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
1013 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1014 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
1015 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
1016 "Skipping this font.\n", debugstr_a(file));
1017 pFT_Done_Face(ft_face);
1021 if(!ft_face->family_name || !ft_face->style_name) {
1022 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
1023 pFT_Done_Face(ft_face);
1029 localised_family = get_familyname(ft_face);
1030 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1032 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1033 HeapFree(GetProcessHeap(), 0, localised_family);
1034 num_faces = ft_face->num_faces;
1035 pFT_Done_Face(ft_face);
1038 HeapFree(GetProcessHeap(), 0, localised_family);
1042 family_name = ft_face->family_name;
1046 My_FT_Bitmap_Size *size = NULL;
1048 if(!FT_IS_SCALABLE(ft_face))
1049 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1051 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1052 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1053 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1055 localised_family = NULL;
1057 localised_family = get_familyname(ft_face);
1058 if(localised_family && !strcmpW(localised_family, english_family)) {
1059 HeapFree(GetProcessHeap(), 0, localised_family);
1060 localised_family = NULL;
1065 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1066 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1067 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1072 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1073 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1074 list_init(&family->faces);
1075 list_add_tail(&font_list, &family->entry);
1077 if(localised_family) {
1078 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1079 subst->from.name = strdupW(english_family);
1080 subst->from.charset = -1;
1081 subst->to.name = strdupW(localised_family);
1082 subst->to.charset = -1;
1083 add_font_subst(&font_subst_list, subst, 0);
1086 HeapFree(GetProcessHeap(), 0, localised_family);
1087 HeapFree(GetProcessHeap(), 0, english_family);
1089 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1090 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1091 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1093 internal_leading = 0;
1094 memset(&fs, 0, sizeof(fs));
1096 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1098 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1099 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1100 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1101 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1102 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1103 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1104 if(pOS2->version == 0) {
1107 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1110 fs.fsCsb[0] |= 1L << 31;
1113 #ifdef HAVE_FREETYPE_FTWINFNT_H
1114 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1116 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1117 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1118 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1119 memcpy(&fs, &csi.fs, sizeof(csi.fs));
1120 internal_leading = winfnt_header.internal_leading;
1124 face_elem_ptr = list_head(&family->faces);
1125 while(face_elem_ptr) {
1126 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1127 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1128 if(!strcmpW(face->StyleName, StyleW) &&
1129 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1130 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1131 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1132 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1135 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1136 HeapFree(GetProcessHeap(), 0, StyleW);
1137 pFT_Done_Face(ft_face);
1140 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1141 TRACE("Original font is newer so skipping this one\n");
1142 HeapFree(GetProcessHeap(), 0, StyleW);
1143 pFT_Done_Face(ft_face);
1146 TRACE("Replacing original with this one\n");
1147 list_remove(&face->entry);
1148 HeapFree(GetProcessHeap(), 0, face->file);
1149 HeapFree(GetProcessHeap(), 0, face->StyleName);
1150 HeapFree(GetProcessHeap(), 0, face);
1155 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1156 list_add_tail(&family->faces, &face->entry);
1157 face->StyleName = StyleW;
1158 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
1159 strcpy(face->file, file);
1160 face->face_index = face_index;
1161 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
1162 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
1163 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1164 face->family = family;
1165 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1166 memcpy(&face->fs, &fs, sizeof(face->fs));
1167 memset(&face->fs_links, 0, sizeof(face->fs_links));
1169 if(FT_IS_SCALABLE(ft_face)) {
1170 memset(&face->size, 0, sizeof(face->size));
1171 face->scalable = TRUE;
1173 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1174 size->height, size->width, size->size >> 6,
1175 size->x_ppem >> 6, size->y_ppem >> 6);
1176 face->size.height = size->height;
1177 face->size.width = size->width;
1178 face->size.size = size->size;
1179 face->size.x_ppem = size->x_ppem;
1180 face->size.y_ppem = size->y_ppem;
1181 face->size.internal_leading = internal_leading;
1182 face->scalable = FALSE;
1185 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1186 face->fs.fsCsb[0], face->fs.fsCsb[1],
1187 face->fs.fsUsb[0], face->fs.fsUsb[1],
1188 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1191 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1192 for(i = 0; i < ft_face->num_charmaps; i++) {
1193 switch(ft_face->charmaps[i]->encoding) {
1194 case FT_ENCODING_UNICODE:
1195 case FT_ENCODING_APPLE_ROMAN:
1196 face->fs.fsCsb[0] |= 1;
1198 case FT_ENCODING_MS_SYMBOL:
1199 face->fs.fsCsb[0] |= 1L << 31;
1207 if(face->fs.fsCsb[0] & ~(1L << 31))
1208 have_installed_roman_font = TRUE;
1209 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1211 num_faces = ft_face->num_faces;
1212 pFT_Done_Face(ft_face);
1213 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1214 debugstr_w(StyleW));
1215 } while(num_faces > ++face_index);
1219 static void DumpFontList(void)
1223 struct list *family_elem_ptr, *face_elem_ptr;
1225 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1226 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1227 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1228 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1229 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1230 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1232 TRACE(" %d", face->size.height);
1239 /***********************************************************
1240 * The replacement list is a way to map an entire font
1241 * family onto another family. For example adding
1243 * [HKCU\Software\Wine\Fonts\Replacements]
1244 * "Wingdings"="Winedings"
1246 * would enumerate the Winedings font both as Winedings and
1247 * Wingdings. However if a real Wingdings font is present the
1248 * replacement does not take place.
1251 static void LoadReplaceList(void)
1254 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1259 struct list *family_elem_ptr, *face_elem_ptr;
1262 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1263 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1265 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1266 &valuelen, &datalen, NULL, NULL);
1268 valuelen++; /* returned value doesn't include room for '\0' */
1269 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1270 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1274 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1275 &dlen) == ERROR_SUCCESS) {
1276 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1277 /* "NewName"="Oldname" */
1278 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1280 /* Find the old family and hence all of the font files
1282 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1283 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1284 if(!strcmpiW(family->FamilyName, data)) {
1285 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1286 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1287 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1288 debugstr_w(face->StyleName), familyA);
1289 /* Now add a new entry with the new family name */
1290 AddFontFileToList(face->file, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1295 /* reset dlen and vlen */
1299 HeapFree(GetProcessHeap(), 0, data);
1300 HeapFree(GetProcessHeap(), 0, value);
1305 /*************************************************************
1308 static BOOL init_system_links(void)
1310 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1311 'W','i','n','d','o','w','s',' ','N','T','\\',
1312 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1313 'S','y','s','t','e','m','L','i','n','k',0};
1316 DWORD type, max_val, max_data, val_len, data_len, index;
1317 WCHAR *value, *data;
1318 WCHAR *entry, *next;
1319 SYSTEM_LINKS *font_link, *system_font_link;
1320 CHILD_FONT *child_font;
1321 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1322 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1323 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1329 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1331 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1332 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1333 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1334 val_len = max_val + 1;
1335 data_len = max_data;
1337 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1339 TRACE("%s:\n", debugstr_w(value));
1341 memset(&fs, 0, sizeof(fs));
1342 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1343 psub = get_font_subst(&font_subst_list, value, -1);
1344 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1345 list_init(&font_link->links);
1346 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1349 CHILD_FONT *child_font;
1351 TRACE("\t%s\n", debugstr_w(entry));
1353 next = entry + strlenW(entry) + 1;
1355 face_name = strchrW(entry, ',');
1359 while(isspaceW(*face_name))
1362 psub = get_font_subst(&font_subst_list, face_name, -1);
1364 face_name = psub->to.name;
1366 face = find_face_from_filename(entry, face_name);
1369 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1373 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1374 child_font->file_name = strdupA(face->file);
1375 child_font->index = face->face_index;
1376 child_font->font = NULL;
1377 fs.fsCsb[0] |= face->fs.fsCsb[0];
1378 fs.fsCsb[1] |= face->fs.fsCsb[1];
1379 TRACE("Adding file %s index %d\n", child_font->file_name, child_font->index);
1380 list_add_tail(&font_link->links, &child_font->entry);
1382 family = find_family_from_name(font_link->font_name);
1385 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1387 memcpy(&face->fs_links, &fs, sizeof(fs));
1390 list_add_tail(&system_links, &font_link->entry);
1391 val_len = max_val + 1;
1392 data_len = max_data;
1395 HeapFree(GetProcessHeap(), 0, value);
1396 HeapFree(GetProcessHeap(), 0, data);
1400 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1403 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1404 system_font_link->font_name = strdupW(System);
1405 list_init(&system_font_link->links);
1407 face = find_face_from_filename(tahoma_ttf, Tahoma);
1410 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1411 child_font->file_name = strdupA(face->file);
1412 child_font->index = face->face_index;
1413 child_font->font = NULL;
1414 TRACE("Found Tahoma in %s index %d\n", child_font->file_name, child_font->index);
1415 list_add_tail(&system_font_link->links, &child_font->entry);
1417 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1419 if(!strcmpiW(font_link->font_name, Tahoma))
1421 CHILD_FONT *font_link_entry;
1422 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1424 CHILD_FONT *new_child;
1425 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1426 new_child->file_name = strdupA(font_link_entry->file_name);
1427 new_child->index = font_link_entry->index;
1428 new_child->font = NULL;
1429 list_add_tail(&system_font_link->links, &new_child->entry);
1434 list_add_tail(&system_links, &system_font_link->entry);
1438 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1441 struct dirent *dent;
1442 char path[MAX_PATH];
1444 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1446 dir = opendir(dirname);
1448 WARN("Can't open directory %s\n", debugstr_a(dirname));
1451 while((dent = readdir(dir)) != NULL) {
1452 struct stat statbuf;
1454 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1457 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1459 sprintf(path, "%s/%s", dirname, dent->d_name);
1461 if(stat(path, &statbuf) == -1)
1463 WARN("Can't stat %s\n", debugstr_a(path));
1466 if(S_ISDIR(statbuf.st_mode))
1467 ReadFontDir(path, external_fonts);
1469 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1475 static void load_fontconfig_fonts(void)
1477 #ifdef SONAME_LIBFONTCONFIG
1478 void *fc_handle = NULL;
1487 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1489 TRACE("Wine cannot find the fontconfig library (%s).\n",
1490 SONAME_LIBFONTCONFIG);
1493 #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;}
1494 LOAD_FUNCPTR(FcConfigGetCurrent);
1495 LOAD_FUNCPTR(FcFontList);
1496 LOAD_FUNCPTR(FcFontSetDestroy);
1497 LOAD_FUNCPTR(FcInit);
1498 LOAD_FUNCPTR(FcObjectSetAdd);
1499 LOAD_FUNCPTR(FcObjectSetCreate);
1500 LOAD_FUNCPTR(FcObjectSetDestroy);
1501 LOAD_FUNCPTR(FcPatternCreate);
1502 LOAD_FUNCPTR(FcPatternDestroy);
1503 LOAD_FUNCPTR(FcPatternGetBool);
1504 LOAD_FUNCPTR(FcPatternGetString);
1507 if(!pFcInit()) return;
1509 config = pFcConfigGetCurrent();
1510 pat = pFcPatternCreate();
1511 os = pFcObjectSetCreate();
1512 pFcObjectSetAdd(os, FC_FILE);
1513 pFcObjectSetAdd(os, FC_SCALABLE);
1514 fontset = pFcFontList(config, pat, os);
1515 if(!fontset) return;
1516 for(i = 0; i < fontset->nfont; i++) {
1519 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1521 TRACE("fontconfig: %s\n", file);
1523 /* We're just interested in OT/TT fonts for now, so this hack just
1524 picks up the scalable fonts without extensions .pf[ab] to save time
1525 loading every other font */
1527 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1529 TRACE("not scalable\n");
1533 len = strlen( file );
1534 if(len < 4) continue;
1535 ext = &file[ len - 3 ];
1536 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1537 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1539 pFcFontSetDestroy(fontset);
1540 pFcObjectSetDestroy(os);
1541 pFcPatternDestroy(pat);
1547 static BOOL load_font_from_data_dir(LPCWSTR file)
1550 const char *data_dir = wine_get_data_dir();
1552 if (!data_dir) data_dir = wine_get_build_dir();
1559 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1561 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1563 strcpy(unix_name, data_dir);
1564 strcat(unix_name, "/fonts/");
1566 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1568 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1569 HeapFree(GetProcessHeap(), 0, unix_name);
1574 static void load_system_fonts(void)
1577 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1578 const WCHAR * const *value;
1580 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1583 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1584 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1585 strcatW(windowsdir, fontsW);
1586 for(value = SystemFontValues; *value; value++) {
1587 dlen = sizeof(data);
1588 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1592 sprintfW(pathW, fmtW, windowsdir, data);
1593 if((unixname = wine_get_unix_file_name(pathW))) {
1594 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1595 HeapFree(GetProcessHeap(), 0, unixname);
1598 load_font_from_data_dir(data);
1605 /*************************************************************
1607 * This adds registry entries for any externally loaded fonts
1608 * (fonts from fontconfig or FontDirs). It also deletes entries
1609 * of no longer existing fonts.
1612 static void update_reg_entries(void)
1614 HKEY winkey = 0, externalkey = 0;
1617 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1620 struct list *family_elem_ptr, *face_elem_ptr;
1622 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1623 static const WCHAR spaceW[] = {' ', '\0'};
1626 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1627 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1628 ERR("Can't create Windows font reg key\n");
1631 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1632 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1633 ERR("Can't create external font reg key\n");
1637 /* Delete all external fonts added last time */
1639 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1640 &valuelen, &datalen, NULL, NULL);
1641 valuelen++; /* returned value doesn't include room for '\0' */
1642 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1643 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1645 dlen = datalen * sizeof(WCHAR);
1648 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1649 &dlen) == ERROR_SUCCESS) {
1651 RegDeleteValueW(winkey, valueW);
1652 /* reset dlen and vlen */
1656 HeapFree(GetProcessHeap(), 0, data);
1657 HeapFree(GetProcessHeap(), 0, valueW);
1659 /* Delete the old external fonts key */
1660 RegCloseKey(externalkey);
1662 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1664 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1665 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1666 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1667 ERR("Can't create external font reg key\n");
1671 /* enumerate the fonts and add external ones to the two keys */
1673 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1674 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1675 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1676 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1677 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1678 if(!face->external) continue;
1680 if(strcmpiW(face->StyleName, RegularW))
1681 len = len_fam + strlenW(face->StyleName) + 1;
1682 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1683 strcpyW(valueW, family->FamilyName);
1684 if(len != len_fam) {
1685 strcatW(valueW, spaceW);
1686 strcatW(valueW, face->StyleName);
1688 strcatW(valueW, TrueType);
1689 if((path = strrchr(face->file, '/')) == NULL)
1693 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1695 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1696 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1697 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1698 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1700 HeapFree(GetProcessHeap(), 0, file);
1701 HeapFree(GetProcessHeap(), 0, valueW);
1706 RegCloseKey(externalkey);
1708 RegCloseKey(winkey);
1713 /*************************************************************
1714 * WineEngAddFontResourceEx
1717 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1719 if (ft_handle) /* do it only if we have freetype up and running */
1724 FIXME("Ignoring flags %x\n", flags);
1726 if((unixname = wine_get_unix_file_name(file)))
1728 INT ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1729 HeapFree(GetProcessHeap(), 0, unixname);
1736 /*************************************************************
1737 * WineEngRemoveFontResourceEx
1740 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1746 static const struct nls_update_font_list
1748 UINT ansi_cp, oem_cp;
1749 const char *oem, *fixed, *system;
1750 const char *courier, *serif, *small, *sserif;
1751 /* these are for font substitute */
1752 const char *shelldlg, *tmsrmn;
1753 } nls_update_font_list[] =
1755 /* Latin 1 (United States) */
1756 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1757 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1758 "Tahoma","Times New Roman",
1760 /* Latin 1 (Multilingual) */
1761 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1762 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1763 "Tahoma","Times New Roman", /* FIXME unverified */
1765 /* Eastern Europe */
1766 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1767 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1768 "Tahoma","Times New Roman", /* FIXME unverified */
1771 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1772 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1773 "Tahoma","Times New Roman", /* FIXME unverified */
1776 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1777 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1778 "Tahoma","Times New Roman", /* FIXME unverified */
1781 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1782 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1783 "Tahoma","Times New Roman", /* FIXME unverified */
1786 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1787 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1788 "Tahoma","Times New Roman", /* FIXME unverified */
1791 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1792 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1793 "Tahoma","Times New Roman", /* FIXME unverified */
1796 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1797 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1798 "Tahoma","Times New Roman", /* FIXME unverified */
1801 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1802 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1803 "Tahoma","Times New Roman", /* FIXME unverified */
1806 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1807 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1808 "Tahoma","Times New Roman", /* FIXME unverified */
1811 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1812 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1813 "MS UI Gothic","MS Serif",
1815 /* Chinese Simplified */
1816 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1817 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1818 "Tahoma", "Times New Roman", /* FIXME unverified */
1821 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1822 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1825 /* Chinese Traditional */
1826 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1827 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1828 "Tahoma", "Times New Roman", /* FIXME unverified */
1832 static inline HKEY create_fonts_NT_registry_key(void)
1836 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1837 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1841 static inline HKEY create_fonts_9x_registry_key(void)
1845 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1846 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1850 static inline HKEY create_config_fonts_registry_key(void)
1854 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1855 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1859 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1861 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1862 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1863 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1864 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1867 static void update_font_info(void)
1869 char buf[40], cpbuf[40];
1872 UINT i, ansi_cp = 0, oem_cp = 0;
1874 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
1877 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1878 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1879 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1880 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1881 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
1884 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1886 if (!strcmp( buf, cpbuf )) /* already set correctly */
1891 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
1893 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
1895 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
1898 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1900 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1901 nls_update_font_list[i].oem_cp == oem_cp)
1905 hkey = create_config_fonts_registry_key();
1906 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1907 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1908 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1911 hkey = create_fonts_NT_registry_key();
1912 add_font_list(hkey, &nls_update_font_list[i]);
1915 hkey = create_fonts_9x_registry_key();
1916 add_font_list(hkey, &nls_update_font_list[i]);
1919 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
1921 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
1922 strlen(nls_update_font_list[i].shelldlg)+1);
1923 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
1924 strlen(nls_update_font_list[i].tmsrmn)+1);
1930 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
1933 /*************************************************************
1936 * Initialize FreeType library and create a list of available faces
1938 BOOL WineEngInit(void)
1940 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1941 static const WCHAR pathW[] = {'P','a','t','h',0};
1943 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1945 WCHAR windowsdir[MAX_PATH];
1948 const char *data_dir;
1952 /* update locale dependent font info in registry */
1955 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1958 "Wine cannot find the FreeType font library. To enable Wine to\n"
1959 "use TrueType fonts please install a version of FreeType greater than\n"
1960 "or equal to 2.0.5.\n"
1961 "http://www.freetype.org\n");
1965 #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;}
1967 LOAD_FUNCPTR(FT_Vector_Unit)
1968 LOAD_FUNCPTR(FT_Done_Face)
1969 LOAD_FUNCPTR(FT_Get_Char_Index)
1970 LOAD_FUNCPTR(FT_Get_Module)
1971 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1972 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1973 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1974 LOAD_FUNCPTR(FT_Init_FreeType)
1975 LOAD_FUNCPTR(FT_Load_Glyph)
1976 LOAD_FUNCPTR(FT_Matrix_Multiply)
1977 LOAD_FUNCPTR(FT_MulFix)
1978 LOAD_FUNCPTR(FT_New_Face)
1979 LOAD_FUNCPTR(FT_New_Memory_Face)
1980 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1981 LOAD_FUNCPTR(FT_Outline_Transform)
1982 LOAD_FUNCPTR(FT_Outline_Translate)
1983 LOAD_FUNCPTR(FT_Select_Charmap)
1984 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1985 LOAD_FUNCPTR(FT_Vector_Transform)
1988 /* Don't warn if this one is missing */
1989 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1990 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1991 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1992 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
1993 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
1994 #ifdef HAVE_FREETYPE_FTWINFNT_H
1995 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1997 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1998 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1999 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2000 <= 2.0.3 has FT_Sqrt64 */
2004 if(pFT_Init_FreeType(&library) != 0) {
2005 ERR("Can't init FreeType library\n");
2006 wine_dlclose(ft_handle, NULL, 0);
2010 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
2011 if (pFT_Library_Version)
2013 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2015 if (FT_Version.major<=0)
2021 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2022 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2023 ((FT_Version.minor << 8) & 0x00ff00) |
2024 ((FT_Version.patch ) & 0x0000ff);
2026 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2027 ERR("Failed to create font mutex\n");
2030 WaitForSingleObject(font_mutex, INFINITE);
2032 /* load the system bitmap fonts */
2033 load_system_fonts();
2035 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2036 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2037 strcatW(windowsdir, fontsW);
2038 if((unixname = wine_get_unix_file_name(windowsdir)))
2040 ReadFontDir(unixname, FALSE);
2041 HeapFree(GetProcessHeap(), 0, unixname);
2044 /* load the system truetype fonts */
2045 data_dir = wine_get_data_dir();
2046 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2047 strcpy(unixname, data_dir);
2048 strcat(unixname, "/fonts/");
2049 ReadFontDir(unixname, FALSE);
2050 HeapFree(GetProcessHeap(), 0, unixname);
2053 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2054 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2055 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2057 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2058 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2059 &hkey) == ERROR_SUCCESS) {
2061 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2062 &valuelen, &datalen, NULL, NULL);
2064 valuelen++; /* returned value doesn't include room for '\0' */
2065 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2066 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2069 dlen = datalen * sizeof(WCHAR);
2071 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2072 &dlen) == ERROR_SUCCESS) {
2073 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2075 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2077 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2078 HeapFree(GetProcessHeap(), 0, unixname);
2081 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2083 WCHAR pathW[MAX_PATH];
2084 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2087 sprintfW(pathW, fmtW, windowsdir, data);
2088 if((unixname = wine_get_unix_file_name(pathW)))
2090 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2091 HeapFree(GetProcessHeap(), 0, unixname);
2094 load_font_from_data_dir(data);
2096 /* reset dlen and vlen */
2101 HeapFree(GetProcessHeap(), 0, data);
2102 HeapFree(GetProcessHeap(), 0, valueW);
2106 load_fontconfig_fonts();
2108 /* then look in any directories that we've specified in the config file */
2109 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2110 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2116 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2118 len += sizeof(WCHAR);
2119 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2120 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2122 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2123 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2124 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2125 TRACE( "got font path %s\n", debugstr_a(valueA) );
2129 LPSTR next = strchr( ptr, ':' );
2130 if (next) *next++ = 0;
2131 ReadFontDir( ptr, TRUE );
2134 HeapFree( GetProcessHeap(), 0, valueA );
2136 HeapFree( GetProcessHeap(), 0, valueW );
2145 update_reg_entries();
2147 init_system_links();
2149 ReleaseMutex(font_mutex);
2153 "Wine cannot find certain functions that it needs inside the FreeType\n"
2154 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2155 "FreeType to at least version 2.0.5.\n"
2156 "http://www.freetype.org\n");
2157 wine_dlclose(ft_handle, NULL, 0);
2163 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2166 TT_HoriHeader *pHori;
2170 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2171 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2173 if(height == 0) height = 16;
2175 /* Calc. height of EM square:
2177 * For +ve lfHeight we have
2178 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2179 * Re-arranging gives:
2180 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2182 * For -ve lfHeight we have
2184 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2185 * with il = winAscent + winDescent - units_per_em]
2190 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2191 ppem = ft_face->units_per_EM * height /
2192 (pHori->Ascender - pHori->Descender);
2194 ppem = ft_face->units_per_EM * height /
2195 (pOS2->usWinAscent + pOS2->usWinDescent);
2203 static struct font_mapping *map_font( const char *name )
2205 struct font_mapping *mapping;
2209 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2210 if (fstat( fd, &st ) == -1) goto error;
2212 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2214 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2216 mapping->refcount++;
2221 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2224 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2227 if (mapping->data == MAP_FAILED)
2229 HeapFree( GetProcessHeap(), 0, mapping );
2232 mapping->refcount = 1;
2233 mapping->dev = st.st_dev;
2234 mapping->ino = st.st_ino;
2235 mapping->size = st.st_size;
2236 list_add_tail( &mappings_list, &mapping->entry );
2244 static void unmap_font( struct font_mapping *mapping )
2246 if (!--mapping->refcount)
2248 list_remove( &mapping->entry );
2249 munmap( mapping->data, mapping->size );
2250 HeapFree( GetProcessHeap(), 0, mapping );
2254 static LONG load_VDMX(GdiFont*, LONG);
2256 static FT_Face OpenFontFile(GdiFont *font, char *file, FT_Long face_index, LONG width, LONG height)
2261 TRACE("%s, %ld, %d x %d\n", debugstr_a(file), face_index, width, height);
2263 if (!(font->mapping = map_font( file )))
2265 WARN("failed to map %s\n", debugstr_a(file));
2269 err = pFT_New_Memory_Face(library, font->mapping->data, font->mapping->size, face_index, &ft_face);
2271 ERR("FT_New_Face rets %d\n", err);
2275 /* set it here, as load_VDMX needs it */
2276 font->ft_face = ft_face;
2278 if(FT_IS_SCALABLE(ft_face)) {
2279 /* load the VDMX table if we have one */
2280 font->ppem = load_VDMX(font, height);
2282 font->ppem = calc_ppem_for_height(ft_face, height);
2284 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2285 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2287 font->ppem = height;
2288 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2289 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2295 static int get_nearest_charset(Face *face, int *cp)
2297 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2298 a single face with the requested charset. The idea is to check if
2299 the selected font supports the current ANSI codepage, if it does
2300 return the corresponding charset, else return the first charset */
2303 int acp = GetACP(), i;
2307 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2308 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2309 return csi.ciCharset;
2311 for(i = 0; i < 32; i++) {
2313 if(face->fs.fsCsb[0] & fs0) {
2314 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2316 return csi.ciCharset;
2319 FIXME("TCI failing on %x\n", fs0);
2323 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2324 face->fs.fsCsb[0], face->file);
2326 return DEFAULT_CHARSET;
2329 static GdiFont *alloc_font(void)
2331 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2332 ret->gmsize = INIT_GM_SIZE;
2333 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2334 ret->gmsize * sizeof(*ret->gm));
2336 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2337 ret->total_kern_pairs = (DWORD)-1;
2338 ret->kern_pairs = NULL;
2339 list_init(&ret->hfontlist);
2340 list_init(&ret->child_fonts);
2344 static void free_font(GdiFont *font)
2346 struct list *cursor, *cursor2;
2348 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2350 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2351 struct list *first_hfont;
2352 HFONTLIST *hfontlist;
2353 list_remove(cursor);
2356 first_hfont = list_head(&child->font->hfontlist);
2357 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2358 DeleteObject(hfontlist->hfont);
2359 HeapFree(GetProcessHeap(), 0, hfontlist);
2360 free_font(child->font);
2362 HeapFree(GetProcessHeap(), 0, child->file_name);
2363 HeapFree(GetProcessHeap(), 0, child);
2366 if (font->ft_face) pFT_Done_Face(font->ft_face);
2367 if (font->mapping) unmap_font( font->mapping );
2368 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2369 HeapFree(GetProcessHeap(), 0, font->potm);
2370 HeapFree(GetProcessHeap(), 0, font->name);
2371 HeapFree(GetProcessHeap(), 0, font->gm);
2372 HeapFree(GetProcessHeap(), 0, font);
2376 /*************************************************************
2379 * load the vdmx entry for the specified height
2382 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2383 ( ( (FT_ULong)_x4 << 24 ) | \
2384 ( (FT_ULong)_x3 << 16 ) | \
2385 ( (FT_ULong)_x2 << 8 ) | \
2388 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2403 static LONG load_VDMX(GdiFont *font, LONG height)
2407 BYTE devXRatio, devYRatio;
2408 USHORT numRecs, numRatios;
2409 DWORD result, offset = -1;
2413 /* For documentation on VDMX records, see
2414 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2417 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2419 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2422 /* FIXME: need the real device aspect ratio */
2426 numRecs = GET_BE_WORD(hdr[1]);
2427 numRatios = GET_BE_WORD(hdr[2]);
2429 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2430 for(i = 0; i < numRatios; i++) {
2433 offset = (3 * 2) + (i * sizeof(Ratios));
2434 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2437 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2439 if((ratio.xRatio == 0 &&
2440 ratio.yStartRatio == 0 &&
2441 ratio.yEndRatio == 0) ||
2442 (devXRatio == ratio.xRatio &&
2443 devYRatio >= ratio.yStartRatio &&
2444 devYRatio <= ratio.yEndRatio))
2446 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2447 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2448 offset = GET_BE_WORD(tmp);
2454 FIXME("No suitable ratio found\n");
2458 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2460 BYTE startsz, endsz;
2463 recs = GET_BE_WORD(group.recs);
2464 startsz = group.startsz;
2465 endsz = group.endsz;
2467 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2469 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2470 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2471 if(result == GDI_ERROR) {
2472 FIXME("Failed to retrieve vTable\n");
2477 for(i = 0; i < recs; i++) {
2478 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2479 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2480 ppem = GET_BE_WORD(vTable[i * 3]);
2482 if(yMax + -yMin == height) {
2485 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2488 if(yMax + -yMin > height) {
2491 goto end; /* failed */
2493 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2494 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2495 ppem = GET_BE_WORD(vTable[i * 3]);
2496 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2502 TRACE("ppem not found for height %d\n", height);
2506 if(ppem < startsz || ppem > endsz)
2509 for(i = 0; i < recs; i++) {
2511 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2513 if(yPelHeight > ppem)
2516 if(yPelHeight == ppem) {
2517 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2518 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2519 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2525 HeapFree(GetProcessHeap(), 0, vTable);
2531 static BOOL fontcmp(GdiFont *font, FONT_DESC *fd)
2533 if(font->font_desc.hash != fd->hash) return TRUE;
2534 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2535 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2536 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2537 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2540 static void calc_hash(FONT_DESC *pfd)
2542 DWORD hash = 0, *ptr, two_chars;
2546 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2548 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2550 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2552 pwc = (WCHAR *)&two_chars;
2554 *pwc = toupperW(*pwc);
2556 *pwc = toupperW(*pwc);
2560 hash ^= !pfd->can_use_bitmap;
2565 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2570 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2572 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2573 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2574 fd.can_use_bitmap = can_use_bitmap;
2577 /* try the in-use list */
2578 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2579 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2580 if(!fontcmp(ret, &fd)) {
2581 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2582 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2583 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2584 if(hflist->hfont == hfont)
2587 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2588 hflist->hfont = hfont;
2589 list_add_head(&ret->hfontlist, &hflist->entry);
2594 /* then the unused list */
2595 font_elem_ptr = list_head(&unused_gdi_font_list);
2596 while(font_elem_ptr) {
2597 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2598 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2599 if(!fontcmp(ret, &fd)) {
2600 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2601 assert(list_empty(&ret->hfontlist));
2602 TRACE("Found %p in unused list\n", ret);
2603 list_remove(&ret->entry);
2604 list_add_head(&gdi_font_list, &ret->entry);
2605 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2606 hflist->hfont = hfont;
2607 list_add_head(&ret->hfontlist, &hflist->entry);
2615 /*************************************************************
2616 * create_child_font_list
2618 static BOOL create_child_font_list(GdiFont *font)
2621 SYSTEM_LINKS *font_link;
2622 CHILD_FONT *font_link_entry, *new_child;
2624 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2626 if(!strcmpW(font_link->font_name, font->name))
2628 TRACE("found entry in system list\n");
2629 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2631 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2632 new_child->file_name = strdupA(font_link_entry->file_name);
2633 new_child->index = font_link_entry->index;
2634 new_child->font = NULL;
2635 list_add_tail(&font->child_fonts, &new_child->entry);
2636 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
2646 /*************************************************************
2647 * WineEngCreateFontInstance
2650 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
2653 Face *face, *best, *best_bitmap;
2654 Family *family, *last_resort_family;
2655 struct list *family_elem_ptr, *face_elem_ptr;
2656 INT height, width = 0;
2657 unsigned int score = 0, new_score;
2658 signed int diff = 0, newdiff;
2659 BOOL bd, it, can_use_bitmap;
2664 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2666 struct list *first_hfont = list_head(&ret->hfontlist);
2667 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2668 if(hflist->hfont == hfont)
2672 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2673 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2675 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2676 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2677 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2680 /* check the cache first */
2681 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2682 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2686 TRACE("not in cache\n");
2687 if(list_empty(&font_list)) /* No fonts installed */
2689 TRACE("No fonts installed\n");
2692 if(!have_installed_roman_font)
2694 TRACE("No roman font installed\n");
2700 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2701 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2702 ret->font_desc.can_use_bitmap = can_use_bitmap;
2703 calc_hash(&ret->font_desc);
2704 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2705 hflist->hfont = hfont;
2706 list_add_head(&ret->hfontlist, &hflist->entry);
2709 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2710 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2711 original value lfCharSet. Note this is a special case for
2712 Symbol and doesn't happen at least for "Wingdings*" */
2714 if(!strcmpiW(lf.lfFaceName, SymbolW))
2715 lf.lfCharSet = SYMBOL_CHARSET;
2717 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2718 switch(lf.lfCharSet) {
2719 case DEFAULT_CHARSET:
2720 csi.fs.fsCsb[0] = 0;
2723 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2724 csi.fs.fsCsb[0] = 0;
2730 if(lf.lfFaceName[0] != '\0') {
2732 SYSTEM_LINKS *font_link;
2733 CHILD_FONT *font_link_entry;
2735 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2738 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2739 debugstr_w(psub->to.name));
2740 strcpyW(lf.lfFaceName, psub->to.name);
2743 /* We want a match on name and charset or just name if
2744 charset was DEFAULT_CHARSET. If the latter then
2745 we fixup the returned charset later in get_nearest_charset
2746 where we'll either use the charset of the current ansi codepage
2747 or if that's unavailable the first charset that the font supports.
2749 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2750 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2751 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2752 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2753 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2754 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2755 if(face->scalable || can_use_bitmap)
2762 * Try check the SystemLink list first for a replacement font.
2763 * We may find good replacements there.
2765 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2767 if(!strcmpiW(font_link->font_name, lf.lfFaceName))
2769 TRACE("found entry in system list\n");
2770 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2772 face = find_face_from_path_index(font_link_entry->file_name,
2773 font_link_entry->index);
2776 family = face->family;
2777 if(csi.fs.fsCsb[0] &
2778 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
2780 if(face->scalable || can_use_bitmap)
2789 /* If requested charset was DEFAULT_CHARSET then try using charset
2790 corresponding to the current ansi codepage */
2791 if(!csi.fs.fsCsb[0]) {
2793 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
2794 FIXME("TCI failed on codepage %d\n", acp);
2795 csi.fs.fsCsb[0] = 0;
2797 lf.lfCharSet = csi.ciCharset;
2800 /* Face families are in the top 4 bits of lfPitchAndFamily,
2801 so mask with 0xF0 before testing */
2803 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2804 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2805 strcpyW(lf.lfFaceName, defFixed);
2806 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2807 strcpyW(lf.lfFaceName, defSerif);
2808 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2809 strcpyW(lf.lfFaceName, defSans);
2811 strcpyW(lf.lfFaceName, defSans);
2812 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2813 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2814 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2815 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2816 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2817 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2818 if(face->scalable || can_use_bitmap)
2824 last_resort_family = NULL;
2825 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2826 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2827 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2828 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2829 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2832 if(can_use_bitmap && !last_resort_family)
2833 last_resort_family = family;
2838 if(last_resort_family) {
2839 family = last_resort_family;
2840 csi.fs.fsCsb[0] = 0;
2844 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2845 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2846 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2847 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2848 if(face->scalable) {
2849 csi.fs.fsCsb[0] = 0;
2850 WARN("just using first face for now\n");
2853 if(can_use_bitmap && !last_resort_family)
2854 last_resort_family = family;
2857 if(!last_resort_family) {
2858 FIXME("can't find a single appropriate font - bailing\n");
2863 WARN("could only find a bitmap font - this will probably look awful!\n");
2864 family = last_resort_family;
2865 csi.fs.fsCsb[0] = 0;
2868 it = lf.lfItalic ? 1 : 0;
2869 bd = lf.lfWeight > 550 ? 1 : 0;
2871 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2872 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2874 face = best = best_bitmap = NULL;
2875 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2877 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2879 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
2880 if(!best || new_score <= score)
2882 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
2883 face->Italic, face->Bold, it, bd);
2886 if(best->scalable && score == 0) break;
2890 newdiff = height - (signed int)(best->size.height);
2892 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
2893 if(!best_bitmap || new_score < score ||
2894 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
2896 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
2899 if(score == 0 && diff == 0) break;
2906 face = best->scalable ? best : best_bitmap;
2907 ret->fake_italic = (it && !face->Italic);
2908 ret->fake_bold = (bd && !face->Bold);
2910 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2912 if(csi.fs.fsCsb[0]) {
2913 ret->charset = lf.lfCharSet;
2914 ret->codepage = csi.ciACP;
2917 ret->charset = get_nearest_charset(face, &ret->codepage);
2919 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2920 debugstr_w(face->StyleName), face->file, face->face_index);
2922 if(!face->scalable) {
2923 width = face->size.x_ppem >> 6;
2924 height = face->size.y_ppem >> 6;
2926 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2934 if (ret->charset == SYMBOL_CHARSET &&
2935 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2938 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2942 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2945 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2946 ret->name = strdupW(family->FamilyName);
2947 ret->underline = lf.lfUnderline ? 0xff : 0;
2948 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2949 create_child_font_list(ret);
2951 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2953 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? abs(lf.lfWidth) : 0;
2954 list_add_head(&gdi_font_list, &ret->entry);
2958 static void dump_gdi_font_list(void)
2961 struct list *elem_ptr;
2963 TRACE("---------- gdiFont Cache ----------\n");
2964 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2965 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2966 TRACE("gdiFont=%p %s %d\n",
2967 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2970 TRACE("---------- Unused gdiFont Cache ----------\n");
2971 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2972 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2973 TRACE("gdiFont=%p %s %d\n",
2974 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2978 /*************************************************************
2979 * WineEngDestroyFontInstance
2981 * free the gdiFont associated with this handle
2984 BOOL WineEngDestroyFontInstance(HFONT handle)
2989 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2992 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
2994 struct list *first_hfont = list_head(&gdiFont->hfontlist);
2995 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2996 if(hflist->hfont == handle)
2998 TRACE("removing child font %p from child list\n", gdiFont);
2999 list_remove(&gdiFont->entry);
3004 TRACE("destroying hfont=%p\n", handle);
3006 dump_gdi_font_list();
3008 font_elem_ptr = list_head(&gdi_font_list);
3009 while(font_elem_ptr) {
3010 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3011 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3013 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3014 while(hfontlist_elem_ptr) {
3015 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3016 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3017 if(hflist->hfont == handle) {
3018 list_remove(&hflist->entry);
3019 HeapFree(GetProcessHeap(), 0, hflist);
3023 if(list_empty(&gdiFont->hfontlist)) {
3024 TRACE("Moving to Unused list\n");
3025 list_remove(&gdiFont->entry);
3026 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3031 font_elem_ptr = list_head(&unused_gdi_font_list);
3032 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3033 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3034 while(font_elem_ptr) {
3035 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3036 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3037 TRACE("freeing %p\n", gdiFont);
3038 list_remove(&gdiFont->entry);
3044 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3045 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3047 OUTLINETEXTMETRICW *potm = NULL;
3049 TEXTMETRICW tm, *ptm;
3050 GdiFont *font = alloc_font();
3053 if(face->scalable) {
3057 height = face->size.y_ppem >> 6;
3058 width = face->size.x_ppem >> 6;
3061 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
3067 font->name = strdupW(face->family->FamilyName);
3069 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
3071 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
3073 potm = HeapAlloc(GetProcessHeap(), 0, size);
3074 WineEngGetOutlineTextMetrics(font, size, potm);
3075 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
3077 WineEngGetTextMetrics(font, &tm);
3081 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
3082 pntm->ntmTm.tmAscent = ptm->tmAscent;
3083 pntm->ntmTm.tmDescent = ptm->tmDescent;
3084 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
3085 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
3086 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
3087 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
3088 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
3089 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
3090 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
3091 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
3092 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
3093 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
3094 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
3095 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
3096 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
3097 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
3098 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
3099 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
3100 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
3101 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
3102 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3103 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3104 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3106 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
3107 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
3108 *ptype |= RASTER_FONTTYPE;
3110 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
3111 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
3112 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
3114 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3115 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3116 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
3119 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
3121 lstrcpynW(pelf->elfLogFont.lfFaceName,
3122 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
3124 lstrcpynW(pelf->elfFullName,
3125 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
3127 lstrcpynW(pelf->elfStyle,
3128 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
3131 HeapFree(GetProcessHeap(), 0, potm);
3133 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3135 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3136 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
3137 pelf->elfStyle[0] = '\0';
3140 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3145 /*************************************************************
3149 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3153 struct list *family_elem_ptr, *face_elem_ptr;
3155 NEWTEXTMETRICEXW ntm;
3156 DWORD type, ret = 1;
3162 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3164 if(plf->lfFaceName[0]) {
3166 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3169 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3170 debugstr_w(psub->to.name));
3171 memcpy(&lf, plf, sizeof(lf));
3172 strcpyW(lf.lfFaceName, psub->to.name);
3176 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3177 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3178 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3179 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3180 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3181 GetEnumStructs(face, &elf, &ntm, &type);
3182 for(i = 0; i < 32; i++) {
3183 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3184 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3185 strcpyW(elf.elfScript, OEM_DOSW);
3186 i = 32; /* break out of loop */
3187 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3190 fs.fsCsb[0] = 1L << i;
3192 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3194 csi.ciCharset = DEFAULT_CHARSET;
3195 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3196 if(csi.ciCharset != DEFAULT_CHARSET) {
3197 elf.elfLogFont.lfCharSet =
3198 ntm.ntmTm.tmCharSet = csi.ciCharset;
3200 strcpyW(elf.elfScript, ElfScriptsW[i]);
3202 FIXME("Unknown elfscript for bit %d\n", i);
3205 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3206 debugstr_w(elf.elfLogFont.lfFaceName),
3207 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3208 csi.ciCharset, type, debugstr_w(elf.elfScript),
3209 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3210 ntm.ntmTm.ntmFlags);
3211 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3218 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3219 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3220 face_elem_ptr = list_head(&family->faces);
3221 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3222 GetEnumStructs(face, &elf, &ntm, &type);
3223 for(i = 0; i < 32; i++) {
3224 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3225 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3226 strcpyW(elf.elfScript, OEM_DOSW);
3227 i = 32; /* break out of loop */
3228 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3231 fs.fsCsb[0] = 1L << i;
3233 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3235 csi.ciCharset = DEFAULT_CHARSET;
3236 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3237 if(csi.ciCharset != DEFAULT_CHARSET) {
3238 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3241 strcpyW(elf.elfScript, ElfScriptsW[i]);
3243 FIXME("Unknown elfscript for bit %d\n", i);
3246 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3247 debugstr_w(elf.elfLogFont.lfFaceName),
3248 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3249 csi.ciCharset, type, debugstr_w(elf.elfScript),
3250 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3251 ntm.ntmTm.ntmFlags);
3252 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3261 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3263 pt->x.value = vec->x >> 6;
3264 pt->x.fract = (vec->x & 0x3f) << 10;
3265 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3266 pt->y.value = vec->y >> 6;
3267 pt->y.fract = (vec->y & 0x3f) << 10;
3268 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3272 /***************************************************
3273 * According to the MSDN documentation on WideCharToMultiByte,
3274 * certain codepages cannot set the default_used parameter.
3275 * This returns TRUE if the codepage can set that parameter, false else
3276 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3278 static BOOL codepage_sets_default_used(UINT codepage)
3291 static FT_UInt get_glyph_index(GdiFont *font, UINT glyph)
3293 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
3294 WCHAR wc = (WCHAR)glyph;
3296 BOOL *default_used_pointer;
3299 default_used_pointer = NULL;
3300 default_used = FALSE;
3301 if (codepage_sets_default_used(font->codepage))
3302 default_used_pointer = &default_used;
3303 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
3306 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
3307 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
3311 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
3312 glyph = glyph + 0xf000;
3313 return pFT_Get_Char_Index(font->ft_face, glyph);
3316 /*************************************************************
3317 * WineEngGetGlyphIndices
3319 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3321 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
3322 LPWORD pgi, DWORD flags)
3325 WCHAR default_char = 0;
3328 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
3330 for(i = 0; i < count; i++)
3332 pgi[i] = get_glyph_index(font, lpstr[i]);
3337 WineEngGetTextMetrics(font, &textm);
3338 default_char = textm.tmDefaultChar;
3340 pgi[i] = default_char;
3346 /*************************************************************
3347 * WineEngGetGlyphOutline
3349 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3350 * except that the first parameter is the HWINEENGFONT of the font in
3351 * question rather than an HDC.
3354 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
3355 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3358 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3359 FT_Face ft_face = incoming_font->ft_face;
3360 GdiFont *font = incoming_font;
3361 FT_UInt glyph_index;
3362 DWORD width, height, pitch, needed = 0;
3363 FT_Bitmap ft_bitmap;
3365 INT left, right, top = 0, bottom = 0;
3367 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3368 float widthRatio = 1.0;
3369 FT_Matrix transMat = identityMat;
3370 BOOL needsTransform = FALSE;
3373 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
3374 buflen, buf, lpmat);
3376 if(format & GGO_GLYPH_INDEX) {
3377 glyph_index = glyph;
3378 format &= ~GGO_GLYPH_INDEX;
3380 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
3381 ft_face = font->ft_face;
3384 if(glyph_index >= font->gmsize) {
3385 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
3386 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
3387 font->gmsize * sizeof(*font->gm));
3389 if(format == GGO_METRICS && font->gm[glyph_index].init) {
3390 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
3391 return 1; /* FIXME */
3395 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
3396 load_flags |= FT_LOAD_NO_BITMAP;
3398 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
3401 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
3405 /* Scaling factor */
3406 if (font->aveWidth && font->potm) {
3407 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
3410 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3411 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3413 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3414 font->gm[glyph_index].lsb = left >> 6;
3415 font->gm[glyph_index].bbx = (right - left) >> 6;
3417 /* Scaling transform */
3418 if(font->aveWidth) {
3420 scaleMat.xx = FT_FixedFromFloat(widthRatio);
3423 scaleMat.yy = (1 << 16);
3425 pFT_Matrix_Multiply(&scaleMat, &transMat);
3426 needsTransform = TRUE;
3429 /* Slant transform */
3430 if (font->fake_italic) {
3433 slantMat.xx = (1 << 16);
3434 slantMat.xy = ((1 << 16) >> 2);
3436 slantMat.yy = (1 << 16);
3437 pFT_Matrix_Multiply(&slantMat, &transMat);
3438 needsTransform = TRUE;
3441 /* Rotation transform */
3442 if(font->orientation) {
3443 FT_Matrix rotationMat;
3445 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3446 pFT_Vector_Unit(&vecAngle, angle);
3447 rotationMat.xx = vecAngle.x;
3448 rotationMat.xy = -vecAngle.y;
3449 rotationMat.yx = -rotationMat.xy;
3450 rotationMat.yy = rotationMat.xx;
3452 pFT_Matrix_Multiply(&rotationMat, &transMat);
3453 needsTransform = TRUE;
3456 /* Extra transformation specified by caller */
3459 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3460 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3461 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3462 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3463 pFT_Matrix_Multiply(&extraMat, &transMat);
3464 needsTransform = TRUE;
3467 if(!needsTransform) {
3468 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3469 bottom = (ft_face->glyph->metrics.horiBearingY -
3470 ft_face->glyph->metrics.height) & -64;
3471 lpgm->gmCellIncX = font->gm[glyph_index].adv;
3472 lpgm->gmCellIncY = 0;
3476 for(xc = 0; xc < 2; xc++) {
3477 for(yc = 0; yc < 2; yc++) {
3478 vec.x = (ft_face->glyph->metrics.horiBearingX +
3479 xc * ft_face->glyph->metrics.width);
3480 vec.y = ft_face->glyph->metrics.horiBearingY -
3481 yc * ft_face->glyph->metrics.height;
3482 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3483 pFT_Vector_Transform(&vec, &transMat);
3484 if(xc == 0 && yc == 0) {
3485 left = right = vec.x;
3486 top = bottom = vec.y;
3488 if(vec.x < left) left = vec.x;
3489 else if(vec.x > right) right = vec.x;
3490 if(vec.y < bottom) bottom = vec.y;
3491 else if(vec.y > top) top = vec.y;
3496 right = (right + 63) & -64;
3497 bottom = bottom & -64;
3498 top = (top + 63) & -64;
3500 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3501 vec.x = ft_face->glyph->metrics.horiAdvance;
3503 pFT_Vector_Transform(&vec, &transMat);
3504 lpgm->gmCellIncX = (vec.x+63) >> 6;
3505 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3507 lpgm->gmBlackBoxX = (right - left) >> 6;
3508 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3509 lpgm->gmptGlyphOrigin.x = left >> 6;
3510 lpgm->gmptGlyphOrigin.y = top >> 6;
3512 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
3513 font->gm[glyph_index].init = TRUE;
3515 if(format == GGO_METRICS)
3516 return 1; /* FIXME */
3518 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
3519 TRACE("loaded a bitmap\n");
3525 width = lpgm->gmBlackBoxX;
3526 height = lpgm->gmBlackBoxY;
3527 pitch = ((width + 31) >> 5) << 2;
3528 needed = pitch * height;
3530 if(!buf || !buflen) break;
3532 switch(ft_face->glyph->format) {
3533 case ft_glyph_format_bitmap:
3535 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3536 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3537 INT h = ft_face->glyph->bitmap.rows;
3539 memcpy(dst, src, w);
3540 src += ft_face->glyph->bitmap.pitch;
3546 case ft_glyph_format_outline:
3547 ft_bitmap.width = width;
3548 ft_bitmap.rows = height;
3549 ft_bitmap.pitch = pitch;
3550 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3551 ft_bitmap.buffer = buf;
3553 if(needsTransform) {
3554 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3557 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3559 /* Note: FreeType will only set 'black' bits for us. */
3560 memset(buf, 0, needed);
3561 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3565 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3570 case GGO_GRAY2_BITMAP:
3571 case GGO_GRAY4_BITMAP:
3572 case GGO_GRAY8_BITMAP:
3573 case WINE_GGO_GRAY16_BITMAP:
3575 unsigned int mult, row, col;
3578 width = lpgm->gmBlackBoxX;
3579 height = lpgm->gmBlackBoxY;
3580 pitch = (width + 3) / 4 * 4;
3581 needed = pitch * height;
3583 if(!buf || !buflen) break;
3584 ft_bitmap.width = width;
3585 ft_bitmap.rows = height;
3586 ft_bitmap.pitch = pitch;
3587 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3588 ft_bitmap.buffer = buf;
3590 if(needsTransform) {
3591 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3594 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3596 memset(ft_bitmap.buffer, 0, buflen);
3598 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3600 if(format == GGO_GRAY2_BITMAP)
3602 else if(format == GGO_GRAY4_BITMAP)
3604 else if(format == GGO_GRAY8_BITMAP)
3606 else if(format == WINE_GGO_GRAY16_BITMAP)
3614 for(row = 0; row < height; row++) {
3616 for(col = 0; col < width; col++, ptr++) {
3617 *ptr = (((int)*ptr) * mult + 128) / 256;
3626 int contour, point = 0, first_pt;
3627 FT_Outline *outline = &ft_face->glyph->outline;
3628 TTPOLYGONHEADER *pph;
3630 DWORD pph_start, cpfx, type;
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_QSPLINE;
3655 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3658 } while(point <= outline->contours[contour] &&
3659 (outline->tags[point] & FT_Curve_Tag_On) ==
3660 (outline->tags[point-1] & FT_Curve_Tag_On));
3661 /* At the end of a contour Windows adds the start point, but
3663 if(point > outline->contours[contour] &&
3664 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3666 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3668 } else if(point <= outline->contours[contour] &&
3669 outline->tags[point] & FT_Curve_Tag_On) {
3670 /* add closing pt for bezier */
3672 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3680 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3683 pph->cb = needed - pph_start;
3689 /* Convert the quadratic Beziers to cubic Beziers.
3690 The parametric eqn for a cubic Bezier is, from PLRM:
3691 r(t) = at^3 + bt^2 + ct + r0
3692 with the control points:
3697 A quadratic Beizer has the form:
3698 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3700 So equating powers of t leads to:
3701 r1 = 2/3 p1 + 1/3 p0
3702 r2 = 2/3 p1 + 1/3 p2
3703 and of course r0 = p0, r3 = p2
3706 int contour, point = 0, first_pt;
3707 FT_Outline *outline = &ft_face->glyph->outline;
3708 TTPOLYGONHEADER *pph;
3710 DWORD pph_start, cpfx, type;
3711 FT_Vector cubic_control[4];
3712 if(buflen == 0) buf = NULL;
3714 if (needsTransform && buf) {
3715 pFT_Outline_Transform(outline, &transMat);
3718 for(contour = 0; contour < outline->n_contours; contour++) {
3720 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3723 pph->dwType = TT_POLYGON_TYPE;
3724 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3726 needed += sizeof(*pph);
3728 while(point <= outline->contours[contour]) {
3729 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3730 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3731 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3734 if(type == TT_PRIM_LINE) {
3736 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3740 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3743 /* FIXME: Possible optimization in endpoint calculation
3744 if there are two consecutive curves */
3745 cubic_control[0] = outline->points[point-1];
3746 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3747 cubic_control[0].x += outline->points[point].x + 1;
3748 cubic_control[0].y += outline->points[point].y + 1;
3749 cubic_control[0].x >>= 1;
3750 cubic_control[0].y >>= 1;
3752 if(point+1 > outline->contours[contour])
3753 cubic_control[3] = outline->points[first_pt];
3755 cubic_control[3] = outline->points[point+1];
3756 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3757 cubic_control[3].x += outline->points[point].x + 1;
3758 cubic_control[3].y += outline->points[point].y + 1;
3759 cubic_control[3].x >>= 1;
3760 cubic_control[3].y >>= 1;
3763 /* r1 = 1/3 p0 + 2/3 p1
3764 r2 = 1/3 p2 + 2/3 p1 */
3765 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3766 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3767 cubic_control[2] = cubic_control[1];
3768 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3769 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3770 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3771 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3773 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3774 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3775 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3780 } while(point <= outline->contours[contour] &&
3781 (outline->tags[point] & FT_Curve_Tag_On) ==
3782 (outline->tags[point-1] & FT_Curve_Tag_On));
3783 /* At the end of a contour Windows adds the start point,
3784 but only for Beziers and we've already done that.
3786 if(point <= outline->contours[contour] &&
3787 outline->tags[point] & FT_Curve_Tag_On) {
3788 /* This is the closing pt of a bezier, but we've already
3789 added it, so just inc point and carry on */
3796 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3799 pph->cb = needed - pph_start;
3805 FIXME("Unsupported format %d\n", format);
3811 static BOOL get_bitmap_text_metrics(GdiFont *font)
3813 FT_Face ft_face = font->ft_face;
3814 #ifdef HAVE_FREETYPE_FTWINFNT_H
3815 FT_WinFNT_HeaderRec winfnt_header;
3817 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3818 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3819 font->potm->otmSize = size;
3821 #define TM font->potm->otmTextMetrics
3822 #ifdef HAVE_FREETYPE_FTWINFNT_H
3823 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3825 TM.tmHeight = winfnt_header.pixel_height;
3826 TM.tmAscent = winfnt_header.ascent;
3827 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3828 TM.tmInternalLeading = winfnt_header.internal_leading;
3829 TM.tmExternalLeading = winfnt_header.external_leading;
3830 TM.tmAveCharWidth = winfnt_header.avg_width;
3831 TM.tmMaxCharWidth = winfnt_header.max_width;
3832 TM.tmWeight = winfnt_header.weight;
3834 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3835 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3836 TM.tmFirstChar = winfnt_header.first_char;
3837 TM.tmLastChar = winfnt_header.last_char;
3838 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3839 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3840 TM.tmItalic = winfnt_header.italic;
3841 TM.tmUnderlined = font->underline;
3842 TM.tmStruckOut = font->strikeout;
3843 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3844 TM.tmCharSet = winfnt_header.charset;
3849 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3850 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3851 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3852 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3853 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3854 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3855 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3856 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3858 TM.tmDigitizedAspectX = 96; /* FIXME */
3859 TM.tmDigitizedAspectY = 96; /* FIXME */
3861 TM.tmLastChar = 255;
3862 TM.tmDefaultChar = 32;
3863 TM.tmBreakChar = 32;
3864 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3865 TM.tmUnderlined = font->underline;
3866 TM.tmStruckOut = font->strikeout;
3867 /* NB inverted meaning of TMPF_FIXED_PITCH */
3868 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3869 TM.tmCharSet = font->charset;
3876 /*************************************************************
3877 * WineEngGetTextMetrics
3880 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
3883 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3884 if(!get_bitmap_text_metrics(font))
3887 if(!font->potm) return FALSE;
3888 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3890 if (font->aveWidth) {
3891 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3897 /*************************************************************
3898 * WineEngGetOutlineTextMetrics
3901 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
3902 OUTLINETEXTMETRICW *potm)
3904 FT_Face ft_face = font->ft_face;
3905 UINT needed, lenfam, lensty, ret;
3907 TT_HoriHeader *pHori;
3908 TT_Postscript *pPost;
3909 FT_Fixed x_scale, y_scale;
3910 WCHAR *family_nameW, *style_nameW;
3911 static const WCHAR spaceW[] = {' ', '\0'};
3913 INT ascent, descent;
3915 TRACE("font=%p\n", font);
3917 if(!FT_IS_SCALABLE(ft_face))
3921 if(cbSize >= font->potm->otmSize)
3922 memcpy(potm, font->potm, font->potm->otmSize);
3923 return font->potm->otmSize;
3927 needed = sizeof(*potm);
3929 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3930 family_nameW = strdupW(font->name);
3932 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3934 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3935 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3936 style_nameW, lensty/sizeof(WCHAR));
3938 /* These names should be read from the TT name table */
3940 /* length of otmpFamilyName */
3943 /* length of otmpFaceName */
3944 if(!strcasecmp(ft_face->style_name, "regular")) {
3945 needed += lenfam; /* just the family name */
3947 needed += lenfam + lensty; /* family + " " + style */
3950 /* length of otmpStyleName */
3953 /* length of otmpFullName */
3954 needed += lenfam + lensty;
3957 x_scale = ft_face->size->metrics.x_scale;
3958 y_scale = ft_face->size->metrics.y_scale;
3960 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3962 FIXME("Can't find OS/2 table - not TT font?\n");
3967 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3969 FIXME("Can't find HHEA table - not TT font?\n");
3974 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3976 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",
3977 pOS2->usWinAscent, pOS2->usWinDescent,
3978 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3979 ft_face->ascender, ft_face->descender, ft_face->height,
3980 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3981 ft_face->bbox.yMax, ft_face->bbox.yMin);
3983 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3984 font->potm->otmSize = needed;
3986 #define TM font->potm->otmTextMetrics
3988 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3989 ascent = pHori->Ascender;
3990 descent = -pHori->Descender;
3992 ascent = pOS2->usWinAscent;
3993 descent = pOS2->usWinDescent;
3997 TM.tmAscent = font->yMax;
3998 TM.tmDescent = -font->yMin;
3999 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
4001 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
4002 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
4003 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
4004 - ft_face->units_per_EM, y_scale) + 32) >> 6;
4007 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4010 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4012 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
4013 ((ascent + descent) -
4014 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
4016 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
4017 if (TM.tmAveCharWidth == 0) {
4018 TM.tmAveCharWidth = 1;
4020 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
4021 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
4023 TM.tmDigitizedAspectX = 300;
4024 TM.tmDigitizedAspectY = 300;
4025 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4026 * symbol range to 0 - f0ff
4028 if (font->charset == SYMBOL_CHARSET)
4031 TM.tmFirstChar = pOS2->usFirstCharIndex;
4032 TM.tmLastChar = pOS2->usLastCharIndex;
4033 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4034 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
4035 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4036 TM.tmUnderlined = font->underline;
4037 TM.tmStruckOut = font->strikeout;
4039 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4040 if(!FT_IS_FIXED_WIDTH(ft_face) &&
4041 (pOS2->version == 0xFFFFU ||
4042 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4043 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
4045 TM.tmPitchAndFamily = 0;
4047 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
4048 case PAN_FAMILY_SCRIPT:
4049 TM.tmPitchAndFamily |= FF_SCRIPT;
4051 case PAN_FAMILY_DECORATIVE:
4052 case PAN_FAMILY_PICTORIAL:
4053 TM.tmPitchAndFamily |= FF_DECORATIVE;
4055 case PAN_FAMILY_TEXT_DISPLAY:
4056 if(TM.tmPitchAndFamily == 0) /* fixed */
4057 TM.tmPitchAndFamily = FF_MODERN;
4059 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
4060 case PAN_SERIF_NORMAL_SANS:
4061 case PAN_SERIF_OBTUSE_SANS:
4062 case PAN_SERIF_PERP_SANS:
4063 TM.tmPitchAndFamily |= FF_SWISS;
4066 TM.tmPitchAndFamily |= FF_ROMAN;
4071 TM.tmPitchAndFamily |= FF_DONTCARE;
4074 if(FT_IS_SCALABLE(ft_face))
4075 TM.tmPitchAndFamily |= TMPF_VECTOR;
4076 if(FT_IS_SFNT(ft_face))
4077 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
4079 TM.tmCharSet = font->charset;
4082 font->potm->otmFiller = 0;
4083 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
4084 font->potm->otmfsSelection = pOS2->fsSelection;
4085 font->potm->otmfsType = pOS2->fsType;
4086 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
4087 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
4088 font->potm->otmItalicAngle = 0; /* POST table */
4089 font->potm->otmEMSquare = ft_face->units_per_EM;
4090 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
4091 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4092 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4093 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
4094 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4095 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
4096 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
4097 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
4098 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4099 font->potm->otmMacAscent = 0; /* where do these come from ? */
4100 font->potm->otmMacDescent = 0;
4101 font->potm->otmMacLineGap = 0;
4102 font->potm->otmusMinimumPPEM = 0; /* TT Header */
4103 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
4104 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
4105 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
4106 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
4107 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
4108 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
4109 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
4110 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
4111 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
4112 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4114 font->potm->otmsUnderscoreSize = 0;
4115 font->potm->otmsUnderscorePosition = 0;
4117 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
4118 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
4121 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4122 cp = (char*)font->potm + sizeof(*font->potm);
4123 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4124 strcpyW((WCHAR*)cp, family_nameW);
4126 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4127 strcpyW((WCHAR*)cp, style_nameW);
4129 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4130 strcpyW((WCHAR*)cp, family_nameW);
4131 if(strcasecmp(ft_face->style_name, "regular")) {
4132 strcatW((WCHAR*)cp, spaceW);
4133 strcatW((WCHAR*)cp, style_nameW);
4134 cp += lenfam + lensty;
4137 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
4138 strcpyW((WCHAR*)cp, family_nameW);
4139 strcatW((WCHAR*)cp, spaceW);
4140 strcatW((WCHAR*)cp, style_nameW);
4143 if(potm && needed <= cbSize)
4144 memcpy(potm, font->potm, font->potm->otmSize);
4147 HeapFree(GetProcessHeap(), 0, style_nameW);
4148 HeapFree(GetProcessHeap(), 0, family_nameW);
4153 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
4155 HFONTLIST *hfontlist;
4156 child->font = alloc_font();
4157 child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem);
4158 if(!child->font->ft_face)
4160 free_font(child->font);
4165 child->font->orientation = font->orientation;
4166 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
4167 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
4168 list_add_head(&child->font->hfontlist, &hfontlist->entry);
4169 child->font->base_font = font;
4170 list_add_head(&child_font_list, &child->font->entry);
4171 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
4175 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
4178 CHILD_FONT *child_font;
4181 font = font->base_font;
4183 *linked_font = font;
4185 if((*glyph = get_glyph_index(font, c)))
4188 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
4190 if(!child_font->font)
4191 if(!load_child_font(font, child_font))
4194 if(!child_font->font->ft_face)
4196 g = get_glyph_index(child_font->font, c);
4200 *linked_font = child_font->font;
4207 /*************************************************************
4208 * WineEngGetCharWidth
4211 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4216 FT_UInt glyph_index;
4217 GdiFont *linked_font;
4219 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4221 for(c = firstChar; c <= lastChar; c++) {
4222 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4223 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4224 &gm, 0, NULL, NULL);
4225 buffer[c - firstChar] = linked_font->gm[glyph_index].adv;
4230 /*************************************************************
4231 * WineEngGetCharABCWidths
4234 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4239 FT_UInt glyph_index;
4240 GdiFont *linked_font;
4242 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4244 if(!FT_IS_SCALABLE(font->ft_face))
4247 for(c = firstChar; c <= lastChar; c++) {
4248 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4249 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4250 &gm, 0, NULL, NULL);
4251 buffer[c - firstChar].abcA = linked_font->gm[glyph_index].lsb;
4252 buffer[c - firstChar].abcB = linked_font->gm[glyph_index].bbx;
4253 buffer[c - firstChar].abcC = linked_font->gm[glyph_index].adv - linked_font->gm[glyph_index].lsb -
4254 linked_font->gm[glyph_index].bbx;
4259 /*************************************************************
4260 * WineEngGetCharABCWidthsI
4263 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4268 FT_UInt glyph_index;
4269 GdiFont *linked_font;
4271 if(!FT_IS_SCALABLE(font->ft_face))
4274 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
4276 for(c = firstChar; c < firstChar+count; c++) {
4277 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
4278 &gm, 0, NULL, NULL);
4279 buffer[c - firstChar].abcA = linked_font->gm[c].lsb;
4280 buffer[c - firstChar].abcB = linked_font->gm[c].bbx;
4281 buffer[c - firstChar].abcC = linked_font->gm[c].adv - linked_font->gm[c].lsb
4282 - linked_font->gm[c].bbx;
4285 for(c = 0; c < count; c++) {
4286 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
4287 &gm, 0, NULL, NULL);
4288 buffer[c].abcA = linked_font->gm[pgi[c]].lsb;
4289 buffer[c].abcB = linked_font->gm[pgi[c]].bbx;
4290 buffer[c].abcC = linked_font->gm[pgi[c]].adv
4291 - linked_font->gm[pgi[c]].lsb - linked_font->gm[pgi[c]].bbx;
4297 /*************************************************************
4298 * WineEngGetTextExtentExPoint
4301 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4302 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4308 FT_UInt glyph_index;
4309 GdiFont *linked_font;
4311 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
4315 WineEngGetTextMetrics(font, &tm);
4316 size->cy = tm.tmHeight;
4318 for(idx = 0; idx < count; idx++) {
4319 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
4320 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4321 &gm, 0, NULL, NULL);
4322 size->cx += linked_font->gm[glyph_index].adv;
4324 if (! pnfit || ext <= max_ext) {
4334 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4338 /*************************************************************
4339 * WineEngGetTextExtentPointI
4342 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4349 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
4352 WineEngGetTextMetrics(font, &tm);
4353 size->cy = tm.tmHeight;
4355 for(idx = 0; idx < count; idx++) {
4356 WineEngGetGlyphOutline(font, indices[idx],
4357 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
4359 size->cx += font->gm[indices[idx]].adv;
4361 TRACE("return %d,%d\n", size->cx, size->cy);
4365 /*************************************************************
4366 * WineEngGetFontData
4369 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4372 FT_Face ft_face = font->ft_face;
4376 TRACE("font=%p, table=%08x, offset=%08x, buf=%p, cbData=%x\n",
4377 font, table, offset, buf, cbData);
4379 if(!FT_IS_SFNT(ft_face))
4387 if(table) { /* MS tags differ in endidness from FT ones */
4388 table = table >> 24 | table << 24 |
4389 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
4392 /* If the FT_Load_Sfnt_Table function is there we'll use it */
4393 if(pFT_Load_Sfnt_Table) {
4394 /* make sure value of len is the value freetype says it needs */
4396 FT_ULong needed = 0;
4397 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4398 if( !err && needed < len) len = needed;
4400 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4402 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
4403 else { /* Do it the hard way */
4404 TT_Face tt_face = (TT_Face) ft_face;
4405 SFNT_Interface *sfnt;
4406 if (FT_Version.major==2 && FT_Version.minor==0)
4409 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
4413 /* A field was added in the middle of the structure in 2.1.x */
4414 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
4416 /* make sure value of len is the value freetype says it needs */
4418 FT_ULong needed = 0;
4419 err = sfnt->load_any(tt_face, table, offset, NULL, &needed);
4420 if( !err && needed < len) len = needed;
4422 err = sfnt->load_any(tt_face, table, offset, buf, &len);
4428 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
4429 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
4430 "Please upgrade your freetype library.\n");
4433 err = FT_Err_Unimplemented_Feature;
4437 TRACE("Can't find table %08x.\n", table);
4443 /*************************************************************
4444 * WineEngGetTextFace
4447 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4450 lstrcpynW(str, font->name, count);
4451 return strlenW(font->name);
4453 return strlenW(font->name) + 1;
4456 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4458 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4459 return font->charset;
4462 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4464 GdiFont *font = dc->gdiFont, *linked_font;
4465 struct list *first_hfont;
4468 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4469 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4470 if(font == linked_font)
4471 *new_hfont = dc->hFont;
4474 first_hfont = list_head(&linked_font->hfontlist);
4475 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4481 /* Retrieve a list of supported Unicode ranges for a given font.
4482 * Can be called with NULL gs to calculate the buffer size. Returns
4483 * the number of ranges found.
4485 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
4487 DWORD num_ranges = 0;
4489 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4492 FT_ULong char_code, char_code_prev;
4495 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
4497 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4498 face->num_glyphs, glyph_code, char_code);
4500 if (!glyph_code) return 0;
4504 gs->ranges[0].wcLow = (USHORT)char_code;
4505 gs->ranges[0].cGlyphs = 0;
4506 gs->cGlyphsSupported = 0;
4512 if (char_code < char_code_prev)
4514 ERR("expected increasing char code from FT_Get_Next_Char\n");
4517 if (char_code - char_code_prev > 1)
4522 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4523 gs->ranges[num_ranges - 1].cGlyphs = 1;
4524 gs->cGlyphsSupported++;
4529 gs->ranges[num_ranges - 1].cGlyphs++;
4530 gs->cGlyphsSupported++;
4532 char_code_prev = char_code;
4533 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
4537 FIXME("encoding %u not supported\n", face->charmap->encoding);
4542 DWORD WineEngGetFontUnicodeRanges(HDC hdc, LPGLYPHSET glyphset)
4545 DC *dc = DC_GetDCPtr(hdc);
4547 TRACE("(%p, %p)\n", hdc, glyphset);
4553 DWORD num_ranges = get_font_unicode_ranges(dc->gdiFont->ft_face, glyphset);
4555 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
4558 glyphset->cbThis = size;
4559 glyphset->cRanges = num_ranges;
4563 GDI_ReleaseObj(hdc);
4567 /*************************************************************
4570 BOOL WINAPI FontIsLinked(HDC hdc)
4572 DC *dc = DC_GetDCPtr(hdc);
4575 if(!dc) return FALSE;
4576 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
4578 GDI_ReleaseObj(hdc);
4579 TRACE("returning %d\n", ret);
4583 static BOOL is_hinting_enabled(void)
4585 /* Use the >= 2.2.0 function if available */
4586 if(pFT_Get_TrueType_Engine_Type)
4588 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4589 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4591 #ifdef FT_DRIVER_HAS_HINTER
4596 /* otherwise if we've been compiled with < 2.2.0 headers
4597 use the internal macro */
4598 mod = pFT_Get_Module(library, "truetype");
4599 if(mod && FT_DRIVER_HAS_HINTER(mod))
4607 /*************************************************************************
4608 * GetRasterizerCaps (GDI32.@)
4610 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4612 static int hinting = -1;
4616 hinting = is_hinting_enabled();
4617 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
4620 lprs->nSize = sizeof(RASTERIZER_STATUS);
4621 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4622 lprs->nLanguageID = 0;
4626 /*************************************************************************
4627 * Kerning support for TrueType fonts
4629 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4631 struct TT_kern_table
4637 struct TT_kern_subtable
4646 USHORT horizontal : 1;
4648 USHORT cross_stream: 1;
4649 USHORT override : 1;
4650 USHORT reserved1 : 4;
4656 struct TT_format0_kern_subtable
4660 USHORT entrySelector;
4671 static DWORD parse_format0_kern_subtable(GdiFont *font,
4672 const struct TT_format0_kern_subtable *tt_f0_ks,
4673 const USHORT *glyph_to_char,
4674 KERNINGPAIR *kern_pair, DWORD cPairs)
4677 const struct TT_kern_pair *tt_kern_pair;
4679 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
4681 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4683 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4684 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4685 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4687 if (!kern_pair || !cPairs)
4690 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4692 nPairs = min(nPairs, cPairs);
4694 for (i = 0; i < nPairs; i++)
4696 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4697 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4698 /* this algorithm appears to better match what Windows does */
4699 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4700 if (kern_pair->iKernAmount < 0)
4702 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
4703 kern_pair->iKernAmount -= font->ppem;
4705 else if (kern_pair->iKernAmount > 0)
4707 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
4708 kern_pair->iKernAmount += font->ppem;
4710 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
4712 TRACE("left %u right %u value %d\n",
4713 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
4717 TRACE("copied %u entries\n", nPairs);
4721 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4725 const struct TT_kern_table *tt_kern_table;
4726 const struct TT_kern_subtable *tt_kern_subtable;
4728 USHORT *glyph_to_char;
4730 if (font->total_kern_pairs != (DWORD)-1)
4732 if (cPairs && kern_pair)
4734 cPairs = min(cPairs, font->total_kern_pairs);
4735 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4738 return font->total_kern_pairs;
4741 font->total_kern_pairs = 0;
4743 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
4745 if (length == GDI_ERROR)
4747 TRACE("no kerning data in the font\n");
4751 buf = HeapAlloc(GetProcessHeap(), 0, length);
4754 WARN("Out of memory\n");
4758 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
4760 /* build a glyph index to char code map */
4761 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
4764 WARN("Out of memory allocating a glyph index to char code map\n");
4765 HeapFree(GetProcessHeap(), 0, buf);
4769 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4775 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
4777 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4778 font->ft_face->num_glyphs, glyph_code, char_code);
4782 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4784 /* FIXME: This doesn't match what Windows does: it does some fancy
4785 * things with duplicate glyph index to char code mappings, while
4786 * we just avoid overriding existing entries.
4788 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
4789 glyph_to_char[glyph_code] = (USHORT)char_code;
4791 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
4798 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
4799 for (n = 0; n <= 65535; n++)
4800 glyph_to_char[n] = (USHORT)n;
4803 tt_kern_table = buf;
4804 nTables = GET_BE_WORD(tt_kern_table->nTables);
4805 TRACE("version %u, nTables %u\n",
4806 GET_BE_WORD(tt_kern_table->version), nTables);
4808 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
4810 for (i = 0; i < nTables; i++)
4812 struct TT_kern_subtable tt_kern_subtable_copy;
4814 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
4815 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
4816 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
4818 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4819 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
4820 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
4822 /* According to the TrueType specification this is the only format
4823 * that will be properly interpreted by Windows and OS/2
4825 if (tt_kern_subtable_copy.coverage.bits.format == 0)
4827 DWORD new_chunk, old_total = font->total_kern_pairs;
4829 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4830 glyph_to_char, NULL, 0);
4831 font->total_kern_pairs += new_chunk;
4833 if (!font->kern_pairs)
4834 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
4835 font->total_kern_pairs * sizeof(*font->kern_pairs));
4837 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
4838 font->total_kern_pairs * sizeof(*font->kern_pairs));
4840 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4841 glyph_to_char, font->kern_pairs + old_total, new_chunk);
4844 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
4846 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
4849 HeapFree(GetProcessHeap(), 0, glyph_to_char);
4850 HeapFree(GetProcessHeap(), 0, buf);
4852 if (cPairs && kern_pair)
4854 cPairs = min(cPairs, font->total_kern_pairs);
4855 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4858 return font->total_kern_pairs;
4861 #else /* HAVE_FREETYPE */
4863 /*************************************************************************/
4865 BOOL WineEngInit(void)
4869 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
4873 BOOL WineEngDestroyFontInstance(HFONT hfont)
4878 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4883 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4884 LPWORD pgi, DWORD flags)
4889 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
4890 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4893 ERR("called but we don't have FreeType\n");
4897 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4899 ERR("called but we don't have FreeType\n");
4903 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4904 OUTLINETEXTMETRICW *potm)
4906 ERR("called but we don't have FreeType\n");
4910 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4913 ERR("called but we don't have FreeType\n");
4917 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4920 ERR("called but we don't have FreeType\n");
4924 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4927 ERR("called but we don't have FreeType\n");
4931 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4932 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
4934 ERR("called but we don't have FreeType\n");
4938 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4941 ERR("called but we don't have FreeType\n");
4945 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4948 ERR("called but we don't have FreeType\n");
4952 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4954 ERR("called but we don't have FreeType\n");
4958 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4964 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4970 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4973 return DEFAULT_CHARSET;
4976 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4981 DWORD WineEngGetFontUnicodeRanges(HDC hdc, LPGLYPHSET glyphset)
4983 FIXME("(%p, %p): stub\n", hdc, glyphset);
4987 BOOL WINAPI FontIsLinked(HDC hdc)
4992 /*************************************************************************
4993 * GetRasterizerCaps (GDI32.@)
4995 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4997 lprs->nSize = sizeof(RASTERIZER_STATUS);
4999 lprs->nLanguageID = 0;
5003 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5005 ERR("called but we don't have FreeType\n");
5009 #endif /* HAVE_FREETYPE */