2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
40 #ifdef HAVE_CARBON_CARBON_H
41 #define LoadResource __carbon_LoadResource
42 #define CompareString __carbon_CompareString
43 #define GetCurrentThread __carbon_GetCurrentThread
44 #define GetCurrentProcess __carbon_GetCurrentProcess
45 #define AnimatePalette __carbon_AnimatePalette
46 #define EqualRgn __carbon_EqualRgn
47 #define FillRgn __carbon_FillRgn
48 #define FrameRgn __carbon_FrameRgn
49 #define GetPixel __carbon_GetPixel
50 #define InvertRgn __carbon_InvertRgn
51 #define LineTo __carbon_LineTo
52 #define OffsetRgn __carbon_OffsetRgn
53 #define PaintRgn __carbon_PaintRgn
54 #define Polygon __carbon_Polygon
55 #define ResizePalette __carbon_ResizePalette
56 #define SetRectRgn __carbon_SetRectRgn
57 #include <Carbon/Carbon.h>
60 #undef GetCurrentThread
63 #undef GetCurrentProcess
76 #endif /* HAVE_CARBON_CARBON_H */
84 #include "gdi_private.h"
85 #include "wine/unicode.h"
86 #include "wine/debug.h"
87 #include "wine/list.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(font);
93 #ifdef HAVE_FT2BUILD_H
96 #ifdef HAVE_FREETYPE_FREETYPE_H
97 #include <freetype/freetype.h>
99 #ifdef HAVE_FREETYPE_FTGLYPH_H
100 #include <freetype/ftglyph.h>
102 #ifdef HAVE_FREETYPE_TTTABLES_H
103 #include <freetype/tttables.h>
105 #ifdef HAVE_FREETYPE_FTSNAMES_H
106 #include <freetype/ftsnames.h>
108 # ifdef HAVE_FREETYPE_FTNAMES_H
109 # include <freetype/ftnames.h>
112 #ifdef HAVE_FREETYPE_TTNAMEID_H
113 #include <freetype/ttnameid.h>
115 #ifdef HAVE_FREETYPE_FTOUTLN_H
116 #include <freetype/ftoutln.h>
118 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
119 #include <freetype/internal/sfnt.h>
121 #ifdef HAVE_FREETYPE_FTTRIGON_H
122 #include <freetype/fttrigon.h>
124 #ifdef HAVE_FREETYPE_FTWINFNT_H
125 #include <freetype/ftwinfnt.h>
127 #ifdef HAVE_FREETYPE_FTMODAPI_H
128 #include <freetype/ftmodapi.h>
131 #ifndef SONAME_LIBFREETYPE
132 #define SONAME_LIBFREETYPE "libfreetype.so"
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
138 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType;
144 static FT_Library library = 0;
151 static FT_Version_t FT_Version;
152 static DWORD FT_SimpleVersion;
154 static void *ft_handle = NULL;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Vector_Unit);
158 MAKE_FUNCPTR(FT_Done_Face);
159 MAKE_FUNCPTR(FT_Get_Char_Index);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
164 MAKE_FUNCPTR(FT_Init_FreeType);
165 MAKE_FUNCPTR(FT_Load_Glyph);
166 MAKE_FUNCPTR(FT_Matrix_Multiply);
167 MAKE_FUNCPTR(FT_MulFix);
168 MAKE_FUNCPTR(FT_New_Face);
169 MAKE_FUNCPTR(FT_New_Memory_Face);
170 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
171 MAKE_FUNCPTR(FT_Outline_Transform);
172 MAKE_FUNCPTR(FT_Outline_Translate);
173 MAKE_FUNCPTR(FT_Select_Charmap);
174 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
175 MAKE_FUNCPTR(FT_Vector_Transform);
176 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
177 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
178 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
179 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
180 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
181 #ifdef HAVE_FREETYPE_FTWINFNT_H
182 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
185 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
186 #include <fontconfig/fontconfig.h>
187 MAKE_FUNCPTR(FcConfigGetCurrent);
188 MAKE_FUNCPTR(FcFontList);
189 MAKE_FUNCPTR(FcFontSetDestroy);
190 MAKE_FUNCPTR(FcInit);
191 MAKE_FUNCPTR(FcObjectSetAdd);
192 MAKE_FUNCPTR(FcObjectSetCreate);
193 MAKE_FUNCPTR(FcObjectSetDestroy);
194 MAKE_FUNCPTR(FcPatternCreate);
195 MAKE_FUNCPTR(FcPatternDestroy);
196 MAKE_FUNCPTR(FcPatternGetBool);
197 MAKE_FUNCPTR(FcPatternGetString);
198 #ifndef SONAME_LIBFONTCONFIG
199 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
205 #ifndef ft_encoding_none
206 #define FT_ENCODING_NONE ft_encoding_none
208 #ifndef ft_encoding_ms_symbol
209 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
211 #ifndef ft_encoding_unicode
212 #define FT_ENCODING_UNICODE ft_encoding_unicode
214 #ifndef ft_encoding_apple_roman
215 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
218 #ifdef WORDS_BIGENDIAN
219 #define GET_BE_WORD(x) (x)
221 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
224 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
231 FT_Short internal_leading;
234 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
235 So to let this compile on older versions of FreeType we'll define the
236 new structure here. */
238 FT_Short height, width;
239 FT_Pos size, x_ppem, y_ppem;
242 typedef struct tagFace {
250 FONTSIGNATURE fs_links;
251 FT_Fixed font_version;
253 Bitmap_Size size; /* set if face is a bitmap */
254 BOOL external; /* TRUE if we should manually add this font to the registry */
255 struct tagFamily *family;
258 typedef struct tagFamily {
260 const WCHAR *FamilyName;
266 INT adv; /* These three hold to widths of the unrotated chars */
284 typedef struct tagHFONTLIST {
299 struct font_mapping *mapping;
310 struct list hfontlist;
315 OUTLINETEXTMETRICW *potm;
316 DWORD total_kern_pairs;
317 KERNINGPAIR *kern_pairs;
320 struct list child_fonts;
326 const WCHAR *font_name;
330 #define INIT_GM_SIZE 128
332 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
333 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
334 #define UNUSED_CACHE_SIZE 10
335 static struct list child_font_list = LIST_INIT(child_font_list);
336 static struct list system_links = LIST_INIT(system_links);
338 static struct list font_subst_list = LIST_INIT(font_subst_list);
340 static struct list font_list = LIST_INIT(font_list);
342 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
343 static const WCHAR defSans[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
344 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
346 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
348 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
349 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
350 'W','i','n','d','o','w','s','\\',
351 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
352 'F','o','n','t','s','\0'};
354 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
355 'W','i','n','d','o','w','s',' ','N','T','\\',
356 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
357 'F','o','n','t','s','\0'};
359 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
360 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
361 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
362 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
364 static const WCHAR * const SystemFontValues[4] = {
371 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
372 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
374 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
375 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
376 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
377 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
378 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
379 'E','u','r','o','p','e','a','n','\0'};
380 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
381 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
382 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
383 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
384 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
385 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
386 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
387 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
388 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
389 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
390 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
391 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
393 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
403 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
411 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
420 typedef struct tagFontSubst {
436 static struct list mappings_list = LIST_INIT( mappings_list );
438 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
440 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
443 /****************************************
444 * Notes on .fon files
446 * The fonts System, FixedSys and Terminal are special. There are typically multiple
447 * versions installed for different resolutions and codepages. Windows stores which one to use
448 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
450 * FIXEDFON.FON FixedSys
452 * OEMFONT.FON Terminal
453 * LogPixels Current dpi set by the display control panel applet
454 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
455 * also has a LogPixels value that appears to mirror this)
457 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
458 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
459 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
460 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
461 * so that makes sense.
463 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
464 * to be mapped into the registry on Windows 2000 at least).
467 * ega80woa.fon=ega80850.fon
468 * ega40woa.fon=ega40850.fon
469 * cga80woa.fon=cga80850.fon
470 * cga40woa.fon=cga40850.fon
473 #ifdef HAVE_CARBON_CARBON_H
474 static char *find_cache_dir(void)
478 static char cached_path[MAX_PATH];
479 static const char *wine = "/Wine", *fonts = "/Fonts";
481 if(*cached_path) return cached_path;
483 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
486 WARN("can't create cached data folder\n");
489 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
492 WARN("can't create cached data path\n");
496 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
498 ERR("Could not create full path\n");
502 strcat(cached_path, wine);
504 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
506 WARN("Couldn't mkdir %s\n", cached_path);
510 strcat(cached_path, fonts);
511 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
513 WARN("Couldn't mkdir %s\n", cached_path);
520 /******************************************************************
523 * Extracts individual TrueType font files from a Mac suitcase font
524 * and saves them into the user's caches directory (see
526 * Returns a NULL terminated array of filenames.
528 * We do this because they are apps that try to read ttf files
529 * themselves and they don't like Mac suitcase files.
531 static char **expand_mac_font(const char *path)
538 const char *filename;
542 unsigned int size, max_size;
545 TRACE("path %s\n", path);
547 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
550 WARN("failed to get ref\n");
554 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
557 TRACE("no data fork, so trying resource fork\n");
558 res_ref = FSOpenResFile(&ref, fsRdPerm);
561 TRACE("unable to open resource fork\n");
568 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
571 CloseResFile(res_ref);
575 out_dir = find_cache_dir();
577 filename = strrchr(path, '/');
578 if(!filename) filename = path;
581 /* output filename has the form out_dir/filename_%04x.ttf */
582 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
589 unsigned short *num_faces_ptr, num_faces, face;
593 fond = Get1IndResource('FOND', idx);
595 TRACE("got fond resource %d\n", idx);
598 fam_rec = *(FamRec**)fond;
599 num_faces_ptr = (unsigned short *)(fam_rec + 1);
600 num_faces = GET_BE_WORD(*num_faces_ptr);
602 assoc = (AsscEntry*)(num_faces_ptr + 1);
603 TRACE("num faces %04x\n", num_faces);
604 for(face = 0; face < num_faces; face++, assoc++)
607 unsigned short size, font_id;
610 size = GET_BE_WORD(assoc->fontSize);
611 font_id = GET_BE_WORD(assoc->fontID);
614 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
618 TRACE("trying to load sfnt id %04x\n", font_id);
619 sfnt = GetResource('sfnt', font_id);
622 TRACE("can't get sfnt resource %04x\n", font_id);
626 output = HeapAlloc(GetProcessHeap(), 0, output_len);
631 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
633 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
634 if(fd != -1 || errno == EEXIST)
638 unsigned char *sfnt_data;
641 sfnt_data = *(unsigned char**)sfnt;
642 write(fd, sfnt_data, GetHandleSize(sfnt));
646 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
649 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
651 ret.array[ret.size++] = output;
655 WARN("unable to create %s\n", output);
656 HeapFree(GetProcessHeap(), 0, output);
659 ReleaseResource(sfnt);
662 ReleaseResource(fond);
665 CloseResFile(res_ref);
670 #endif /* HAVE_CARBON_CARBON_H */
672 static inline BOOL is_win9x(void)
674 return GetVersion() & 0x80000000;
677 This function builds an FT_Fixed from a float. It puts the integer part
678 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
679 It fails if the integer part of the float number is greater than SHORT_MAX.
681 static inline FT_Fixed FT_FixedFromFloat(float f)
684 unsigned short fract = (f - value) * 0xFFFF;
685 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
689 This function builds an FT_Fixed from a FIXED. It simply put f.value
690 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
692 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
694 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
698 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
703 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
704 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
706 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
707 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
709 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
711 if(face_name && strcmpiW(face_name, family->FamilyName))
713 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
715 file = strrchr(face->file, '/');
720 if(!strcasecmp(file, file_nameA))
722 HeapFree(GetProcessHeap(), 0, file_nameA);
727 HeapFree(GetProcessHeap(), 0, file_nameA);
731 static Family *find_family_from_name(const WCHAR *name)
735 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
737 if(!strcmpiW(family->FamilyName, name))
744 static Face *find_face_from_path_index(const CHAR *file_name, const INT index)
749 TRACE("looking for file %s index %i\n", debugstr_a(file_name), index);
751 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
753 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
755 if(!strcasecmp(face->file, file_name) && face->face_index == index)
762 static void DumpSubstList(void)
766 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
768 if(psub->from.charset != -1 || psub->to.charset != -1)
769 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
770 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
772 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
773 debugstr_w(psub->to.name));
778 static LPWSTR strdupW(LPCWSTR p)
781 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
782 ret = HeapAlloc(GetProcessHeap(), 0, len);
787 static LPSTR strdupA(LPCSTR p)
790 DWORD len = (strlen(p) + 1);
791 ret = HeapAlloc(GetProcessHeap(), 0, len);
796 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
801 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
803 if(!strcmpiW(element->from.name, from_name) &&
804 (element->from.charset == from_charset ||
805 element->from.charset == -1))
812 #define ADD_FONT_SUBST_FORCE 1
814 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
816 FontSubst *from_exist, *to_exist;
818 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
820 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
822 list_remove(&from_exist->entry);
823 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
824 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
825 HeapFree(GetProcessHeap(), 0, from_exist);
831 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
835 HeapFree(GetProcessHeap(), 0, subst->to.name);
836 subst->to.name = strdupW(to_exist->to.name);
839 list_add_tail(subst_list, &subst->entry);
844 HeapFree(GetProcessHeap(), 0, subst->from.name);
845 HeapFree(GetProcessHeap(), 0, subst->to.name);
846 HeapFree(GetProcessHeap(), 0, subst);
850 static void split_subst_info(NameCs *nc, LPSTR str)
852 CHAR *p = strrchr(str, ',');
857 nc->charset = strtol(p+1, NULL, 10);
860 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
861 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
862 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
865 static void LoadSubstList(void)
869 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
873 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
874 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
875 &hkey) == ERROR_SUCCESS) {
877 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
878 &valuelen, &datalen, NULL, NULL);
880 valuelen++; /* returned value doesn't include room for '\0' */
881 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
882 data = HeapAlloc(GetProcessHeap(), 0, datalen);
886 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
887 &dlen) == ERROR_SUCCESS) {
888 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
890 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
891 split_subst_info(&psub->from, value);
892 split_subst_info(&psub->to, data);
894 /* Win 2000 doesn't allow mapping between different charsets
895 or mapping of DEFAULT_CHARSET */
896 if((psub->to.charset != psub->from.charset) ||
897 psub->to.charset == DEFAULT_CHARSET) {
898 HeapFree(GetProcessHeap(), 0, psub->to.name);
899 HeapFree(GetProcessHeap(), 0, psub->from.name);
900 HeapFree(GetProcessHeap(), 0, psub);
902 add_font_subst(&font_subst_list, psub, 0);
904 /* reset dlen and vlen */
908 HeapFree(GetProcessHeap(), 0, data);
909 HeapFree(GetProcessHeap(), 0, value);
914 static WCHAR *get_familyname(FT_Face ft_face)
916 WCHAR *family = NULL;
918 FT_UInt num_names, name_index, i;
920 if(FT_IS_SFNT(ft_face))
922 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
924 for(name_index = 0; name_index < num_names; name_index++)
926 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
928 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
929 (name.language_id == GetUserDefaultLCID()) &&
930 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
931 (name.encoding_id == TT_MS_ID_UNICODE_CS))
933 /* String is not nul terminated and string_len is a byte length. */
934 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
935 for(i = 0; i < name.string_len / 2; i++)
937 WORD *tmp = (WORD *)&name.string[i * 2];
938 family[i] = GET_BE_WORD(*tmp);
942 TRACE("Got localised name %s\n", debugstr_w(family));
953 #define ADDFONT_EXTERNAL_FONT 0x01
954 #define ADDFONT_FORCE_BITMAP 0x02
955 static BOOL AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
959 TT_Header *pHeader = NULL;
960 WCHAR *english_family, *localised_family, *StyleW;
964 struct list *family_elem_ptr, *face_elem_ptr;
966 FT_Long face_index = 0, num_faces;
967 #ifdef HAVE_FREETYPE_FTWINFNT_H
968 FT_WinFNT_HeaderRec winfnt_header;
970 int i, bitmap_num, internal_leading;
973 #ifdef HAVE_CARBON_CARBON_H
976 char **mac_list = expand_mac_font(file);
979 BOOL had_one = FALSE;
981 for(cursor = mac_list; *cursor; cursor++)
984 AddFontFileToList(*cursor, NULL, NULL, flags);
985 HeapFree(GetProcessHeap(), 0, *cursor);
987 HeapFree(GetProcessHeap(), 0, mac_list);
992 #endif /* HAVE_CARBON_CARBON_H */
995 char *family_name = fake_family;
997 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
998 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
999 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
1003 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*/
1004 WARN("Ignoring font %s\n", debugstr_a(file));
1005 pFT_Done_Face(ft_face);
1009 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1010 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1011 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file));
1012 pFT_Done_Face(ft_face);
1016 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
1017 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1018 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
1019 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
1020 "Skipping this font.\n", debugstr_a(file));
1021 pFT_Done_Face(ft_face);
1025 if(!ft_face->family_name || !ft_face->style_name) {
1026 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
1027 pFT_Done_Face(ft_face);
1033 localised_family = get_familyname(ft_face);
1034 if (localised_family && lstrcmpW(localised_family,target_family)!=0)
1036 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1037 HeapFree(GetProcessHeap(), 0, localised_family);
1038 num_faces = ft_face->num_faces;
1039 pFT_Done_Face(ft_face);
1042 HeapFree(GetProcessHeap(), 0, localised_family);
1046 family_name = ft_face->family_name;
1050 My_FT_Bitmap_Size *size = NULL;
1052 if(!FT_IS_SCALABLE(ft_face))
1053 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1055 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1056 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1057 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1059 localised_family = NULL;
1061 localised_family = get_familyname(ft_face);
1062 if(localised_family && !strcmpW(localised_family, english_family)) {
1063 HeapFree(GetProcessHeap(), 0, localised_family);
1064 localised_family = NULL;
1069 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1070 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1071 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1076 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1077 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1078 list_init(&family->faces);
1079 list_add_tail(&font_list, &family->entry);
1081 if(localised_family) {
1082 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1083 subst->from.name = strdupW(english_family);
1084 subst->from.charset = -1;
1085 subst->to.name = strdupW(localised_family);
1086 subst->to.charset = -1;
1087 add_font_subst(&font_subst_list, subst, 0);
1090 HeapFree(GetProcessHeap(), 0, localised_family);
1091 HeapFree(GetProcessHeap(), 0, english_family);
1093 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1094 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1095 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1097 internal_leading = 0;
1098 memset(&fs, 0, sizeof(fs));
1100 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1102 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1103 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1104 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1105 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1106 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1107 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1108 if(pOS2->version == 0) {
1111 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1114 fs.fsCsb[0] |= 1L << 31;
1117 #ifdef HAVE_FREETYPE_FTWINFNT_H
1118 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1120 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1121 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1122 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1123 memcpy(&fs, &csi.fs, sizeof(csi.fs));
1124 internal_leading = winfnt_header.internal_leading;
1128 face_elem_ptr = list_head(&family->faces);
1129 while(face_elem_ptr) {
1130 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1131 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1132 if(!strcmpW(face->StyleName, StyleW) &&
1133 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1134 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1135 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1136 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1139 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1140 HeapFree(GetProcessHeap(), 0, StyleW);
1141 pFT_Done_Face(ft_face);
1144 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1145 TRACE("Original font is newer so skipping this one\n");
1146 HeapFree(GetProcessHeap(), 0, StyleW);
1147 pFT_Done_Face(ft_face);
1150 TRACE("Replacing original with this one\n");
1151 list_remove(&face->entry);
1152 HeapFree(GetProcessHeap(), 0, face->file);
1153 HeapFree(GetProcessHeap(), 0, face->StyleName);
1154 HeapFree(GetProcessHeap(), 0, face);
1159 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1160 list_add_tail(&family->faces, &face->entry);
1161 face->StyleName = StyleW;
1162 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
1163 strcpy(face->file, file);
1164 face->face_index = face_index;
1165 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
1166 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
1167 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1168 face->family = family;
1169 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1170 memcpy(&face->fs, &fs, sizeof(face->fs));
1171 memset(&face->fs_links, 0, sizeof(face->fs_links));
1173 if(FT_IS_SCALABLE(ft_face)) {
1174 memset(&face->size, 0, sizeof(face->size));
1175 face->scalable = TRUE;
1177 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1178 size->height, size->width, size->size >> 6,
1179 size->x_ppem >> 6, size->y_ppem >> 6);
1180 face->size.height = size->height;
1181 face->size.width = size->width;
1182 face->size.size = size->size;
1183 face->size.x_ppem = size->x_ppem;
1184 face->size.y_ppem = size->y_ppem;
1185 face->size.internal_leading = internal_leading;
1186 face->scalable = FALSE;
1189 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1190 face->fs.fsCsb[0], face->fs.fsCsb[1],
1191 face->fs.fsUsb[0], face->fs.fsUsb[1],
1192 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1195 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1196 for(i = 0; i < ft_face->num_charmaps; i++) {
1197 switch(ft_face->charmaps[i]->encoding) {
1198 case FT_ENCODING_UNICODE:
1199 case FT_ENCODING_APPLE_ROMAN:
1200 face->fs.fsCsb[0] |= 1;
1202 case FT_ENCODING_MS_SYMBOL:
1203 face->fs.fsCsb[0] |= 1L << 31;
1211 if(face->fs.fsCsb[0] & ~(1L << 31))
1212 have_installed_roman_font = TRUE;
1213 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1215 num_faces = ft_face->num_faces;
1216 pFT_Done_Face(ft_face);
1217 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1218 debugstr_w(StyleW));
1219 } while(num_faces > ++face_index);
1223 static void DumpFontList(void)
1227 struct list *family_elem_ptr, *face_elem_ptr;
1229 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1230 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1231 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1232 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1233 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1234 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1236 TRACE(" %d", face->size.height);
1243 /***********************************************************
1244 * The replacement list is a way to map an entire font
1245 * family onto another family. For example adding
1247 * [HKCU\Software\Wine\Fonts\Replacements]
1248 * "Wingdings"="Winedings"
1250 * would enumerate the Winedings font both as Winedings and
1251 * Wingdings. However if a real Wingdings font is present the
1252 * replacement does not take place.
1255 static void LoadReplaceList(void)
1258 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1263 struct list *family_elem_ptr, *face_elem_ptr;
1266 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1267 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1269 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1270 &valuelen, &datalen, NULL, NULL);
1272 valuelen++; /* returned value doesn't include room for '\0' */
1273 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1274 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1278 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1279 &dlen) == ERROR_SUCCESS) {
1280 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1281 /* "NewName"="Oldname" */
1282 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1284 /* Find the old family and hence all of the font files
1286 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1287 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1288 if(!strcmpiW(family->FamilyName, data)) {
1289 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1290 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1291 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1292 debugstr_w(face->StyleName), familyA);
1293 /* Now add a new entry with the new family name */
1294 AddFontFileToList(face->file, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1299 /* reset dlen and vlen */
1303 HeapFree(GetProcessHeap(), 0, data);
1304 HeapFree(GetProcessHeap(), 0, value);
1309 /*************************************************************
1312 static BOOL init_system_links(void)
1314 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1315 'W','i','n','d','o','w','s',' ','N','T','\\',
1316 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1317 'S','y','s','t','e','m','L','i','n','k',0};
1320 DWORD type, max_val, max_data, val_len, data_len, index;
1321 WCHAR *value, *data;
1322 WCHAR *entry, *next;
1323 SYSTEM_LINKS *font_link, *system_font_link;
1324 CHILD_FONT *child_font;
1325 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1326 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1327 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1333 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1335 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1336 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1337 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1338 val_len = max_val + 1;
1339 data_len = max_data;
1341 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1343 TRACE("%s:\n", debugstr_w(value));
1345 memset(&fs, 0, sizeof(fs));
1346 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1347 psub = get_font_subst(&font_subst_list, value, -1);
1348 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1349 list_init(&font_link->links);
1350 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1353 CHILD_FONT *child_font;
1355 TRACE("\t%s\n", debugstr_w(entry));
1357 next = entry + strlenW(entry) + 1;
1359 face_name = strchrW(entry, ',');
1363 while(isspaceW(*face_name))
1366 psub = get_font_subst(&font_subst_list, face_name, -1);
1368 face_name = psub->to.name;
1370 face = find_face_from_filename(entry, face_name);
1373 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1377 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1378 child_font->file_name = strdupA(face->file);
1379 child_font->index = face->face_index;
1380 child_font->font = NULL;
1381 fs.fsCsb[0] |= face->fs.fsCsb[0];
1382 fs.fsCsb[1] |= face->fs.fsCsb[1];
1383 TRACE("Adding file %s index %d\n", child_font->file_name, child_font->index);
1384 list_add_tail(&font_link->links, &child_font->entry);
1386 family = find_family_from_name(font_link->font_name);
1389 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1391 memcpy(&face->fs_links, &fs, sizeof(fs));
1394 list_add_tail(&system_links, &font_link->entry);
1395 val_len = max_val + 1;
1396 data_len = max_data;
1399 HeapFree(GetProcessHeap(), 0, value);
1400 HeapFree(GetProcessHeap(), 0, data);
1404 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1407 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1408 system_font_link->font_name = strdupW(System);
1409 list_init(&system_font_link->links);
1411 face = find_face_from_filename(tahoma_ttf, Tahoma);
1414 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1415 child_font->file_name = strdupA(face->file);
1416 child_font->index = face->face_index;
1417 child_font->font = NULL;
1418 TRACE("Found Tahoma in %s index %d\n", child_font->file_name, child_font->index);
1419 list_add_tail(&system_font_link->links, &child_font->entry);
1421 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1423 if(!strcmpiW(font_link->font_name, Tahoma))
1425 CHILD_FONT *font_link_entry;
1426 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1428 CHILD_FONT *new_child;
1429 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1430 new_child->file_name = strdupA(font_link_entry->file_name);
1431 new_child->index = font_link_entry->index;
1432 new_child->font = NULL;
1433 list_add_tail(&system_font_link->links, &new_child->entry);
1438 list_add_tail(&system_links, &system_font_link->entry);
1442 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1445 struct dirent *dent;
1446 char path[MAX_PATH];
1448 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1450 dir = opendir(dirname);
1452 WARN("Can't open directory %s\n", debugstr_a(dirname));
1455 while((dent = readdir(dir)) != NULL) {
1456 struct stat statbuf;
1458 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1461 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1463 sprintf(path, "%s/%s", dirname, dent->d_name);
1465 if(stat(path, &statbuf) == -1)
1467 WARN("Can't stat %s\n", debugstr_a(path));
1470 if(S_ISDIR(statbuf.st_mode))
1471 ReadFontDir(path, external_fonts);
1473 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1479 static void load_fontconfig_fonts(void)
1481 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1482 void *fc_handle = NULL;
1491 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1493 TRACE("Wine cannot find the fontconfig library (%s).\n",
1494 SONAME_LIBFONTCONFIG);
1497 #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;}
1498 LOAD_FUNCPTR(FcConfigGetCurrent);
1499 LOAD_FUNCPTR(FcFontList);
1500 LOAD_FUNCPTR(FcFontSetDestroy);
1501 LOAD_FUNCPTR(FcInit);
1502 LOAD_FUNCPTR(FcObjectSetAdd);
1503 LOAD_FUNCPTR(FcObjectSetCreate);
1504 LOAD_FUNCPTR(FcObjectSetDestroy);
1505 LOAD_FUNCPTR(FcPatternCreate);
1506 LOAD_FUNCPTR(FcPatternDestroy);
1507 LOAD_FUNCPTR(FcPatternGetBool);
1508 LOAD_FUNCPTR(FcPatternGetString);
1511 if(!pFcInit()) return;
1513 config = pFcConfigGetCurrent();
1514 pat = pFcPatternCreate();
1515 os = pFcObjectSetCreate();
1516 pFcObjectSetAdd(os, FC_FILE);
1517 pFcObjectSetAdd(os, FC_SCALABLE);
1518 fontset = pFcFontList(config, pat, os);
1519 if(!fontset) return;
1520 for(i = 0; i < fontset->nfont; i++) {
1523 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1525 TRACE("fontconfig: %s\n", file);
1527 /* We're just interested in OT/TT fonts for now, so this hack just
1528 picks up the scalable fonts without extensions .pf[ab] to save time
1529 loading every other font */
1531 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1533 TRACE("not scalable\n");
1537 len = strlen( file );
1538 if(len < 4) continue;
1539 ext = &file[ len - 3 ];
1540 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1541 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1543 pFcFontSetDestroy(fontset);
1544 pFcObjectSetDestroy(os);
1545 pFcPatternDestroy(pat);
1551 static BOOL load_font_from_data_dir(LPCWSTR file)
1554 const char *data_dir = wine_get_data_dir();
1556 if (!data_dir) data_dir = wine_get_build_dir();
1563 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1565 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1567 strcpy(unix_name, data_dir);
1568 strcat(unix_name, "/fonts/");
1570 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1572 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1573 HeapFree(GetProcessHeap(), 0, unix_name);
1578 static void load_system_fonts(void)
1581 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1582 const WCHAR * const *value;
1584 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1587 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1588 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1589 strcatW(windowsdir, fontsW);
1590 for(value = SystemFontValues; *value; value++) {
1591 dlen = sizeof(data);
1592 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1596 sprintfW(pathW, fmtW, windowsdir, data);
1597 if((unixname = wine_get_unix_file_name(pathW))) {
1598 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1599 HeapFree(GetProcessHeap(), 0, unixname);
1602 load_font_from_data_dir(data);
1609 /*************************************************************
1611 * This adds registry entries for any externally loaded fonts
1612 * (fonts from fontconfig or FontDirs). It also deletes entries
1613 * of no longer existing fonts.
1616 static void update_reg_entries(void)
1618 HKEY winkey = 0, externalkey = 0;
1621 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1624 struct list *family_elem_ptr, *face_elem_ptr;
1626 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1627 static const WCHAR spaceW[] = {' ', '\0'};
1630 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1631 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1632 ERR("Can't create Windows font reg key\n");
1635 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1636 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1637 ERR("Can't create external font reg key\n");
1641 /* Delete all external fonts added last time */
1643 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1644 &valuelen, &datalen, NULL, NULL);
1645 valuelen++; /* returned value doesn't include room for '\0' */
1646 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1647 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1649 dlen = datalen * sizeof(WCHAR);
1652 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1653 &dlen) == ERROR_SUCCESS) {
1655 RegDeleteValueW(winkey, valueW);
1656 /* reset dlen and vlen */
1660 HeapFree(GetProcessHeap(), 0, data);
1661 HeapFree(GetProcessHeap(), 0, valueW);
1663 /* Delete the old external fonts key */
1664 RegCloseKey(externalkey);
1666 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1668 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1669 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1670 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1671 ERR("Can't create external font reg key\n");
1675 /* enumerate the fonts and add external ones to the two keys */
1677 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1678 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1679 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1680 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1681 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1682 if(!face->external) continue;
1684 if(strcmpiW(face->StyleName, RegularW))
1685 len = len_fam + strlenW(face->StyleName) + 1;
1686 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1687 strcpyW(valueW, family->FamilyName);
1688 if(len != len_fam) {
1689 strcatW(valueW, spaceW);
1690 strcatW(valueW, face->StyleName);
1692 strcatW(valueW, TrueType);
1693 if((path = strrchr(face->file, '/')) == NULL)
1697 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1699 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1700 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1701 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1702 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1704 HeapFree(GetProcessHeap(), 0, file);
1705 HeapFree(GetProcessHeap(), 0, valueW);
1710 RegCloseKey(externalkey);
1712 RegCloseKey(winkey);
1717 /*************************************************************
1718 * WineEngAddFontResourceEx
1721 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1723 if (ft_handle) /* do it only if we have freetype up and running */
1728 FIXME("Ignoring flags %x\n", flags);
1730 if((unixname = wine_get_unix_file_name(file)))
1732 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1733 HeapFree(GetProcessHeap(), 0, unixname);
1739 /*************************************************************
1740 * WineEngRemoveFontResourceEx
1743 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1749 static const struct nls_update_font_list
1751 UINT ansi_cp, oem_cp;
1752 const char *oem, *fixed, *system;
1753 const char *courier, *serif, *small, *sserif;
1754 /* these are for font substitute */
1755 const char *shelldlg, *tmsrmn;
1756 } nls_update_font_list[] =
1758 /* Latin 1 (United States) */
1759 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1760 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1761 "Tahoma","Times New Roman",
1763 /* Latin 1 (Multilingual) */
1764 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1765 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1766 "Tahoma","Times New Roman", /* FIXME unverified */
1768 /* Eastern Europe */
1769 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1770 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1771 "Tahoma","Times New Roman", /* FIXME unverified */
1774 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1775 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1776 "Tahoma","Times New Roman", /* FIXME unverified */
1779 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1780 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1781 "Tahoma","Times New Roman", /* FIXME unverified */
1784 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1785 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1786 "Tahoma","Times New Roman", /* FIXME unverified */
1789 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1790 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1791 "Tahoma","Times New Roman", /* FIXME unverified */
1794 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1795 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1796 "Tahoma","Times New Roman", /* FIXME unverified */
1799 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1800 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1801 "Tahoma","Times New Roman", /* FIXME unverified */
1804 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1805 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1806 "Tahoma","Times New Roman", /* FIXME unverified */
1809 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1810 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1811 "Tahoma","Times New Roman", /* FIXME unverified */
1814 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1815 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1816 "MS UI Gothic","MS Serif",
1818 /* Chinese Simplified */
1819 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1820 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1821 "Tahoma", "Times New Roman", /* FIXME unverified */
1824 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1825 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1828 /* Chinese Traditional */
1829 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1830 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1831 "Tahoma", "Times New Roman", /* FIXME unverified */
1835 inline static HKEY create_fonts_NT_registry_key(void)
1839 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1840 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1844 inline static HKEY create_fonts_9x_registry_key(void)
1848 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1849 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1853 inline static HKEY create_config_fonts_registry_key(void)
1857 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1858 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1862 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1864 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1865 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1866 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1867 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1870 static void update_font_info(void)
1872 char buf[40], cpbuf[40];
1875 UINT i, ansi_cp = 0, oem_cp = 0;
1877 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
1880 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1881 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1882 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1883 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1884 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
1887 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1889 if (!strcmp( buf, cpbuf )) /* already set correctly */
1894 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
1896 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
1898 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
1901 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1903 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1904 nls_update_font_list[i].oem_cp == oem_cp)
1908 hkey = create_config_fonts_registry_key();
1909 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1910 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1911 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1914 hkey = create_fonts_NT_registry_key();
1915 add_font_list(hkey, &nls_update_font_list[i]);
1918 hkey = create_fonts_9x_registry_key();
1919 add_font_list(hkey, &nls_update_font_list[i]);
1922 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
1924 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
1925 strlen(nls_update_font_list[i].shelldlg)+1);
1926 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
1927 strlen(nls_update_font_list[i].tmsrmn)+1);
1933 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
1936 /*************************************************************
1939 * Initialize FreeType library and create a list of available faces
1941 BOOL WineEngInit(void)
1943 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1944 static const WCHAR pathW[] = {'P','a','t','h',0};
1946 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1948 WCHAR windowsdir[MAX_PATH];
1951 const char *data_dir;
1955 /* update locale dependent font info in registry */
1958 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1961 "Wine cannot find the FreeType font library. To enable Wine to\n"
1962 "use TrueType fonts please install a version of FreeType greater than\n"
1963 "or equal to 2.0.5.\n"
1964 "http://www.freetype.org\n");
1968 #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;}
1970 LOAD_FUNCPTR(FT_Vector_Unit)
1971 LOAD_FUNCPTR(FT_Done_Face)
1972 LOAD_FUNCPTR(FT_Get_Char_Index)
1973 LOAD_FUNCPTR(FT_Get_Module)
1974 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1975 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1976 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1977 LOAD_FUNCPTR(FT_Init_FreeType)
1978 LOAD_FUNCPTR(FT_Load_Glyph)
1979 LOAD_FUNCPTR(FT_Matrix_Multiply)
1980 LOAD_FUNCPTR(FT_MulFix)
1981 LOAD_FUNCPTR(FT_New_Face)
1982 LOAD_FUNCPTR(FT_New_Memory_Face)
1983 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1984 LOAD_FUNCPTR(FT_Outline_Transform)
1985 LOAD_FUNCPTR(FT_Outline_Translate)
1986 LOAD_FUNCPTR(FT_Select_Charmap)
1987 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1988 LOAD_FUNCPTR(FT_Vector_Transform)
1991 /* Don't warn if this one is missing */
1992 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1993 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1994 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1995 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
1996 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
1997 #ifdef HAVE_FREETYPE_FTWINFNT_H
1998 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2000 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2001 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2002 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2003 <= 2.0.3 has FT_Sqrt64 */
2007 if(pFT_Init_FreeType(&library) != 0) {
2008 ERR("Can't init FreeType library\n");
2009 wine_dlclose(ft_handle, NULL, 0);
2013 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
2014 if (pFT_Library_Version)
2016 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2018 if (FT_Version.major<=0)
2024 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2025 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2026 ((FT_Version.minor << 8) & 0x00ff00) |
2027 ((FT_Version.patch ) & 0x0000ff);
2029 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2030 ERR("Failed to create font mutex\n");
2033 WaitForSingleObject(font_mutex, INFINITE);
2035 /* load the system bitmap fonts */
2036 load_system_fonts();
2038 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2039 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2040 strcatW(windowsdir, fontsW);
2041 if((unixname = wine_get_unix_file_name(windowsdir)))
2043 ReadFontDir(unixname, FALSE);
2044 HeapFree(GetProcessHeap(), 0, unixname);
2047 /* load the system truetype fonts */
2048 data_dir = wine_get_data_dir();
2049 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2050 strcpy(unixname, data_dir);
2051 strcat(unixname, "/fonts/");
2052 ReadFontDir(unixname, FALSE);
2053 HeapFree(GetProcessHeap(), 0, unixname);
2056 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2057 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2058 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2060 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2061 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2062 &hkey) == ERROR_SUCCESS) {
2064 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2065 &valuelen, &datalen, NULL, NULL);
2067 valuelen++; /* returned value doesn't include room for '\0' */
2068 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2069 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2072 dlen = datalen * sizeof(WCHAR);
2074 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2075 &dlen) == ERROR_SUCCESS) {
2076 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2078 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2080 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2081 HeapFree(GetProcessHeap(), 0, unixname);
2084 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2086 WCHAR pathW[MAX_PATH];
2087 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2090 sprintfW(pathW, fmtW, windowsdir, data);
2091 if((unixname = wine_get_unix_file_name(pathW)))
2093 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2094 HeapFree(GetProcessHeap(), 0, unixname);
2097 load_font_from_data_dir(data);
2099 /* reset dlen and vlen */
2104 HeapFree(GetProcessHeap(), 0, data);
2105 HeapFree(GetProcessHeap(), 0, valueW);
2109 load_fontconfig_fonts();
2111 /* then look in any directories that we've specified in the config file */
2112 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2113 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2119 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2121 len += sizeof(WCHAR);
2122 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2123 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2125 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2126 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2127 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2128 TRACE( "got font path %s\n", debugstr_a(valueA) );
2132 LPSTR next = strchr( ptr, ':' );
2133 if (next) *next++ = 0;
2134 ReadFontDir( ptr, TRUE );
2137 HeapFree( GetProcessHeap(), 0, valueA );
2139 HeapFree( GetProcessHeap(), 0, valueW );
2148 update_reg_entries();
2150 init_system_links();
2152 ReleaseMutex(font_mutex);
2156 "Wine cannot find certain functions that it needs inside the FreeType\n"
2157 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2158 "FreeType to at least version 2.0.5.\n"
2159 "http://www.freetype.org\n");
2160 wine_dlclose(ft_handle, NULL, 0);
2166 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2169 TT_HoriHeader *pHori;
2173 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2174 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2176 if(height == 0) height = 16;
2178 /* Calc. height of EM square:
2180 * For +ve lfHeight we have
2181 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2182 * Re-arranging gives:
2183 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2185 * For -ve lfHeight we have
2187 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2188 * with il = winAscent + winDescent - units_per_em]
2193 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2194 ppem = ft_face->units_per_EM * height /
2195 (pHori->Ascender - pHori->Descender);
2197 ppem = ft_face->units_per_EM * height /
2198 (pOS2->usWinAscent + pOS2->usWinDescent);
2206 static struct font_mapping *map_font( const char *name )
2208 #ifndef __APPLE__ /* Mac OS fonts use resource forks, we can't simply mmap them */
2209 struct font_mapping *mapping;
2213 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2214 if (fstat( fd, &st ) == -1) goto error;
2216 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2218 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2220 mapping->refcount++;
2225 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2228 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2231 if (mapping->data == MAP_FAILED)
2233 HeapFree( GetProcessHeap(), 0, mapping );
2236 mapping->refcount = 1;
2237 mapping->dev = st.st_dev;
2238 mapping->ino = st.st_ino;
2239 mapping->size = st.st_size;
2240 list_add_tail( &mappings_list, &mapping->entry );
2249 static void unmap_font( struct font_mapping *mapping )
2251 if (!--mapping->refcount)
2253 list_remove( &mapping->entry );
2254 munmap( mapping->data, mapping->size );
2255 HeapFree( GetProcessHeap(), 0, mapping );
2259 static LONG load_VDMX(GdiFont*, LONG);
2261 static FT_Face OpenFontFile(GdiFont *font, char *file, FT_Long face_index, LONG width, LONG height)
2266 TRACE("%s, %ld, %d x %d\n", debugstr_a(file), face_index, width, height);
2268 if ((font->mapping = map_font( file )))
2269 err = pFT_New_Memory_Face(library, font->mapping->data, font->mapping->size, face_index, &ft_face);
2271 err = pFT_New_Face(library, file, face_index, &ft_face);
2274 ERR("FT_New_Face rets %d\n", err);
2278 /* set it here, as load_VDMX needs it */
2279 font->ft_face = ft_face;
2281 if(FT_IS_SCALABLE(ft_face)) {
2282 /* load the VDMX table if we have one */
2283 font->ppem = load_VDMX(font, height);
2285 font->ppem = calc_ppem_for_height(ft_face, height);
2287 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2288 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2290 font->ppem = height;
2291 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2292 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2298 static int get_nearest_charset(Face *face, int *cp)
2300 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2301 a single face with the requested charset. The idea is to check if
2302 the selected font supports the current ANSI codepage, if it does
2303 return the corresponding charset, else return the first charset */
2306 int acp = GetACP(), i;
2310 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2311 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2312 return csi.ciCharset;
2314 for(i = 0; i < 32; i++) {
2316 if(face->fs.fsCsb[0] & fs0) {
2317 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2319 return csi.ciCharset;
2322 FIXME("TCI failing on %x\n", fs0);
2326 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2327 face->fs.fsCsb[0], face->file);
2329 return DEFAULT_CHARSET;
2332 static GdiFont *alloc_font(void)
2334 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2335 ret->gmsize = INIT_GM_SIZE;
2336 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2337 ret->gmsize * sizeof(*ret->gm));
2339 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2340 ret->total_kern_pairs = (DWORD)-1;
2341 ret->kern_pairs = NULL;
2342 list_init(&ret->hfontlist);
2343 list_init(&ret->child_fonts);
2347 static void free_font(GdiFont *font)
2349 struct list *cursor, *cursor2;
2351 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2353 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2354 struct list *first_hfont;
2355 HFONTLIST *hfontlist;
2356 list_remove(cursor);
2359 first_hfont = list_head(&child->font->hfontlist);
2360 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2361 DeleteObject(hfontlist->hfont);
2362 HeapFree(GetProcessHeap(), 0, hfontlist);
2363 free_font(child->font);
2365 HeapFree(GetProcessHeap(), 0, child->file_name);
2366 HeapFree(GetProcessHeap(), 0, child);
2369 if (font->ft_face) pFT_Done_Face(font->ft_face);
2370 if (font->mapping) unmap_font( font->mapping );
2371 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2372 HeapFree(GetProcessHeap(), 0, font->potm);
2373 HeapFree(GetProcessHeap(), 0, font->name);
2374 HeapFree(GetProcessHeap(), 0, font->gm);
2375 HeapFree(GetProcessHeap(), 0, font);
2379 /*************************************************************
2382 * load the vdmx entry for the specified height
2385 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2386 ( ( (FT_ULong)_x4 << 24 ) | \
2387 ( (FT_ULong)_x3 << 16 ) | \
2388 ( (FT_ULong)_x2 << 8 ) | \
2391 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2406 static LONG load_VDMX(GdiFont *font, LONG height)
2410 BYTE devXRatio, devYRatio;
2411 USHORT numRecs, numRatios;
2412 DWORD result, offset = -1;
2416 /* For documentation on VDMX records, see
2417 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2420 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2422 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2425 /* FIXME: need the real device aspect ratio */
2429 numRecs = GET_BE_WORD(hdr[1]);
2430 numRatios = GET_BE_WORD(hdr[2]);
2432 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2433 for(i = 0; i < numRatios; i++) {
2436 offset = (3 * 2) + (i * sizeof(Ratios));
2437 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2440 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2442 if((ratio.xRatio == 0 &&
2443 ratio.yStartRatio == 0 &&
2444 ratio.yEndRatio == 0) ||
2445 (devXRatio == ratio.xRatio &&
2446 devYRatio >= ratio.yStartRatio &&
2447 devYRatio <= ratio.yEndRatio))
2449 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2450 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2451 offset = GET_BE_WORD(tmp);
2457 FIXME("No suitable ratio found\n");
2461 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2463 BYTE startsz, endsz;
2466 recs = GET_BE_WORD(group.recs);
2467 startsz = group.startsz;
2468 endsz = group.endsz;
2470 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2472 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2473 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2474 if(result == GDI_ERROR) {
2475 FIXME("Failed to retrieve vTable\n");
2480 for(i = 0; i < recs; i++) {
2481 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2482 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2483 ppem = GET_BE_WORD(vTable[i * 3]);
2485 if(yMax + -yMin == height) {
2488 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2491 if(yMax + -yMin > height) {
2494 goto end; /* failed */
2496 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2497 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2498 ppem = GET_BE_WORD(vTable[i * 3]);
2499 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2505 TRACE("ppem not found for height %d\n", height);
2509 if(ppem < startsz || ppem > endsz)
2512 for(i = 0; i < recs; i++) {
2514 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2516 if(yPelHeight > ppem)
2519 if(yPelHeight == ppem) {
2520 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2521 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2522 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2528 HeapFree(GetProcessHeap(), 0, vTable);
2534 static BOOL fontcmp(GdiFont *font, FONT_DESC *fd)
2536 if(font->font_desc.hash != fd->hash) return TRUE;
2537 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2538 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2539 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2540 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2543 static void calc_hash(FONT_DESC *pfd)
2545 DWORD hash = 0, *ptr, two_chars;
2549 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2551 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2553 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2555 pwc = (WCHAR *)&two_chars;
2557 *pwc = toupperW(*pwc);
2559 *pwc = toupperW(*pwc);
2563 hash ^= !pfd->can_use_bitmap;
2568 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2573 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2575 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2576 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2577 fd.can_use_bitmap = can_use_bitmap;
2580 /* try the in-use list */
2581 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2582 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2583 if(!fontcmp(ret, &fd)) {
2584 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2585 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2586 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2587 if(hflist->hfont == hfont)
2590 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2591 hflist->hfont = hfont;
2592 list_add_head(&ret->hfontlist, &hflist->entry);
2597 /* then the unused list */
2598 font_elem_ptr = list_head(&unused_gdi_font_list);
2599 while(font_elem_ptr) {
2600 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2601 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2602 if(!fontcmp(ret, &fd)) {
2603 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2604 assert(list_empty(&ret->hfontlist));
2605 TRACE("Found %p in unused list\n", ret);
2606 list_remove(&ret->entry);
2607 list_add_head(&gdi_font_list, &ret->entry);
2608 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2609 hflist->hfont = hfont;
2610 list_add_head(&ret->hfontlist, &hflist->entry);
2618 /*************************************************************
2619 * create_child_font_list
2621 static BOOL create_child_font_list(GdiFont *font)
2624 SYSTEM_LINKS *font_link;
2625 CHILD_FONT *font_link_entry, *new_child;
2627 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2629 if(!strcmpW(font_link->font_name, font->name))
2631 TRACE("found entry in system list\n");
2632 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2634 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2635 new_child->file_name = strdupA(font_link_entry->file_name);
2636 new_child->index = font_link_entry->index;
2637 new_child->font = NULL;
2638 list_add_tail(&font->child_fonts, &new_child->entry);
2639 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
2649 /*************************************************************
2650 * WineEngCreateFontInstance
2653 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
2656 Face *face, *best, *best_bitmap;
2657 Family *family, *last_resort_family;
2658 struct list *family_elem_ptr, *face_elem_ptr;
2659 INT height, width = 0;
2660 unsigned int score = 0, new_score;
2661 signed int diff = 0, newdiff;
2662 BOOL bd, it, can_use_bitmap;
2667 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2669 struct list *first_hfont = list_head(&ret->hfontlist);
2670 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2671 if(hflist->hfont == hfont)
2675 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2676 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2678 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2679 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2680 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2683 /* check the cache first */
2684 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2685 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2689 TRACE("not in cache\n");
2690 if(list_empty(&font_list)) /* No fonts installed */
2692 TRACE("No fonts installed\n");
2695 if(!have_installed_roman_font)
2697 TRACE("No roman font installed\n");
2703 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2704 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2705 ret->font_desc.can_use_bitmap = can_use_bitmap;
2706 calc_hash(&ret->font_desc);
2707 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2708 hflist->hfont = hfont;
2709 list_add_head(&ret->hfontlist, &hflist->entry);
2712 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2713 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2714 original value lfCharSet. Note this is a special case for
2715 Symbol and doesn't happen at least for "Wingdings*" */
2717 if(!strcmpiW(lf.lfFaceName, SymbolW))
2718 lf.lfCharSet = SYMBOL_CHARSET;
2720 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2721 switch(lf.lfCharSet) {
2722 case DEFAULT_CHARSET:
2723 csi.fs.fsCsb[0] = 0;
2726 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2727 csi.fs.fsCsb[0] = 0;
2733 if(lf.lfFaceName[0] != '\0') {
2735 SYSTEM_LINKS *font_link;
2736 CHILD_FONT *font_link_entry;
2738 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2741 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2742 debugstr_w(psub->to.name));
2743 strcpyW(lf.lfFaceName, psub->to.name);
2746 /* We want a match on name and charset or just name if
2747 charset was DEFAULT_CHARSET. If the latter then
2748 we fixup the returned charset later in get_nearest_charset
2749 where we'll either use the charset of the current ansi codepage
2750 or if that's unavailable the first charset that the font supports.
2752 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2753 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2754 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2755 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2756 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2757 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2758 if(face->scalable || can_use_bitmap)
2765 * Try check the SystemLink list first for a replacement font.
2766 * We may find good replacements there.
2768 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2770 if(!strcmpW(font_link->font_name, lf.lfFaceName))
2772 TRACE("found entry in system list\n");
2773 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2775 face = find_face_from_path_index(font_link_entry->file_name,
2776 font_link_entry->index);
2779 family = face->family;
2780 if(csi.fs.fsCsb[0] &
2781 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2783 if(face->scalable || can_use_bitmap)
2792 /* If requested charset was DEFAULT_CHARSET then try using charset
2793 corresponding to the current ansi codepage */
2794 if(!csi.fs.fsCsb[0]) {
2796 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
2797 FIXME("TCI failed on codepage %d\n", acp);
2798 csi.fs.fsCsb[0] = 0;
2800 lf.lfCharSet = csi.ciCharset;
2803 /* Face families are in the top 4 bits of lfPitchAndFamily,
2804 so mask with 0xF0 before testing */
2806 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2807 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2808 strcpyW(lf.lfFaceName, defFixed);
2809 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2810 strcpyW(lf.lfFaceName, defSerif);
2811 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2812 strcpyW(lf.lfFaceName, defSans);
2814 strcpyW(lf.lfFaceName, defSans);
2815 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2816 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2817 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2818 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2819 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2820 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2821 if(face->scalable || can_use_bitmap)
2827 last_resort_family = NULL;
2828 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2829 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2830 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2831 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2832 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2835 if(can_use_bitmap && !last_resort_family)
2836 last_resort_family = family;
2841 if(last_resort_family) {
2842 family = last_resort_family;
2843 csi.fs.fsCsb[0] = 0;
2847 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2848 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2849 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2850 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2851 if(face->scalable) {
2852 csi.fs.fsCsb[0] = 0;
2853 WARN("just using first face for now\n");
2856 if(can_use_bitmap && !last_resort_family)
2857 last_resort_family = family;
2860 if(!last_resort_family) {
2861 FIXME("can't find a single appropriate font - bailing\n");
2866 WARN("could only find a bitmap font - this will probably look awful!\n");
2867 family = last_resort_family;
2868 csi.fs.fsCsb[0] = 0;
2871 it = lf.lfItalic ? 1 : 0;
2872 bd = lf.lfWeight > 550 ? 1 : 0;
2874 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2875 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2877 face = best = best_bitmap = NULL;
2878 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2880 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2882 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
2883 if(!best || new_score <= score)
2885 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
2886 face->Italic, face->Bold, it, bd);
2889 if(best->scalable && score == 0) break;
2893 newdiff = height - (signed int)(best->size.height);
2895 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
2896 if(!best_bitmap || new_score < score ||
2897 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
2899 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
2902 if(score == 0 && diff == 0) break;
2909 face = best->scalable ? best : best_bitmap;
2910 ret->fake_italic = (it && !face->Italic);
2911 ret->fake_bold = (bd && !face->Bold);
2913 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2915 if(csi.fs.fsCsb[0]) {
2916 ret->charset = lf.lfCharSet;
2917 ret->codepage = csi.ciACP;
2920 ret->charset = get_nearest_charset(face, &ret->codepage);
2922 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2923 debugstr_w(face->StyleName), face->file, face->face_index);
2925 if(!face->scalable) {
2926 width = face->size.x_ppem >> 6;
2927 height = face->size.y_ppem >> 6;
2929 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2937 if (ret->charset == SYMBOL_CHARSET &&
2938 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2941 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2945 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2948 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2949 ret->name = strdupW(family->FamilyName);
2950 ret->underline = lf.lfUnderline ? 0xff : 0;
2951 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2952 create_child_font_list(ret);
2954 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2956 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
2957 list_add_head(&gdi_font_list, &ret->entry);
2961 static void dump_gdi_font_list(void)
2964 struct list *elem_ptr;
2966 TRACE("---------- gdiFont Cache ----------\n");
2967 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2968 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2969 TRACE("gdiFont=%p %s %d\n",
2970 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2973 TRACE("---------- Unused gdiFont Cache ----------\n");
2974 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2975 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2976 TRACE("gdiFont=%p %s %d\n",
2977 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2981 /*************************************************************
2982 * WineEngDestroyFontInstance
2984 * free the gdiFont associated with this handle
2987 BOOL WineEngDestroyFontInstance(HFONT handle)
2992 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2995 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
2997 struct list *first_hfont = list_head(&gdiFont->hfontlist);
2998 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2999 if(hflist->hfont == handle)
3001 TRACE("removing child font %p from child list\n", gdiFont);
3002 list_remove(&gdiFont->entry);
3007 TRACE("destroying hfont=%p\n", handle);
3009 dump_gdi_font_list();
3011 font_elem_ptr = list_head(&gdi_font_list);
3012 while(font_elem_ptr) {
3013 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3014 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3016 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3017 while(hfontlist_elem_ptr) {
3018 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3019 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3020 if(hflist->hfont == handle) {
3021 list_remove(&hflist->entry);
3022 HeapFree(GetProcessHeap(), 0, hflist);
3026 if(list_empty(&gdiFont->hfontlist)) {
3027 TRACE("Moving to Unused list\n");
3028 list_remove(&gdiFont->entry);
3029 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3034 font_elem_ptr = list_head(&unused_gdi_font_list);
3035 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3036 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3037 while(font_elem_ptr) {
3038 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3039 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3040 TRACE("freeing %p\n", gdiFont);
3041 list_remove(&gdiFont->entry);
3047 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3048 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3050 OUTLINETEXTMETRICW *potm = NULL;
3052 TEXTMETRICW tm, *ptm;
3053 GdiFont *font = alloc_font();
3056 if(face->scalable) {
3060 height = face->size.y_ppem >> 6;
3061 width = face->size.x_ppem >> 6;
3064 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
3070 font->name = strdupW(face->family->FamilyName);
3072 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
3074 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
3076 potm = HeapAlloc(GetProcessHeap(), 0, size);
3077 WineEngGetOutlineTextMetrics(font, size, potm);
3078 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
3080 WineEngGetTextMetrics(font, &tm);
3084 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
3085 pntm->ntmTm.tmAscent = ptm->tmAscent;
3086 pntm->ntmTm.tmDescent = ptm->tmDescent;
3087 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
3088 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
3089 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
3090 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
3091 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
3092 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
3093 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
3094 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
3095 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
3096 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
3097 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
3098 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
3099 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
3100 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
3101 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
3102 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
3103 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
3104 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
3105 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3106 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3107 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3109 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
3110 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
3111 *ptype |= RASTER_FONTTYPE;
3113 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
3114 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
3115 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
3117 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3118 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3119 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
3122 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
3124 lstrcpynW(pelf->elfLogFont.lfFaceName,
3125 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
3127 lstrcpynW(pelf->elfFullName,
3128 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
3130 lstrcpynW(pelf->elfStyle,
3131 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
3134 HeapFree(GetProcessHeap(), 0, potm);
3136 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3138 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3139 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
3140 pelf->elfStyle[0] = '\0';
3143 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3148 /*************************************************************
3152 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3156 struct list *family_elem_ptr, *face_elem_ptr;
3158 NEWTEXTMETRICEXW ntm;
3159 DWORD type, ret = 1;
3165 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3167 if(plf->lfFaceName[0]) {
3169 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3172 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3173 debugstr_w(psub->to.name));
3174 memcpy(&lf, plf, sizeof(lf));
3175 strcpyW(lf.lfFaceName, psub->to.name);
3179 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3180 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3181 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3182 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3183 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3184 GetEnumStructs(face, &elf, &ntm, &type);
3185 for(i = 0; i < 32; i++) {
3186 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3187 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3188 strcpyW(elf.elfScript, OEM_DOSW);
3189 i = 32; /* break out of loop */
3190 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3193 fs.fsCsb[0] = 1L << i;
3195 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3197 csi.ciCharset = DEFAULT_CHARSET;
3198 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3199 if(csi.ciCharset != DEFAULT_CHARSET) {
3200 elf.elfLogFont.lfCharSet =
3201 ntm.ntmTm.tmCharSet = csi.ciCharset;
3203 strcpyW(elf.elfScript, ElfScriptsW[i]);
3205 FIXME("Unknown elfscript for bit %d\n", i);
3208 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3209 debugstr_w(elf.elfLogFont.lfFaceName),
3210 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3211 csi.ciCharset, type, debugstr_w(elf.elfScript),
3212 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3213 ntm.ntmTm.ntmFlags);
3214 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3221 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3222 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3223 face_elem_ptr = list_head(&family->faces);
3224 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3225 GetEnumStructs(face, &elf, &ntm, &type);
3226 for(i = 0; i < 32; i++) {
3227 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3228 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3229 strcpyW(elf.elfScript, OEM_DOSW);
3230 i = 32; /* break out of loop */
3231 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3234 fs.fsCsb[0] = 1L << i;
3236 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3238 csi.ciCharset = DEFAULT_CHARSET;
3239 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3240 if(csi.ciCharset != DEFAULT_CHARSET) {
3241 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3244 strcpyW(elf.elfScript, ElfScriptsW[i]);
3246 FIXME("Unknown elfscript for bit %d\n", i);
3249 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3250 debugstr_w(elf.elfLogFont.lfFaceName),
3251 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3252 csi.ciCharset, type, debugstr_w(elf.elfScript),
3253 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3254 ntm.ntmTm.ntmFlags);
3255 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3264 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3266 pt->x.value = vec->x >> 6;
3267 pt->x.fract = (vec->x & 0x3f) << 10;
3268 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3269 pt->y.value = vec->y >> 6;
3270 pt->y.fract = (vec->y & 0x3f) << 10;
3271 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3275 /***************************************************
3276 * According to the MSDN documentation on WideCharToMultiByte,
3277 * certain codepages cannot set the default_used parameter.
3278 * This returns TRUE if the codepage can set that parameter, false else
3279 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3281 static BOOL codepage_sets_default_used(UINT codepage)
3294 static FT_UInt get_glyph_index(GdiFont *font, UINT glyph)
3296 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
3297 WCHAR wc = (WCHAR)glyph;
3299 BOOL *default_used_pointer;
3302 default_used_pointer = NULL;
3303 default_used = FALSE;
3304 if (codepage_sets_default_used(font->codepage))
3305 default_used_pointer = &default_used;
3306 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
3309 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
3310 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
3314 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
3315 glyph = glyph + 0xf000;
3316 return pFT_Get_Char_Index(font->ft_face, glyph);
3319 /*************************************************************
3320 * WineEngGetGlyphIndices
3322 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3324 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
3325 LPWORD pgi, DWORD flags)
3328 WCHAR default_char = 0;
3331 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
3333 for(i = 0; i < count; i++)
3335 pgi[i] = get_glyph_index(font, lpstr[i]);
3340 WineEngGetTextMetrics(font, &textm);
3341 default_char = textm.tmDefaultChar;
3343 pgi[i] = default_char;
3349 /*************************************************************
3350 * WineEngGetGlyphOutline
3352 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3353 * except that the first parameter is the HWINEENGFONT of the font in
3354 * question rather than an HDC.
3357 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
3358 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3361 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3362 FT_Face ft_face = font->ft_face;
3363 FT_UInt glyph_index;
3364 DWORD width, height, pitch, needed = 0;
3365 FT_Bitmap ft_bitmap;
3367 INT left, right, top = 0, bottom = 0;
3369 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3370 float widthRatio = 1.0;
3371 FT_Matrix transMat = identityMat;
3372 BOOL needsTransform = FALSE;
3375 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
3376 buflen, buf, lpmat);
3378 if(format & GGO_GLYPH_INDEX) {
3379 glyph_index = glyph;
3380 format &= ~GGO_GLYPH_INDEX;
3382 glyph_index = get_glyph_index(font, glyph);
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 */