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_FTTYPES_H
106 #include <freetype/fttypes.h>
108 #ifdef HAVE_FREETYPE_FTSNAMES_H
109 #include <freetype/ftsnames.h>
111 # ifdef HAVE_FREETYPE_FTNAMES_H
112 # include <freetype/ftnames.h>
115 #ifdef HAVE_FREETYPE_TTNAMEID_H
116 #include <freetype/ttnameid.h>
118 #ifdef HAVE_FREETYPE_FTOUTLN_H
119 #include <freetype/ftoutln.h>
121 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
122 #include <freetype/internal/sfnt.h>
124 #ifdef HAVE_FREETYPE_FTTRIGON_H
125 #include <freetype/fttrigon.h>
127 #ifdef HAVE_FREETYPE_FTWINFNT_H
128 #include <freetype/ftwinfnt.h>
130 #ifdef HAVE_FREETYPE_FTMODAPI_H
131 #include <freetype/ftmodapi.h>
134 #ifndef HAVE_FT_TRUETYPEENGINETYPE
137 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
138 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
139 FT_TRUETYPE_ENGINE_TYPE_PATENTED
140 } FT_TrueTypeEngineType;
143 static FT_Library library = 0;
150 static FT_Version_t FT_Version;
151 static DWORD FT_SimpleVersion;
153 static void *ft_handle = NULL;
155 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
156 MAKE_FUNCPTR(FT_Vector_Unit);
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_Module);
160 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
163 MAKE_FUNCPTR(FT_Init_FreeType);
164 MAKE_FUNCPTR(FT_Load_Glyph);
165 MAKE_FUNCPTR(FT_Matrix_Multiply);
166 MAKE_FUNCPTR(FT_MulFix);
167 MAKE_FUNCPTR(FT_New_Face);
168 MAKE_FUNCPTR(FT_New_Memory_Face);
169 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
170 MAKE_FUNCPTR(FT_Outline_Transform);
171 MAKE_FUNCPTR(FT_Outline_Translate);
172 MAKE_FUNCPTR(FT_Select_Charmap);
173 MAKE_FUNCPTR(FT_Set_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 SONAME_LIBFONTCONFIG
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);
203 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
204 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
205 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
208 #ifndef ft_encoding_none
209 #define FT_ENCODING_NONE ft_encoding_none
211 #ifndef ft_encoding_ms_symbol
212 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
214 #ifndef ft_encoding_unicode
215 #define FT_ENCODING_UNICODE ft_encoding_unicode
217 #ifndef ft_encoding_apple_roman
218 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
221 #ifdef WORDS_BIGENDIAN
222 #define GET_BE_WORD(x) (x)
224 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
227 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
234 FT_Short internal_leading;
237 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
238 So to let this compile on older versions of FreeType we'll define the
239 new structure here. */
241 FT_Short height, width;
242 FT_Pos size, x_ppem, y_ppem;
245 typedef struct tagFace {
250 DWORD font_data_size;
255 FONTSIGNATURE fs_links;
256 DWORD ntmFlags; /* Only some bits stored here. Others are computed on the fly */
257 FT_Fixed font_version;
259 Bitmap_Size size; /* set if face is a bitmap */
260 BOOL external; /* TRUE if we should manually add this font to the registry */
261 struct tagFamily *family;
264 typedef struct tagFamily {
266 const WCHAR *FamilyName;
272 INT adv; /* These three hold to widths of the unrotated chars */
290 typedef struct tagHFONTLIST {
304 struct font_mapping *mapping;
315 struct list hfontlist;
320 OUTLINETEXTMETRICW *potm;
322 DWORD total_kern_pairs;
323 KERNINGPAIR *kern_pairs;
326 struct list child_fonts;
332 const WCHAR *font_name;
336 #define GM_BLOCK_SIZE 128
337 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
339 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
340 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
341 #define UNUSED_CACHE_SIZE 10
342 static struct list child_font_list = LIST_INIT(child_font_list);
343 static struct list system_links = LIST_INIT(system_links);
345 static struct list font_subst_list = LIST_INIT(font_subst_list);
347 static struct list font_list = LIST_INIT(font_list);
349 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
350 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
351 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
353 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
355 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
356 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
357 'W','i','n','d','o','w','s','\\',
358 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
359 'F','o','n','t','s','\0'};
361 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
362 'W','i','n','d','o','w','s',' ','N','T','\\',
363 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
364 'F','o','n','t','s','\0'};
366 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
367 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
368 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
369 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
371 static const WCHAR * const SystemFontValues[4] = {
378 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
379 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
381 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
382 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
383 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
384 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
385 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
386 'E','u','r','o','p','e','a','n','\0'};
387 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
388 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
389 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
390 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
391 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
392 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
393 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
394 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
395 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
396 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
397 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
398 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
400 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
410 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
418 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
427 typedef struct tagFontSubst {
443 static struct list mappings_list = LIST_INIT( mappings_list );
445 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
447 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
449 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
451 /****************************************
452 * Notes on .fon files
454 * The fonts System, FixedSys and Terminal are special. There are typically multiple
455 * versions installed for different resolutions and codepages. Windows stores which one to use
456 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
458 * FIXEDFON.FON FixedSys
460 * OEMFONT.FON Terminal
461 * LogPixels Current dpi set by the display control panel applet
462 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
463 * also has a LogPixels value that appears to mirror this)
465 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
466 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
467 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
468 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
469 * so that makes sense.
471 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
472 * to be mapped into the registry on Windows 2000 at least).
475 * ega80woa.fon=ega80850.fon
476 * ega40woa.fon=ega40850.fon
477 * cga80woa.fon=cga80850.fon
478 * cga40woa.fon=cga40850.fon
481 #ifdef HAVE_CARBON_CARBON_H
482 static char *find_cache_dir(void)
486 static char cached_path[MAX_PATH];
487 static const char *wine = "/Wine", *fonts = "/Fonts";
489 if(*cached_path) return cached_path;
491 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
494 WARN("can't create cached data folder\n");
497 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
500 WARN("can't create cached data path\n");
504 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
506 ERR("Could not create full path\n");
510 strcat(cached_path, wine);
512 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
514 WARN("Couldn't mkdir %s\n", cached_path);
518 strcat(cached_path, fonts);
519 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
521 WARN("Couldn't mkdir %s\n", cached_path);
528 /******************************************************************
531 * Extracts individual TrueType font files from a Mac suitcase font
532 * and saves them into the user's caches directory (see
534 * Returns a NULL terminated array of filenames.
536 * We do this because they are apps that try to read ttf files
537 * themselves and they don't like Mac suitcase files.
539 static char **expand_mac_font(const char *path)
546 const char *filename;
550 unsigned int size, max_size;
553 TRACE("path %s\n", path);
555 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
558 WARN("failed to get ref\n");
562 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
565 TRACE("no data fork, so trying resource fork\n");
566 res_ref = FSOpenResFile(&ref, fsRdPerm);
569 TRACE("unable to open resource fork\n");
576 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
579 CloseResFile(res_ref);
583 out_dir = find_cache_dir();
585 filename = strrchr(path, '/');
586 if(!filename) filename = path;
589 /* output filename has the form out_dir/filename_%04x.ttf */
590 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
597 unsigned short *num_faces_ptr, num_faces, face;
600 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
602 fond = Get1IndResource(fond_res, idx);
604 TRACE("got fond resource %d\n", idx);
607 fam_rec = *(FamRec**)fond;
608 num_faces_ptr = (unsigned short *)(fam_rec + 1);
609 num_faces = GET_BE_WORD(*num_faces_ptr);
611 assoc = (AsscEntry*)(num_faces_ptr + 1);
612 TRACE("num faces %04x\n", num_faces);
613 for(face = 0; face < num_faces; face++, assoc++)
616 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
617 unsigned short size, font_id;
620 size = GET_BE_WORD(assoc->fontSize);
621 font_id = GET_BE_WORD(assoc->fontID);
624 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
628 TRACE("trying to load sfnt id %04x\n", font_id);
629 sfnt = GetResource(sfnt_res, font_id);
632 TRACE("can't get sfnt resource %04x\n", font_id);
636 output = HeapAlloc(GetProcessHeap(), 0, output_len);
641 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
643 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
644 if(fd != -1 || errno == EEXIST)
648 unsigned char *sfnt_data;
651 sfnt_data = *(unsigned char**)sfnt;
652 write(fd, sfnt_data, GetHandleSize(sfnt));
656 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
659 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
661 ret.array[ret.size++] = output;
665 WARN("unable to create %s\n", output);
666 HeapFree(GetProcessHeap(), 0, output);
669 ReleaseResource(sfnt);
672 ReleaseResource(fond);
675 CloseResFile(res_ref);
680 #endif /* HAVE_CARBON_CARBON_H */
682 static inline BOOL is_win9x(void)
684 return GetVersion() & 0x80000000;
687 This function builds an FT_Fixed from a float. It puts the integer part
688 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
689 It fails if the integer part of the float number is greater than SHORT_MAX.
691 static inline FT_Fixed FT_FixedFromFloat(float f)
694 unsigned short fract = (f - value) * 0xFFFF;
695 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
699 This function builds an FT_Fixed from a FIXED. It simply put f.value
700 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
702 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
704 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
708 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
713 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
714 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
716 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
717 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
719 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
721 if(face_name && strcmpiW(face_name, family->FamilyName))
723 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
727 file = strrchr(face->file, '/');
732 if(!strcasecmp(file, file_nameA))
734 HeapFree(GetProcessHeap(), 0, file_nameA);
739 HeapFree(GetProcessHeap(), 0, file_nameA);
743 static Family *find_family_from_name(const WCHAR *name)
747 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
749 if(!strcmpiW(family->FamilyName, name))
756 static void DumpSubstList(void)
760 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
762 if(psub->from.charset != -1 || psub->to.charset != -1)
763 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
764 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
766 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
767 debugstr_w(psub->to.name));
772 static LPWSTR strdupW(LPCWSTR p)
775 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
776 ret = HeapAlloc(GetProcessHeap(), 0, len);
781 static LPSTR strdupA(LPCSTR p)
784 DWORD len = (strlen(p) + 1);
785 ret = HeapAlloc(GetProcessHeap(), 0, len);
790 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
795 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
797 if(!strcmpiW(element->from.name, from_name) &&
798 (element->from.charset == from_charset ||
799 element->from.charset == -1))
806 #define ADD_FONT_SUBST_FORCE 1
808 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
810 FontSubst *from_exist, *to_exist;
812 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
814 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
816 list_remove(&from_exist->entry);
817 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
818 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
819 HeapFree(GetProcessHeap(), 0, from_exist);
825 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
829 HeapFree(GetProcessHeap(), 0, subst->to.name);
830 subst->to.name = strdupW(to_exist->to.name);
833 list_add_tail(subst_list, &subst->entry);
838 HeapFree(GetProcessHeap(), 0, subst->from.name);
839 HeapFree(GetProcessHeap(), 0, subst->to.name);
840 HeapFree(GetProcessHeap(), 0, subst);
844 static void split_subst_info(NameCs *nc, LPSTR str)
846 CHAR *p = strrchr(str, ',');
851 nc->charset = strtol(p+1, NULL, 10);
854 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
855 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
856 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
859 static void LoadSubstList(void)
863 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
867 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
868 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
869 &hkey) == ERROR_SUCCESS) {
871 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
872 &valuelen, &datalen, NULL, NULL);
874 valuelen++; /* returned value doesn't include room for '\0' */
875 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
876 data = HeapAlloc(GetProcessHeap(), 0, datalen);
880 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
881 &dlen) == ERROR_SUCCESS) {
882 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
884 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
885 split_subst_info(&psub->from, value);
886 split_subst_info(&psub->to, data);
888 /* Win 2000 doesn't allow mapping between different charsets
889 or mapping of DEFAULT_CHARSET */
890 if((psub->to.charset != psub->from.charset) ||
891 psub->to.charset == DEFAULT_CHARSET) {
892 HeapFree(GetProcessHeap(), 0, psub->to.name);
893 HeapFree(GetProcessHeap(), 0, psub->from.name);
894 HeapFree(GetProcessHeap(), 0, psub);
896 add_font_subst(&font_subst_list, psub, 0);
898 /* reset dlen and vlen */
902 HeapFree(GetProcessHeap(), 0, data);
903 HeapFree(GetProcessHeap(), 0, value);
908 static WCHAR *get_familyname(FT_Face ft_face)
910 WCHAR *family = NULL;
912 FT_UInt num_names, name_index, i;
914 if(FT_IS_SFNT(ft_face))
916 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
918 for(name_index = 0; name_index < num_names; name_index++)
920 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
922 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
923 (name.language_id == GetUserDefaultLCID()) &&
924 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
925 (name.encoding_id == TT_MS_ID_UNICODE_CS))
927 /* String is not nul terminated and string_len is a byte length. */
928 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
929 for(i = 0; i < name.string_len / 2; i++)
931 WORD *tmp = (WORD *)&name.string[i * 2];
932 family[i] = GET_BE_WORD(*tmp);
936 TRACE("Got localised name %s\n", debugstr_w(family));
947 #define ADDFONT_EXTERNAL_FONT 0x01
948 #define ADDFONT_FORCE_BITMAP 0x02
949 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
953 TT_Header *pHeader = NULL;
954 WCHAR *english_family, *localised_family, *StyleW;
958 struct list *family_elem_ptr, *face_elem_ptr;
960 FT_Long face_index = 0, num_faces;
961 #ifdef HAVE_FREETYPE_FTWINFNT_H
962 FT_WinFNT_HeaderRec winfnt_header;
964 int i, bitmap_num, internal_leading;
967 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
968 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
970 #ifdef HAVE_CARBON_CARBON_H
971 if(file && !fake_family)
973 char **mac_list = expand_mac_font(file);
976 BOOL had_one = FALSE;
978 for(cursor = mac_list; *cursor; cursor++)
981 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
982 HeapFree(GetProcessHeap(), 0, *cursor);
984 HeapFree(GetProcessHeap(), 0, mac_list);
989 #endif /* HAVE_CARBON_CARBON_H */
992 char *family_name = fake_family;
996 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
997 err = pFT_New_Face(library, file, face_index, &ft_face);
1000 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1001 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1005 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1009 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*/
1010 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1011 pFT_Done_Face(ft_face);
1015 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1016 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1017 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1018 pFT_Done_Face(ft_face);
1022 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
1023 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1024 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
1025 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1026 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1027 pFT_Done_Face(ft_face);
1031 if(!ft_face->family_name || !ft_face->style_name) {
1032 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1033 pFT_Done_Face(ft_face);
1039 localised_family = get_familyname(ft_face);
1040 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1042 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1043 HeapFree(GetProcessHeap(), 0, localised_family);
1044 num_faces = ft_face->num_faces;
1045 pFT_Done_Face(ft_face);
1048 HeapFree(GetProcessHeap(), 0, localised_family);
1052 family_name = ft_face->family_name;
1056 My_FT_Bitmap_Size *size = NULL;
1059 if(!FT_IS_SCALABLE(ft_face))
1060 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1062 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1063 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1064 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1066 localised_family = NULL;
1068 localised_family = get_familyname(ft_face);
1069 if(localised_family && !strcmpW(localised_family, english_family)) {
1070 HeapFree(GetProcessHeap(), 0, localised_family);
1071 localised_family = NULL;
1076 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1077 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1078 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1083 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1084 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1085 list_init(&family->faces);
1086 list_add_tail(&font_list, &family->entry);
1088 if(localised_family) {
1089 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1090 subst->from.name = strdupW(english_family);
1091 subst->from.charset = -1;
1092 subst->to.name = strdupW(localised_family);
1093 subst->to.charset = -1;
1094 add_font_subst(&font_subst_list, subst, 0);
1097 HeapFree(GetProcessHeap(), 0, localised_family);
1098 HeapFree(GetProcessHeap(), 0, english_family);
1100 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1101 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1102 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1104 internal_leading = 0;
1105 memset(&fs, 0, sizeof(fs));
1107 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1109 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1110 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1111 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1112 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1113 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1114 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1115 if(pOS2->version == 0) {
1118 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1121 fs.fsCsb[0] |= 1L << 31;
1124 #ifdef HAVE_FREETYPE_FTWINFNT_H
1125 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1127 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1128 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1129 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1130 memcpy(&fs, &csi.fs, sizeof(csi.fs));
1131 internal_leading = winfnt_header.internal_leading;
1135 face_elem_ptr = list_head(&family->faces);
1136 while(face_elem_ptr) {
1137 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1138 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1139 if(!strcmpW(face->StyleName, StyleW) &&
1140 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1141 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1142 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1143 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1146 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1147 HeapFree(GetProcessHeap(), 0, StyleW);
1148 pFT_Done_Face(ft_face);
1151 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1152 TRACE("Original font is newer so skipping this one\n");
1153 HeapFree(GetProcessHeap(), 0, StyleW);
1154 pFT_Done_Face(ft_face);
1157 TRACE("Replacing original with this one\n");
1158 list_remove(&face->entry);
1159 HeapFree(GetProcessHeap(), 0, face->file);
1160 HeapFree(GetProcessHeap(), 0, face->StyleName);
1161 HeapFree(GetProcessHeap(), 0, face);
1166 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1167 list_add_tail(&family->faces, &face->entry);
1168 face->StyleName = StyleW;
1171 face->file = strdupA(file);
1172 face->font_data_ptr = NULL;
1173 face->font_data_size = 0;
1178 face->font_data_ptr = font_data_ptr;
1179 face->font_data_size = font_data_size;
1181 face->face_index = face_index;
1182 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
1183 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
1184 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1185 face->family = family;
1186 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1187 memcpy(&face->fs, &fs, sizeof(face->fs));
1188 memset(&face->fs_links, 0, sizeof(face->fs_links));
1190 if(FT_IS_SCALABLE(ft_face)) {
1191 memset(&face->size, 0, sizeof(face->size));
1192 face->scalable = TRUE;
1194 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1195 size->height, size->width, size->size >> 6,
1196 size->x_ppem >> 6, size->y_ppem >> 6);
1197 face->size.height = size->height;
1198 face->size.width = size->width;
1199 face->size.size = size->size;
1200 face->size.x_ppem = size->x_ppem;
1201 face->size.y_ppem = size->y_ppem;
1202 face->size.internal_leading = internal_leading;
1203 face->scalable = FALSE;
1206 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1208 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1210 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1211 face->ntmFlags = NTM_PS_OPENTYPE;
1216 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1217 face->fs.fsCsb[0], face->fs.fsCsb[1],
1218 face->fs.fsUsb[0], face->fs.fsUsb[1],
1219 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1222 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1223 for(i = 0; i < ft_face->num_charmaps; i++) {
1224 switch(ft_face->charmaps[i]->encoding) {
1225 case FT_ENCODING_UNICODE:
1226 case FT_ENCODING_APPLE_ROMAN:
1227 face->fs.fsCsb[0] |= 1;
1229 case FT_ENCODING_MS_SYMBOL:
1230 face->fs.fsCsb[0] |= 1L << 31;
1238 if(face->fs.fsCsb[0] & ~(1L << 31))
1239 have_installed_roman_font = TRUE;
1240 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1242 num_faces = ft_face->num_faces;
1243 pFT_Done_Face(ft_face);
1244 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1245 debugstr_w(StyleW));
1246 } while(num_faces > ++face_index);
1250 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1252 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1255 static void DumpFontList(void)
1259 struct list *family_elem_ptr, *face_elem_ptr;
1261 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1262 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1263 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1264 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1265 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1266 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1268 TRACE(" %d", face->size.height);
1275 /***********************************************************
1276 * The replacement list is a way to map an entire font
1277 * family onto another family. For example adding
1279 * [HKCU\Software\Wine\Fonts\Replacements]
1280 * "Wingdings"="Winedings"
1282 * would enumerate the Winedings font both as Winedings and
1283 * Wingdings. However if a real Wingdings font is present the
1284 * replacement does not take place.
1287 static void LoadReplaceList(void)
1290 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1295 struct list *family_elem_ptr, *face_elem_ptr;
1298 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1299 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1301 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1302 &valuelen, &datalen, NULL, NULL);
1304 valuelen++; /* returned value doesn't include room for '\0' */
1305 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1306 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1310 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1311 &dlen) == ERROR_SUCCESS) {
1312 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1313 /* "NewName"="Oldname" */
1314 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1316 /* Find the old family and hence all of the font files
1318 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1319 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1320 if(!strcmpiW(family->FamilyName, data)) {
1321 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1322 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1323 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1324 debugstr_w(face->StyleName), familyA);
1325 /* Now add a new entry with the new family name */
1326 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1331 /* reset dlen and vlen */
1335 HeapFree(GetProcessHeap(), 0, data);
1336 HeapFree(GetProcessHeap(), 0, value);
1341 /*************************************************************
1344 static BOOL init_system_links(void)
1346 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1347 'W','i','n','d','o','w','s',' ','N','T','\\',
1348 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1349 'S','y','s','t','e','m','L','i','n','k',0};
1352 DWORD type, max_val, max_data, val_len, data_len, index;
1353 WCHAR *value, *data;
1354 WCHAR *entry, *next;
1355 SYSTEM_LINKS *font_link, *system_font_link;
1356 CHILD_FONT *child_font;
1357 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1358 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1359 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1365 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1367 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1368 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1369 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1370 val_len = max_val + 1;
1371 data_len = max_data;
1373 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1375 TRACE("%s:\n", debugstr_w(value));
1377 memset(&fs, 0, sizeof(fs));
1378 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1379 psub = get_font_subst(&font_subst_list, value, -1);
1380 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1381 list_init(&font_link->links);
1382 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1385 CHILD_FONT *child_font;
1387 TRACE("\t%s\n", debugstr_w(entry));
1389 next = entry + strlenW(entry) + 1;
1391 face_name = strchrW(entry, ',');
1395 while(isspaceW(*face_name))
1398 psub = get_font_subst(&font_subst_list, face_name, -1);
1400 face_name = psub->to.name;
1402 face = find_face_from_filename(entry, face_name);
1405 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1409 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1410 child_font->face = face;
1411 child_font->font = NULL;
1412 fs.fsCsb[0] |= face->fs.fsCsb[0];
1413 fs.fsCsb[1] |= face->fs.fsCsb[1];
1414 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1415 list_add_tail(&font_link->links, &child_font->entry);
1417 family = find_family_from_name(font_link->font_name);
1420 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1422 memcpy(&face->fs_links, &fs, sizeof(fs));
1425 list_add_tail(&system_links, &font_link->entry);
1426 val_len = max_val + 1;
1427 data_len = max_data;
1430 HeapFree(GetProcessHeap(), 0, value);
1431 HeapFree(GetProcessHeap(), 0, data);
1435 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1438 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1439 system_font_link->font_name = strdupW(System);
1440 list_init(&system_font_link->links);
1442 face = find_face_from_filename(tahoma_ttf, Tahoma);
1445 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1446 child_font->face = face;
1447 child_font->font = NULL;
1448 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1449 list_add_tail(&system_font_link->links, &child_font->entry);
1451 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1453 if(!strcmpiW(font_link->font_name, Tahoma))
1455 CHILD_FONT *font_link_entry;
1456 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1458 CHILD_FONT *new_child;
1459 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1460 new_child->face = font_link_entry->face;
1461 new_child->font = NULL;
1462 list_add_tail(&system_font_link->links, &new_child->entry);
1467 list_add_tail(&system_links, &system_font_link->entry);
1471 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1474 struct dirent *dent;
1475 char path[MAX_PATH];
1477 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1479 dir = opendir(dirname);
1481 WARN("Can't open directory %s\n", debugstr_a(dirname));
1484 while((dent = readdir(dir)) != NULL) {
1485 struct stat statbuf;
1487 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1490 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1492 sprintf(path, "%s/%s", dirname, dent->d_name);
1494 if(stat(path, &statbuf) == -1)
1496 WARN("Can't stat %s\n", debugstr_a(path));
1499 if(S_ISDIR(statbuf.st_mode))
1500 ReadFontDir(path, external_fonts);
1502 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1508 static void load_fontconfig_fonts(void)
1510 #ifdef SONAME_LIBFONTCONFIG
1511 void *fc_handle = NULL;
1520 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1522 TRACE("Wine cannot find the fontconfig library (%s).\n",
1523 SONAME_LIBFONTCONFIG);
1526 #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;}
1527 LOAD_FUNCPTR(FcConfigGetCurrent);
1528 LOAD_FUNCPTR(FcFontList);
1529 LOAD_FUNCPTR(FcFontSetDestroy);
1530 LOAD_FUNCPTR(FcInit);
1531 LOAD_FUNCPTR(FcObjectSetAdd);
1532 LOAD_FUNCPTR(FcObjectSetCreate);
1533 LOAD_FUNCPTR(FcObjectSetDestroy);
1534 LOAD_FUNCPTR(FcPatternCreate);
1535 LOAD_FUNCPTR(FcPatternDestroy);
1536 LOAD_FUNCPTR(FcPatternGetBool);
1537 LOAD_FUNCPTR(FcPatternGetString);
1540 if(!pFcInit()) return;
1542 config = pFcConfigGetCurrent();
1543 pat = pFcPatternCreate();
1544 os = pFcObjectSetCreate();
1545 pFcObjectSetAdd(os, FC_FILE);
1546 pFcObjectSetAdd(os, FC_SCALABLE);
1547 fontset = pFcFontList(config, pat, os);
1548 if(!fontset) return;
1549 for(i = 0; i < fontset->nfont; i++) {
1552 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1554 TRACE("fontconfig: %s\n", file);
1556 /* We're just interested in OT/TT fonts for now, so this hack just
1557 picks up the scalable fonts without extensions .pf[ab] to save time
1558 loading every other font */
1560 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1562 TRACE("not scalable\n");
1566 len = strlen( file );
1567 if(len < 4) continue;
1568 ext = &file[ len - 3 ];
1569 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1570 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1572 pFcFontSetDestroy(fontset);
1573 pFcObjectSetDestroy(os);
1574 pFcPatternDestroy(pat);
1580 static BOOL load_font_from_data_dir(LPCWSTR file)
1583 const char *data_dir = wine_get_data_dir();
1585 if (!data_dir) data_dir = wine_get_build_dir();
1592 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1594 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1596 strcpy(unix_name, data_dir);
1597 strcat(unix_name, "/fonts/");
1599 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1601 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1602 HeapFree(GetProcessHeap(), 0, unix_name);
1607 static void load_system_fonts(void)
1610 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1611 const WCHAR * const *value;
1613 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1616 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1617 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1618 strcatW(windowsdir, fontsW);
1619 for(value = SystemFontValues; *value; value++) {
1620 dlen = sizeof(data);
1621 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1625 sprintfW(pathW, fmtW, windowsdir, data);
1626 if((unixname = wine_get_unix_file_name(pathW))) {
1627 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1628 HeapFree(GetProcessHeap(), 0, unixname);
1631 load_font_from_data_dir(data);
1638 /*************************************************************
1640 * This adds registry entries for any externally loaded fonts
1641 * (fonts from fontconfig or FontDirs). It also deletes entries
1642 * of no longer existing fonts.
1645 static void update_reg_entries(void)
1647 HKEY winkey = 0, externalkey = 0;
1650 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1653 struct list *family_elem_ptr, *face_elem_ptr;
1655 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1656 static const WCHAR spaceW[] = {' ', '\0'};
1659 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1660 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1661 ERR("Can't create Windows font reg key\n");
1664 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1665 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1666 ERR("Can't create external font reg key\n");
1670 /* Delete all external fonts added last time */
1672 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1673 &valuelen, &datalen, NULL, NULL);
1674 valuelen++; /* returned value doesn't include room for '\0' */
1675 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1676 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1678 dlen = datalen * sizeof(WCHAR);
1681 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1682 &dlen) == ERROR_SUCCESS) {
1684 RegDeleteValueW(winkey, valueW);
1685 /* reset dlen and vlen */
1689 HeapFree(GetProcessHeap(), 0, data);
1690 HeapFree(GetProcessHeap(), 0, valueW);
1692 /* Delete the old external fonts key */
1693 RegCloseKey(externalkey);
1695 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1697 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1698 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1699 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1700 ERR("Can't create external font reg key\n");
1704 /* enumerate the fonts and add external ones to the two keys */
1706 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1707 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1708 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1709 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1710 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1711 if(!face->external) continue;
1713 if(strcmpiW(face->StyleName, RegularW))
1714 len = len_fam + strlenW(face->StyleName) + 1;
1715 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1716 strcpyW(valueW, family->FamilyName);
1717 if(len != len_fam) {
1718 strcatW(valueW, spaceW);
1719 strcatW(valueW, face->StyleName);
1721 strcatW(valueW, TrueType);
1722 if((path = strrchr(face->file, '/')) == NULL)
1726 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1728 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1729 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1730 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1731 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1733 HeapFree(GetProcessHeap(), 0, file);
1734 HeapFree(GetProcessHeap(), 0, valueW);
1739 RegCloseKey(externalkey);
1741 RegCloseKey(winkey);
1746 /*************************************************************
1747 * WineEngAddFontResourceEx
1750 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1752 if (ft_handle) /* do it only if we have freetype up and running */
1757 FIXME("Ignoring flags %x\n", flags);
1759 if((unixname = wine_get_unix_file_name(file)))
1761 INT ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1762 HeapFree(GetProcessHeap(), 0, unixname);
1769 /*************************************************************
1770 * WineEngAddFontMemResourceEx
1773 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
1775 if (ft_handle) /* do it only if we have freetype up and running */
1777 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
1779 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
1780 memcpy(pFontCopy, pbFont, cbFont);
1782 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
1786 TRACE("AddFontToList failed\n");
1787 HeapFree(GetProcessHeap(), 0, pFontCopy);
1790 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
1791 * For now return something unique but quite random
1793 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
1794 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
1801 /*************************************************************
1802 * WineEngRemoveFontResourceEx
1805 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1811 static const struct nls_update_font_list
1813 UINT ansi_cp, oem_cp;
1814 const char *oem, *fixed, *system;
1815 const char *courier, *serif, *small, *sserif;
1816 /* these are for font substitute */
1817 const char *shelldlg, *tmsrmn;
1818 } nls_update_font_list[] =
1820 /* Latin 1 (United States) */
1821 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1822 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1823 "Tahoma","Times New Roman",
1825 /* Latin 1 (Multilingual) */
1826 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1827 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1828 "Tahoma","Times New Roman", /* FIXME unverified */
1830 /* Eastern Europe */
1831 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1832 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1833 "Tahoma","Times New Roman", /* FIXME unverified */
1836 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1837 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1838 "Tahoma","Times New Roman", /* FIXME unverified */
1841 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1842 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1843 "Tahoma","Times New Roman", /* FIXME unverified */
1846 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1847 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1848 "Tahoma","Times New Roman", /* FIXME unverified */
1851 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1852 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1853 "Tahoma","Times New Roman", /* FIXME unverified */
1856 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1857 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1858 "Tahoma","Times New Roman", /* FIXME unverified */
1861 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1862 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1863 "Tahoma","Times New Roman", /* FIXME unverified */
1866 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1867 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1868 "Tahoma","Times New Roman", /* FIXME unverified */
1871 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1872 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1873 "Tahoma","Times New Roman", /* FIXME unverified */
1876 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1877 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1878 "MS UI Gothic","MS Serif",
1880 /* Chinese Simplified */
1881 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1882 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1883 "Tahoma", "Times New Roman", /* FIXME unverified */
1886 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1887 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1890 /* Chinese Traditional */
1891 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1892 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1893 "Tahoma", "Times New Roman", /* FIXME unverified */
1897 static inline HKEY create_fonts_NT_registry_key(void)
1901 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1902 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1906 static inline HKEY create_fonts_9x_registry_key(void)
1910 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1911 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1915 static inline HKEY create_config_fonts_registry_key(void)
1919 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1920 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1924 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1926 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1927 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1928 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1929 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1932 static void update_font_info(void)
1934 char buf[40], cpbuf[40];
1937 UINT i, ansi_cp = 0, oem_cp = 0;
1939 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
1942 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1943 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1944 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1945 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1946 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
1949 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1951 if (!strcmp( buf, cpbuf )) /* already set correctly */
1956 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
1958 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
1960 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
1963 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1965 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1966 nls_update_font_list[i].oem_cp == oem_cp)
1970 hkey = create_config_fonts_registry_key();
1971 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1972 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1973 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1976 hkey = create_fonts_NT_registry_key();
1977 add_font_list(hkey, &nls_update_font_list[i]);
1980 hkey = create_fonts_9x_registry_key();
1981 add_font_list(hkey, &nls_update_font_list[i]);
1984 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
1986 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
1987 strlen(nls_update_font_list[i].shelldlg)+1);
1988 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
1989 strlen(nls_update_font_list[i].tmsrmn)+1);
1995 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
1998 /*************************************************************
2001 * Initialize FreeType library and create a list of available faces
2003 BOOL WineEngInit(void)
2005 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2006 static const WCHAR pathW[] = {'P','a','t','h',0};
2008 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2010 WCHAR windowsdir[MAX_PATH];
2013 const char *data_dir;
2017 /* update locale dependent font info in registry */
2020 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2023 "Wine cannot find the FreeType font library. To enable Wine to\n"
2024 "use TrueType fonts please install a version of FreeType greater than\n"
2025 "or equal to 2.0.5.\n"
2026 "http://www.freetype.org\n");
2030 #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;}
2032 LOAD_FUNCPTR(FT_Vector_Unit)
2033 LOAD_FUNCPTR(FT_Done_Face)
2034 LOAD_FUNCPTR(FT_Get_Char_Index)
2035 LOAD_FUNCPTR(FT_Get_Module)
2036 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2037 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2038 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2039 LOAD_FUNCPTR(FT_Init_FreeType)
2040 LOAD_FUNCPTR(FT_Load_Glyph)
2041 LOAD_FUNCPTR(FT_Matrix_Multiply)
2042 LOAD_FUNCPTR(FT_MulFix)
2043 LOAD_FUNCPTR(FT_New_Face)
2044 LOAD_FUNCPTR(FT_New_Memory_Face)
2045 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2046 LOAD_FUNCPTR(FT_Outline_Transform)
2047 LOAD_FUNCPTR(FT_Outline_Translate)
2048 LOAD_FUNCPTR(FT_Select_Charmap)
2049 LOAD_FUNCPTR(FT_Set_Charmap)
2050 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2051 LOAD_FUNCPTR(FT_Vector_Transform)
2054 /* Don't warn if this one is missing */
2055 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2056 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2057 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2058 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2059 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2060 #ifdef HAVE_FREETYPE_FTWINFNT_H
2061 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2063 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2064 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2065 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2066 <= 2.0.3 has FT_Sqrt64 */
2070 if(pFT_Init_FreeType(&library) != 0) {
2071 ERR("Can't init FreeType library\n");
2072 wine_dlclose(ft_handle, NULL, 0);
2076 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
2077 if (pFT_Library_Version)
2079 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2081 if (FT_Version.major<=0)
2087 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2088 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2089 ((FT_Version.minor << 8) & 0x00ff00) |
2090 ((FT_Version.patch ) & 0x0000ff);
2092 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2093 ERR("Failed to create font mutex\n");
2096 WaitForSingleObject(font_mutex, INFINITE);
2098 /* load the system bitmap fonts */
2099 load_system_fonts();
2101 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2102 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2103 strcatW(windowsdir, fontsW);
2104 if((unixname = wine_get_unix_file_name(windowsdir)))
2106 ReadFontDir(unixname, FALSE);
2107 HeapFree(GetProcessHeap(), 0, unixname);
2110 /* load the system truetype fonts */
2111 data_dir = wine_get_data_dir();
2112 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2113 strcpy(unixname, data_dir);
2114 strcat(unixname, "/fonts/");
2115 ReadFontDir(unixname, TRUE);
2116 HeapFree(GetProcessHeap(), 0, unixname);
2119 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2120 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2121 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2123 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2124 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2125 &hkey) == ERROR_SUCCESS) {
2127 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2128 &valuelen, &datalen, NULL, NULL);
2130 valuelen++; /* returned value doesn't include room for '\0' */
2131 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2132 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2135 dlen = datalen * sizeof(WCHAR);
2137 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2138 &dlen) == ERROR_SUCCESS) {
2139 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2141 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2143 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2144 HeapFree(GetProcessHeap(), 0, unixname);
2147 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2149 WCHAR pathW[MAX_PATH];
2150 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2153 sprintfW(pathW, fmtW, windowsdir, data);
2154 if((unixname = wine_get_unix_file_name(pathW)))
2156 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2157 HeapFree(GetProcessHeap(), 0, unixname);
2160 load_font_from_data_dir(data);
2162 /* reset dlen and vlen */
2167 HeapFree(GetProcessHeap(), 0, data);
2168 HeapFree(GetProcessHeap(), 0, valueW);
2172 load_fontconfig_fonts();
2174 /* then look in any directories that we've specified in the config file */
2175 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2176 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2182 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2184 len += sizeof(WCHAR);
2185 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2186 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2188 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2189 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2190 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2191 TRACE( "got font path %s\n", debugstr_a(valueA) );
2195 LPSTR next = strchr( ptr, ':' );
2196 if (next) *next++ = 0;
2197 ReadFontDir( ptr, TRUE );
2200 HeapFree( GetProcessHeap(), 0, valueA );
2202 HeapFree( GetProcessHeap(), 0, valueW );
2211 update_reg_entries();
2213 init_system_links();
2215 ReleaseMutex(font_mutex);
2219 "Wine cannot find certain functions that it needs inside the FreeType\n"
2220 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2221 "FreeType to at least version 2.0.5.\n"
2222 "http://www.freetype.org\n");
2223 wine_dlclose(ft_handle, NULL, 0);
2229 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2232 TT_HoriHeader *pHori;
2236 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2237 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2239 if(height == 0) height = 16;
2241 /* Calc. height of EM square:
2243 * For +ve lfHeight we have
2244 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2245 * Re-arranging gives:
2246 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2248 * For -ve lfHeight we have
2250 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2251 * with il = winAscent + winDescent - units_per_em]
2256 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2257 ppem = ft_face->units_per_EM * height /
2258 (pHori->Ascender - pHori->Descender);
2260 ppem = ft_face->units_per_EM * height /
2261 (pOS2->usWinAscent + pOS2->usWinDescent);
2269 static struct font_mapping *map_font_file( const char *name )
2271 struct font_mapping *mapping;
2275 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2276 if (fstat( fd, &st ) == -1) goto error;
2278 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2280 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2282 mapping->refcount++;
2287 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2290 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2293 if (mapping->data == MAP_FAILED)
2295 HeapFree( GetProcessHeap(), 0, mapping );
2298 mapping->refcount = 1;
2299 mapping->dev = st.st_dev;
2300 mapping->ino = st.st_ino;
2301 mapping->size = st.st_size;
2302 list_add_tail( &mappings_list, &mapping->entry );
2310 static void unmap_font_file( struct font_mapping *mapping )
2312 if (!--mapping->refcount)
2314 list_remove( &mapping->entry );
2315 munmap( mapping->data, mapping->size );
2316 HeapFree( GetProcessHeap(), 0, mapping );
2320 static LONG load_VDMX(GdiFont*, LONG);
2322 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2329 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2333 if (!(font->mapping = map_font_file( face->file )))
2335 WARN("failed to map %s\n", debugstr_a(face->file));
2338 data_ptr = font->mapping->data;
2339 data_size = font->mapping->size;
2343 data_ptr = face->font_data_ptr;
2344 data_size = face->font_data_size;
2347 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2349 ERR("FT_New_Face rets %d\n", err);
2353 /* set it here, as load_VDMX needs it */
2354 font->ft_face = ft_face;
2356 if(FT_IS_SCALABLE(ft_face)) {
2357 /* load the VDMX table if we have one */
2358 font->ppem = load_VDMX(font, height);
2360 font->ppem = calc_ppem_for_height(ft_face, height);
2362 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2363 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2365 font->ppem = height;
2366 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2367 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2373 static int get_nearest_charset(Face *face, int *cp)
2375 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2376 a single face with the requested charset. The idea is to check if
2377 the selected font supports the current ANSI codepage, if it does
2378 return the corresponding charset, else return the first charset */
2381 int acp = GetACP(), i;
2385 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2386 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2387 return csi.ciCharset;
2389 for(i = 0; i < 32; i++) {
2391 if(face->fs.fsCsb[0] & fs0) {
2392 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2394 return csi.ciCharset;
2397 FIXME("TCI failing on %x\n", fs0);
2401 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2402 face->fs.fsCsb[0], face->file);
2404 return DEFAULT_CHARSET;
2407 static GdiFont *alloc_font(void)
2409 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2411 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2412 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2414 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2415 ret->total_kern_pairs = (DWORD)-1;
2416 ret->kern_pairs = NULL;
2417 list_init(&ret->hfontlist);
2418 list_init(&ret->child_fonts);
2422 static void free_font(GdiFont *font)
2424 struct list *cursor, *cursor2;
2427 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2429 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2430 struct list *first_hfont;
2431 HFONTLIST *hfontlist;
2432 list_remove(cursor);
2435 first_hfont = list_head(&child->font->hfontlist);
2436 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2437 DeleteObject(hfontlist->hfont);
2438 HeapFree(GetProcessHeap(), 0, hfontlist);
2439 free_font(child->font);
2441 HeapFree(GetProcessHeap(), 0, child);
2444 if (font->ft_face) pFT_Done_Face(font->ft_face);
2445 if (font->mapping) unmap_font_file( font->mapping );
2446 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2447 HeapFree(GetProcessHeap(), 0, font->potm);
2448 HeapFree(GetProcessHeap(), 0, font->name);
2449 for (i = 0; i < font->gmsize; i++)
2450 HeapFree(GetProcessHeap(),0,font->gm[i]);
2451 HeapFree(GetProcessHeap(), 0, font->gm);
2452 HeapFree(GetProcessHeap(), 0, font);
2456 /*************************************************************
2459 * load the vdmx entry for the specified height
2462 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2463 ( ( (FT_ULong)_x4 << 24 ) | \
2464 ( (FT_ULong)_x3 << 16 ) | \
2465 ( (FT_ULong)_x2 << 8 ) | \
2468 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2483 static LONG load_VDMX(GdiFont *font, LONG height)
2487 BYTE devXRatio, devYRatio;
2488 USHORT numRecs, numRatios;
2489 DWORD result, offset = -1;
2493 /* For documentation on VDMX records, see
2494 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2497 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2499 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2502 /* FIXME: need the real device aspect ratio */
2506 numRecs = GET_BE_WORD(hdr[1]);
2507 numRatios = GET_BE_WORD(hdr[2]);
2509 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2510 for(i = 0; i < numRatios; i++) {
2513 offset = (3 * 2) + (i * sizeof(Ratios));
2514 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2517 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2519 if((ratio.xRatio == 0 &&
2520 ratio.yStartRatio == 0 &&
2521 ratio.yEndRatio == 0) ||
2522 (devXRatio == ratio.xRatio &&
2523 devYRatio >= ratio.yStartRatio &&
2524 devYRatio <= ratio.yEndRatio))
2526 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2527 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2528 offset = GET_BE_WORD(tmp);
2534 FIXME("No suitable ratio found\n");
2538 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2540 BYTE startsz, endsz;
2543 recs = GET_BE_WORD(group.recs);
2544 startsz = group.startsz;
2545 endsz = group.endsz;
2547 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2549 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2550 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2551 if(result == GDI_ERROR) {
2552 FIXME("Failed to retrieve vTable\n");
2557 for(i = 0; i < recs; i++) {
2558 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2559 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2560 ppem = GET_BE_WORD(vTable[i * 3]);
2562 if(yMax + -yMin == height) {
2565 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2568 if(yMax + -yMin > height) {
2571 goto end; /* failed */
2573 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2574 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2575 ppem = GET_BE_WORD(vTable[i * 3]);
2576 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2582 TRACE("ppem not found for height %d\n", height);
2586 if(ppem < startsz || ppem > endsz)
2589 for(i = 0; i < recs; i++) {
2591 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2593 if(yPelHeight > ppem)
2596 if(yPelHeight == ppem) {
2597 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2598 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2599 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2605 HeapFree(GetProcessHeap(), 0, vTable);
2611 static BOOL fontcmp(GdiFont *font, FONT_DESC *fd)
2613 if(font->font_desc.hash != fd->hash) return TRUE;
2614 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2615 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2616 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2617 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2620 static void calc_hash(FONT_DESC *pfd)
2622 DWORD hash = 0, *ptr, two_chars;
2626 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2628 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2630 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2632 pwc = (WCHAR *)&two_chars;
2634 *pwc = toupperW(*pwc);
2636 *pwc = toupperW(*pwc);
2640 hash ^= !pfd->can_use_bitmap;
2645 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2650 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2652 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2653 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2654 fd.can_use_bitmap = can_use_bitmap;
2657 /* try the in-use list */
2658 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2659 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2660 if(!fontcmp(ret, &fd)) {
2661 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2662 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2663 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2664 if(hflist->hfont == hfont)
2667 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2668 hflist->hfont = hfont;
2669 list_add_head(&ret->hfontlist, &hflist->entry);
2674 /* then the unused list */
2675 font_elem_ptr = list_head(&unused_gdi_font_list);
2676 while(font_elem_ptr) {
2677 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2678 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2679 if(!fontcmp(ret, &fd)) {
2680 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2681 assert(list_empty(&ret->hfontlist));
2682 TRACE("Found %p in unused list\n", ret);
2683 list_remove(&ret->entry);
2684 list_add_head(&gdi_font_list, &ret->entry);
2685 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2686 hflist->hfont = hfont;
2687 list_add_head(&ret->hfontlist, &hflist->entry);
2695 /*************************************************************
2696 * create_child_font_list
2698 static BOOL create_child_font_list(GdiFont *font)
2701 SYSTEM_LINKS *font_link;
2702 CHILD_FONT *font_link_entry, *new_child;
2704 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2706 if(!strcmpW(font_link->font_name, font->name))
2708 TRACE("found entry in system list\n");
2709 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2711 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2712 new_child->face = font_link_entry->face;
2713 new_child->font = NULL;
2714 list_add_tail(&font->child_fonts, &new_child->entry);
2715 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
2725 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
2727 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
2729 if (pFT_Set_Charmap)
2732 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
2734 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
2736 for (i = 0; i < ft_face->num_charmaps; i++)
2738 if (ft_face->charmaps[i]->encoding == encoding)
2740 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2741 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
2743 switch (ft_face->charmaps[i]->platform_id)
2746 cmap_def = ft_face->charmaps[i];
2748 case 0: /* Apple Unicode */
2749 cmap0 = ft_face->charmaps[i];
2751 case 1: /* Macintosh */
2752 cmap1 = ft_face->charmaps[i];
2755 cmap2 = ft_face->charmaps[i];
2757 case 3: /* Microsoft */
2758 cmap3 = ft_face->charmaps[i];
2763 if (cmap3) /* prefer Microsoft cmap table */
2764 ft_err = pFT_Set_Charmap(ft_face, cmap3);
2766 ft_err = pFT_Set_Charmap(ft_face, cmap1);
2768 ft_err = pFT_Set_Charmap(ft_face, cmap2);
2770 ft_err = pFT_Set_Charmap(ft_face, cmap0);
2772 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
2774 return ft_err == FT_Err_Ok;
2777 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
2780 /*************************************************************
2781 * WineEngCreateFontInstance
2784 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
2787 Face *face, *best, *best_bitmap;
2788 Family *family, *last_resort_family;
2789 struct list *family_elem_ptr, *face_elem_ptr;
2790 INT height, width = 0;
2791 unsigned int score = 0, new_score;
2792 signed int diff = 0, newdiff;
2793 BOOL bd, it, can_use_bitmap;
2798 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2800 struct list *first_hfont = list_head(&ret->hfontlist);
2801 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2802 if(hflist->hfont == hfont)
2806 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2807 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2809 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2810 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2811 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2814 /* check the cache first */
2815 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2816 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2820 TRACE("not in cache\n");
2821 if(list_empty(&font_list)) /* No fonts installed */
2823 TRACE("No fonts installed\n");
2826 if(!have_installed_roman_font)
2828 TRACE("No roman font installed\n");
2834 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2835 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2836 ret->font_desc.can_use_bitmap = can_use_bitmap;
2837 calc_hash(&ret->font_desc);
2838 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2839 hflist->hfont = hfont;
2840 list_add_head(&ret->hfontlist, &hflist->entry);
2843 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2844 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2845 original value lfCharSet. Note this is a special case for
2846 Symbol and doesn't happen at least for "Wingdings*" */
2848 if(!strcmpiW(lf.lfFaceName, SymbolW))
2849 lf.lfCharSet = SYMBOL_CHARSET;
2851 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2852 switch(lf.lfCharSet) {
2853 case DEFAULT_CHARSET:
2854 csi.fs.fsCsb[0] = 0;
2857 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2858 csi.fs.fsCsb[0] = 0;
2864 if(lf.lfFaceName[0] != '\0') {
2866 SYSTEM_LINKS *font_link;
2867 CHILD_FONT *font_link_entry;
2869 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2872 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2873 debugstr_w(psub->to.name));
2874 strcpyW(lf.lfFaceName, psub->to.name);
2877 /* We want a match on name and charset or just name if
2878 charset was DEFAULT_CHARSET. If the latter then
2879 we fixup the returned charset later in get_nearest_charset
2880 where we'll either use the charset of the current ansi codepage
2881 or if that's unavailable the first charset that the font supports.
2883 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2884 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2885 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2886 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2887 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2888 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2889 if(face->scalable || can_use_bitmap)
2896 * Try check the SystemLink list first for a replacement font.
2897 * We may find good replacements there.
2899 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2901 if(!strcmpiW(font_link->font_name, lf.lfFaceName))
2903 TRACE("found entry in system list\n");
2904 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2906 face = font_link_entry->face;
2907 family = face->family;
2908 if(csi.fs.fsCsb[0] &
2909 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
2911 if(face->scalable || can_use_bitmap)
2919 /* If requested charset was DEFAULT_CHARSET then try using charset
2920 corresponding to the current ansi codepage */
2921 if(!csi.fs.fsCsb[0]) {
2923 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
2924 FIXME("TCI failed on codepage %d\n", acp);
2925 csi.fs.fsCsb[0] = 0;
2927 lf.lfCharSet = csi.ciCharset;
2930 /* Face families are in the top 4 bits of lfPitchAndFamily,
2931 so mask with 0xF0 before testing */
2933 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2934 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2935 strcpyW(lf.lfFaceName, defFixed);
2936 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2937 strcpyW(lf.lfFaceName, defSerif);
2938 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2939 strcpyW(lf.lfFaceName, defSans);
2941 strcpyW(lf.lfFaceName, defSans);
2942 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2943 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2944 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2945 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2946 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2947 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2948 if(face->scalable || can_use_bitmap)
2954 last_resort_family = NULL;
2955 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2956 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2957 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2958 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2959 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2962 if(can_use_bitmap && !last_resort_family)
2963 last_resort_family = family;
2968 if(last_resort_family) {
2969 family = last_resort_family;
2970 csi.fs.fsCsb[0] = 0;
2974 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2975 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2976 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2977 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2978 if(face->scalable) {
2979 csi.fs.fsCsb[0] = 0;
2980 WARN("just using first face for now\n");
2983 if(can_use_bitmap && !last_resort_family)
2984 last_resort_family = family;
2987 if(!last_resort_family) {
2988 FIXME("can't find a single appropriate font - bailing\n");
2993 WARN("could only find a bitmap font - this will probably look awful!\n");
2994 family = last_resort_family;
2995 csi.fs.fsCsb[0] = 0;
2998 it = lf.lfItalic ? 1 : 0;
2999 bd = lf.lfWeight > 550 ? 1 : 0;
3001 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
3002 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
3004 face = best = best_bitmap = NULL;
3005 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3007 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3009 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
3010 if(!best || new_score <= score)
3012 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3013 face->Italic, face->Bold, it, bd);
3016 if(best->scalable && score == 0) break;
3020 newdiff = height - (signed int)(best->size.height);
3022 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3023 if(!best_bitmap || new_score < score ||
3024 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3026 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3029 if(score == 0 && diff == 0) break;
3036 face = best->scalable ? best : best_bitmap;
3037 ret->fake_italic = (it && !face->Italic);
3038 ret->fake_bold = (bd && !face->Bold);
3040 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
3042 if(csi.fs.fsCsb[0]) {
3043 ret->charset = lf.lfCharSet;
3044 ret->codepage = csi.ciACP;
3047 ret->charset = get_nearest_charset(face, &ret->codepage);
3049 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3050 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3052 if(!face->scalable) {
3053 width = face->size.x_ppem >> 6;
3054 height = face->size.y_ppem >> 6;
3056 ret->ft_face = OpenFontFace(ret, face, width, height);
3064 ret->ntmFlags = face->ntmFlags;
3066 if (ret->charset == SYMBOL_CHARSET &&
3067 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3070 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3074 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3077 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3078 ret->name = strdupW(family->FamilyName);
3079 ret->underline = lf.lfUnderline ? 0xff : 0;
3080 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3081 create_child_font_list(ret);
3083 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3085 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? abs(lf.lfWidth) : 0;
3086 list_add_head(&gdi_font_list, &ret->entry);
3090 static void dump_gdi_font_list(void)
3093 struct list *elem_ptr;
3095 TRACE("---------- gdiFont Cache ----------\n");
3096 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3097 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3098 TRACE("gdiFont=%p %s %d\n",
3099 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3102 TRACE("---------- Unused gdiFont Cache ----------\n");
3103 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3104 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3105 TRACE("gdiFont=%p %s %d\n",
3106 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3110 /*************************************************************
3111 * WineEngDestroyFontInstance
3113 * free the gdiFont associated with this handle
3116 BOOL WineEngDestroyFontInstance(HFONT handle)
3121 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3124 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3126 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3127 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3128 if(hflist->hfont == handle)
3130 TRACE("removing child font %p from child list\n", gdiFont);
3131 list_remove(&gdiFont->entry);
3136 TRACE("destroying hfont=%p\n", handle);
3138 dump_gdi_font_list();
3140 font_elem_ptr = list_head(&gdi_font_list);
3141 while(font_elem_ptr) {
3142 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3143 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3145 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3146 while(hfontlist_elem_ptr) {
3147 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3148 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3149 if(hflist->hfont == handle) {
3150 list_remove(&hflist->entry);
3151 HeapFree(GetProcessHeap(), 0, hflist);
3155 if(list_empty(&gdiFont->hfontlist)) {
3156 TRACE("Moving to Unused list\n");
3157 list_remove(&gdiFont->entry);
3158 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3163 font_elem_ptr = list_head(&unused_gdi_font_list);
3164 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3165 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3166 while(font_elem_ptr) {
3167 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3168 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3169 TRACE("freeing %p\n", gdiFont);
3170 list_remove(&gdiFont->entry);
3176 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3177 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3179 OUTLINETEXTMETRICW *potm = NULL;
3181 TEXTMETRICW tm, *ptm;
3182 GdiFont *font = alloc_font();
3185 if(face->scalable) {
3189 height = face->size.y_ppem >> 6;
3190 width = face->size.x_ppem >> 6;
3193 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3199 font->name = strdupW(face->family->FamilyName);
3200 font->ntmFlags = face->ntmFlags;
3202 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
3204 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
3206 potm = HeapAlloc(GetProcessHeap(), 0, size);
3207 WineEngGetOutlineTextMetrics(font, size, potm);
3208 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
3210 WineEngGetTextMetrics(font, &tm);
3214 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
3215 pntm->ntmTm.tmAscent = ptm->tmAscent;
3216 pntm->ntmTm.tmDescent = ptm->tmDescent;
3217 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
3218 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
3219 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
3220 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
3221 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
3222 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
3223 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
3224 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
3225 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
3226 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
3227 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
3228 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
3229 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
3230 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
3231 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
3232 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
3233 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
3234 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
3235 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3236 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3237 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3240 if (ptm->tmPitchAndFamily & TMPF_TRUETYPE)
3241 *ptype |= TRUETYPE_FONTTYPE;
3242 if (ptm->tmPitchAndFamily & TMPF_DEVICE)
3243 *ptype |= DEVICE_FONTTYPE;
3244 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
3245 *ptype |= RASTER_FONTTYPE;
3247 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
3248 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
3249 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
3250 pntm->ntmTm.ntmFlags |= face->ntmFlags;
3252 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3253 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3254 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
3257 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
3259 lstrcpynW(pelf->elfLogFont.lfFaceName,
3260 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
3262 lstrcpynW(pelf->elfFullName,
3263 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
3265 lstrcpynW(pelf->elfStyle,
3266 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
3269 HeapFree(GetProcessHeap(), 0, potm);
3271 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3273 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3274 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
3275 pelf->elfStyle[0] = '\0';
3278 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3283 /*************************************************************
3287 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3291 struct list *family_elem_ptr, *face_elem_ptr;
3293 NEWTEXTMETRICEXW ntm;
3294 DWORD type, ret = 1;
3300 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3302 if(plf->lfFaceName[0]) {
3304 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3307 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3308 debugstr_w(psub->to.name));
3309 memcpy(&lf, plf, sizeof(lf));
3310 strcpyW(lf.lfFaceName, psub->to.name);
3314 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3315 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3316 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3317 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3318 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3319 GetEnumStructs(face, &elf, &ntm, &type);
3320 for(i = 0; i < 32; i++) {
3321 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3322 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3323 strcpyW(elf.elfScript, OEM_DOSW);
3324 i = 32; /* break out of loop */
3325 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3328 fs.fsCsb[0] = 1L << i;
3330 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3332 csi.ciCharset = DEFAULT_CHARSET;
3333 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3334 if(csi.ciCharset != DEFAULT_CHARSET) {
3335 elf.elfLogFont.lfCharSet =
3336 ntm.ntmTm.tmCharSet = csi.ciCharset;
3338 strcpyW(elf.elfScript, ElfScriptsW[i]);
3340 FIXME("Unknown elfscript for bit %d\n", i);
3343 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3344 debugstr_w(elf.elfLogFont.lfFaceName),
3345 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3346 csi.ciCharset, type, debugstr_w(elf.elfScript),
3347 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3348 ntm.ntmTm.ntmFlags);
3349 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3356 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3357 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3358 face_elem_ptr = list_head(&family->faces);
3359 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3360 GetEnumStructs(face, &elf, &ntm, &type);
3361 for(i = 0; i < 32; i++) {
3362 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3363 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3364 strcpyW(elf.elfScript, OEM_DOSW);
3365 i = 32; /* break out of loop */
3366 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3369 fs.fsCsb[0] = 1L << i;
3371 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3373 csi.ciCharset = DEFAULT_CHARSET;
3374 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3375 if(csi.ciCharset != DEFAULT_CHARSET) {
3376 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3379 strcpyW(elf.elfScript, ElfScriptsW[i]);
3381 FIXME("Unknown elfscript for bit %d\n", i);
3384 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3385 debugstr_w(elf.elfLogFont.lfFaceName),
3386 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3387 csi.ciCharset, type, debugstr_w(elf.elfScript),
3388 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3389 ntm.ntmTm.ntmFlags);
3390 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3399 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3401 pt->x.value = vec->x >> 6;
3402 pt->x.fract = (vec->x & 0x3f) << 10;
3403 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3404 pt->y.value = vec->y >> 6;
3405 pt->y.fract = (vec->y & 0x3f) << 10;
3406 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3410 /***************************************************
3411 * According to the MSDN documentation on WideCharToMultiByte,
3412 * certain codepages cannot set the default_used parameter.
3413 * This returns TRUE if the codepage can set that parameter, false else
3414 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3416 static BOOL codepage_sets_default_used(UINT codepage)
3429 static FT_UInt get_glyph_index(GdiFont *font, UINT glyph)
3431 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
3432 WCHAR wc = (WCHAR)glyph;
3434 BOOL *default_used_pointer;
3437 default_used_pointer = NULL;
3438 default_used = FALSE;
3439 if (codepage_sets_default_used(font->codepage))
3440 default_used_pointer = &default_used;
3441 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
3444 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
3445 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
3449 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
3450 glyph = glyph + 0xf000;
3451 return pFT_Get_Char_Index(font->ft_face, glyph);
3454 /*************************************************************
3455 * WineEngGetGlyphIndices
3457 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3459 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
3460 LPWORD pgi, DWORD flags)
3463 WCHAR default_char = 0;
3466 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
3468 for(i = 0; i < count; i++)
3470 pgi[i] = get_glyph_index(font, lpstr[i]);
3475 WineEngGetTextMetrics(font, &textm);
3476 default_char = textm.tmDefaultChar;
3478 pgi[i] = default_char;
3484 /*************************************************************
3485 * WineEngGetGlyphOutline
3487 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3488 * except that the first parameter is the HWINEENGFONT of the font in
3489 * question rather than an HDC.
3492 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
3493 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3496 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3497 FT_Face ft_face = incoming_font->ft_face;
3498 GdiFont *font = incoming_font;
3499 FT_UInt glyph_index;
3500 DWORD width, height, pitch, needed = 0;
3501 FT_Bitmap ft_bitmap;
3503 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
3505 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3506 float widthRatio = 1.0;
3507 FT_Matrix transMat = identityMat;
3508 BOOL needsTransform = FALSE;
3511 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
3512 buflen, buf, lpmat);
3514 if(format & GGO_GLYPH_INDEX) {
3515 glyph_index = glyph;
3516 format &= ~GGO_GLYPH_INDEX;
3518 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
3519 ft_face = font->ft_face;
3522 if(glyph_index >= font->gmsize * GM_BLOCK_SIZE) {
3523 font->gmsize = (glyph_index / GM_BLOCK_SIZE + 1);
3524 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
3525 font->gmsize * sizeof(GM*));
3527 if(format == GGO_METRICS && font->gm[glyph_index / GM_BLOCK_SIZE] != NULL && FONT_GM(font,glyph_index)->init ) {
3528 *lpgm = FONT_GM(font,glyph_index)->gm;
3529 return 1; /* FIXME */
3533 if (!font->gm[glyph_index / GM_BLOCK_SIZE])
3534 font->gm[glyph_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3536 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || font->aveWidth || lpmat)
3537 load_flags |= FT_LOAD_NO_BITMAP;
3539 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
3542 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
3546 /* Scaling factor */
3547 if (font->aveWidth && font->potm) {
3548 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
3551 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3552 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3554 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3556 bbx = (right - left) >> 6;
3558 /* Scaling transform */
3559 if(font->aveWidth) {
3561 scaleMat.xx = FT_FixedFromFloat(widthRatio);
3564 scaleMat.yy = (1 << 16);
3566 pFT_Matrix_Multiply(&scaleMat, &transMat);
3567 needsTransform = TRUE;
3570 /* Slant transform */
3571 if (font->fake_italic) {
3574 slantMat.xx = (1 << 16);
3575 slantMat.xy = ((1 << 16) >> 2);
3577 slantMat.yy = (1 << 16);
3578 pFT_Matrix_Multiply(&slantMat, &transMat);
3579 needsTransform = TRUE;
3582 /* Rotation transform */
3583 if(font->orientation) {
3584 FT_Matrix rotationMat;
3586 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3587 pFT_Vector_Unit(&vecAngle, angle);
3588 rotationMat.xx = vecAngle.x;
3589 rotationMat.xy = -vecAngle.y;
3590 rotationMat.yx = -rotationMat.xy;
3591 rotationMat.yy = rotationMat.xx;
3593 pFT_Matrix_Multiply(&rotationMat, &transMat);
3594 needsTransform = TRUE;
3597 /* Extra transformation specified by caller */
3600 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3601 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3602 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3603 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3604 pFT_Matrix_Multiply(&extraMat, &transMat);
3605 needsTransform = TRUE;
3608 if(!needsTransform) {
3609 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3610 bottom = (ft_face->glyph->metrics.horiBearingY -
3611 ft_face->glyph->metrics.height) & -64;
3612 lpgm->gmCellIncX = adv;
3613 lpgm->gmCellIncY = 0;
3617 for(xc = 0; xc < 2; xc++) {
3618 for(yc = 0; yc < 2; yc++) {
3619 vec.x = (ft_face->glyph->metrics.horiBearingX +
3620 xc * ft_face->glyph->metrics.width);
3621 vec.y = ft_face->glyph->metrics.horiBearingY -
3622 yc * ft_face->glyph->metrics.height;
3623 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3624 pFT_Vector_Transform(&vec, &transMat);
3625 if(xc == 0 && yc == 0) {
3626 left = right = vec.x;
3627 top = bottom = vec.y;
3629 if(vec.x < left) left = vec.x;
3630 else if(vec.x > right) right = vec.x;
3631 if(vec.y < bottom) bottom = vec.y;
3632 else if(vec.y > top) top = vec.y;
3637 right = (right + 63) & -64;
3638 bottom = bottom & -64;
3639 top = (top + 63) & -64;
3641 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3642 vec.x = ft_face->glyph->metrics.horiAdvance;
3644 pFT_Vector_Transform(&vec, &transMat);
3645 lpgm->gmCellIncX = (vec.x+63) >> 6;
3646 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3648 lpgm->gmBlackBoxX = (right - left) >> 6;
3649 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3650 lpgm->gmptGlyphOrigin.x = left >> 6;
3651 lpgm->gmptGlyphOrigin.y = top >> 6;
3653 if(format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP)
3655 FONT_GM(font,glyph_index)->gm = *lpgm;
3656 FONT_GM(font,glyph_index)->adv = adv;
3657 FONT_GM(font,glyph_index)->lsb = lsb;
3658 FONT_GM(font,glyph_index)->bbx = bbx;
3659 FONT_GM(font,glyph_index)->init = TRUE;
3662 if(format == GGO_METRICS)
3663 return 1; /* FIXME */
3665 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
3666 TRACE("loaded a bitmap\n");
3672 width = lpgm->gmBlackBoxX;
3673 height = lpgm->gmBlackBoxY;
3674 pitch = ((width + 31) >> 5) << 2;
3675 needed = pitch * height;
3677 if(!buf || !buflen) break;
3679 switch(ft_face->glyph->format) {
3680 case ft_glyph_format_bitmap:
3682 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3683 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3684 INT h = ft_face->glyph->bitmap.rows;
3686 memcpy(dst, src, w);
3687 src += ft_face->glyph->bitmap.pitch;
3693 case ft_glyph_format_outline:
3694 ft_bitmap.width = width;
3695 ft_bitmap.rows = height;
3696 ft_bitmap.pitch = pitch;
3697 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3698 ft_bitmap.buffer = buf;
3700 if(needsTransform) {
3701 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3704 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3706 /* Note: FreeType will only set 'black' bits for us. */
3707 memset(buf, 0, needed);
3708 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3712 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3717 case GGO_GRAY2_BITMAP:
3718 case GGO_GRAY4_BITMAP:
3719 case GGO_GRAY8_BITMAP:
3720 case WINE_GGO_GRAY16_BITMAP:
3722 unsigned int mult, row, col;
3725 width = lpgm->gmBlackBoxX;
3726 height = lpgm->gmBlackBoxY;
3727 pitch = (width + 3) / 4 * 4;
3728 needed = pitch * height;
3730 if(!buf || !buflen) break;
3732 switch(ft_face->glyph->format) {
3733 case ft_glyph_format_bitmap:
3735 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3736 INT h = ft_face->glyph->bitmap.rows;
3739 for(x = 0; x < pitch; x++)
3740 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
3741 src += ft_face->glyph->bitmap.pitch;
3746 case ft_glyph_format_outline:
3748 ft_bitmap.width = width;
3749 ft_bitmap.rows = height;
3750 ft_bitmap.pitch = pitch;
3751 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3752 ft_bitmap.buffer = buf;
3755 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3757 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3759 memset(ft_bitmap.buffer, 0, buflen);
3761 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3763 if(format == GGO_GRAY2_BITMAP)
3765 else if(format == GGO_GRAY4_BITMAP)
3767 else if(format == GGO_GRAY8_BITMAP)
3769 else if(format == WINE_GGO_GRAY16_BITMAP)
3776 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3781 for(row = 0; row < height; row++) {
3783 for(col = 0; col < width; col++, ptr++) {
3784 *ptr = (((int)*ptr) * mult + 128) / 256;
3793 int contour, point = 0, first_pt;
3794 FT_Outline *outline = &ft_face->glyph->outline;
3795 TTPOLYGONHEADER *pph;
3797 DWORD pph_start, cpfx, type;
3799 if(buflen == 0) buf = NULL;
3801 if (needsTransform && buf) {
3802 pFT_Outline_Transform(outline, &transMat);
3805 for(contour = 0; contour < outline->n_contours; contour++) {
3807 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3810 pph->dwType = TT_POLYGON_TYPE;
3811 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3813 needed += sizeof(*pph);
3815 while(point <= outline->contours[contour]) {
3816 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3817 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3818 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3822 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3825 } while(point <= outline->contours[contour] &&
3826 (outline->tags[point] & FT_Curve_Tag_On) ==
3827 (outline->tags[point-1] & FT_Curve_Tag_On));
3828 /* At the end of a contour Windows adds the start point, but
3830 if(point > outline->contours[contour] &&
3831 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3833 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3835 } else if(point <= outline->contours[contour] &&
3836 outline->tags[point] & FT_Curve_Tag_On) {
3837 /* add closing pt for bezier */
3839 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3847 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3850 pph->cb = needed - pph_start;
3856 /* Convert the quadratic Beziers to cubic Beziers.
3857 The parametric eqn for a cubic Bezier is, from PLRM:
3858 r(t) = at^3 + bt^2 + ct + r0
3859 with the control points:
3864 A quadratic Beizer has the form:
3865 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3867 So equating powers of t leads to:
3868 r1 = 2/3 p1 + 1/3 p0
3869 r2 = 2/3 p1 + 1/3 p2
3870 and of course r0 = p0, r3 = p2
3873 int contour, point = 0, first_pt;
3874 FT_Outline *outline = &ft_face->glyph->outline;
3875 TTPOLYGONHEADER *pph;
3877 DWORD pph_start, cpfx, type;
3878 FT_Vector cubic_control[4];
3879 if(buflen == 0) buf = NULL;
3881 if (needsTransform && buf) {
3882 pFT_Outline_Transform(outline, &transMat);
3885 for(contour = 0; contour < outline->n_contours; contour++) {
3887 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3890 pph->dwType = TT_POLYGON_TYPE;
3891 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3893 needed += sizeof(*pph);
3895 while(point <= outline->contours[contour]) {
3896 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3897 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3898 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3901 if(type == TT_PRIM_LINE) {
3903 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3907 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3910 /* FIXME: Possible optimization in endpoint calculation
3911 if there are two consecutive curves */
3912 cubic_control[0] = outline->points[point-1];
3913 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3914 cubic_control[0].x += outline->points[point].x + 1;
3915 cubic_control[0].y += outline->points[point].y + 1;
3916 cubic_control[0].x >>= 1;
3917 cubic_control[0].y >>= 1;
3919 if(point+1 > outline->contours[contour])
3920 cubic_control[3] = outline->points[first_pt];
3922 cubic_control[3] = outline->points[point+1];
3923 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3924 cubic_control[3].x += outline->points[point].x + 1;
3925 cubic_control[3].y += outline->points[point].y + 1;
3926 cubic_control[3].x >>= 1;
3927 cubic_control[3].y >>= 1;
3930 /* r1 = 1/3 p0 + 2/3 p1
3931 r2 = 1/3 p2 + 2/3 p1 */
3932 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3933 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3934 cubic_control[2] = cubic_control[1];
3935 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3936 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3937 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3938 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3940 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3941 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3942 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3947 } while(point <= outline->contours[contour] &&
3948 (outline->tags[point] & FT_Curve_Tag_On) ==
3949 (outline->tags[point-1] & FT_Curve_Tag_On));
3950 /* At the end of a contour Windows adds the start point,
3951 but only for Beziers and we've already done that.
3953 if(point <= outline->contours[contour] &&
3954 outline->tags[point] & FT_Curve_Tag_On) {
3955 /* This is the closing pt of a bezier, but we've already
3956 added it, so just inc point and carry on */
3963 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3966 pph->cb = needed - pph_start;
3972 FIXME("Unsupported format %d\n", format);
3978 static BOOL get_bitmap_text_metrics(GdiFont *font)
3980 FT_Face ft_face = font->ft_face;
3981 #ifdef HAVE_FREETYPE_FTWINFNT_H
3982 FT_WinFNT_HeaderRec winfnt_header;
3984 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3985 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3986 font->potm->otmSize = size;
3988 #define TM font->potm->otmTextMetrics
3989 #ifdef HAVE_FREETYPE_FTWINFNT_H
3990 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3992 TM.tmHeight = winfnt_header.pixel_height;
3993 TM.tmAscent = winfnt_header.ascent;
3994 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3995 TM.tmInternalLeading = winfnt_header.internal_leading;
3996 TM.tmExternalLeading = winfnt_header.external_leading;
3997 TM.tmAveCharWidth = winfnt_header.avg_width;
3998 TM.tmMaxCharWidth = winfnt_header.max_width;
3999 TM.tmWeight = winfnt_header.weight;
4001 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4002 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4003 TM.tmFirstChar = winfnt_header.first_char;
4004 TM.tmLastChar = winfnt_header.last_char;
4005 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4006 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4007 TM.tmItalic = winfnt_header.italic;
4008 TM.tmUnderlined = font->underline;
4009 TM.tmStruckOut = font->strikeout;
4010 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4011 TM.tmCharSet = winfnt_header.charset;
4016 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4017 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4018 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4019 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4020 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4021 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4022 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4023 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4025 TM.tmDigitizedAspectX = 96; /* FIXME */
4026 TM.tmDigitizedAspectY = 96; /* FIXME */
4028 TM.tmLastChar = 255;
4029 TM.tmDefaultChar = 32;
4030 TM.tmBreakChar = 32;
4031 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4032 TM.tmUnderlined = font->underline;
4033 TM.tmStruckOut = font->strikeout;
4034 /* NB inverted meaning of TMPF_FIXED_PITCH */
4035 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4036 TM.tmCharSet = font->charset;
4043 /*************************************************************
4044 * WineEngGetTextMetrics
4047 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4050 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
4051 if(!get_bitmap_text_metrics(font))
4054 if(!font->potm) return FALSE;
4055 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
4057 if (font->aveWidth) {
4058 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
4064 /*************************************************************
4065 * WineEngGetOutlineTextMetrics
4068 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4069 OUTLINETEXTMETRICW *potm)
4071 FT_Face ft_face = font->ft_face;
4072 UINT needed, lenfam, lensty, ret;
4074 TT_HoriHeader *pHori;
4075 TT_Postscript *pPost;
4076 FT_Fixed x_scale, y_scale;
4077 WCHAR *family_nameW, *style_nameW;
4078 static const WCHAR spaceW[] = {' ', '\0'};
4080 INT ascent, descent;
4082 TRACE("font=%p\n", font);
4084 if(!FT_IS_SCALABLE(ft_face))
4088 if(cbSize >= font->potm->otmSize)
4089 memcpy(potm, font->potm, font->potm->otmSize);
4090 return font->potm->otmSize;
4094 needed = sizeof(*potm);
4096 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
4097 family_nameW = strdupW(font->name);
4099 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
4101 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
4102 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
4103 style_nameW, lensty/sizeof(WCHAR));
4105 /* These names should be read from the TT name table */
4107 /* length of otmpFamilyName */
4110 /* length of otmpFaceName */
4111 if(!strcasecmp(ft_face->style_name, "regular")) {
4112 needed += lenfam; /* just the family name */
4114 needed += lenfam + lensty; /* family + " " + style */
4117 /* length of otmpStyleName */
4120 /* length of otmpFullName */
4121 needed += lenfam + lensty;
4124 x_scale = ft_face->size->metrics.x_scale;
4125 y_scale = ft_face->size->metrics.y_scale;
4127 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4129 FIXME("Can't find OS/2 table - not TT font?\n");
4134 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4136 FIXME("Can't find HHEA table - not TT font?\n");
4141 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
4143 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",
4144 pOS2->usWinAscent, pOS2->usWinDescent,
4145 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
4146 ft_face->ascender, ft_face->descender, ft_face->height,
4147 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
4148 ft_face->bbox.yMax, ft_face->bbox.yMin);
4150 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
4151 font->potm->otmSize = needed;
4153 #define TM font->potm->otmTextMetrics
4155 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
4156 ascent = pHori->Ascender;
4157 descent = -pHori->Descender;
4159 ascent = pOS2->usWinAscent;
4160 descent = pOS2->usWinDescent;
4164 TM.tmAscent = font->yMax;
4165 TM.tmDescent = -font->yMin;
4166 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
4168 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
4169 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
4170 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
4171 - ft_face->units_per_EM, y_scale) + 32) >> 6;
4174 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4177 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4179 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
4180 ((ascent + descent) -
4181 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
4183 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
4184 if (TM.tmAveCharWidth == 0) {
4185 TM.tmAveCharWidth = 1;
4187 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
4188 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
4190 TM.tmDigitizedAspectX = 300;
4191 TM.tmDigitizedAspectY = 300;
4192 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4193 * symbol range to 0 - f0ff
4195 if (font->charset == SYMBOL_CHARSET)
4198 TM.tmFirstChar = pOS2->usFirstCharIndex;
4199 TM.tmLastChar = pOS2->usLastCharIndex;
4200 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4201 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
4202 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4203 TM.tmUnderlined = font->underline;
4204 TM.tmStruckOut = font->strikeout;
4206 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4207 if(!FT_IS_FIXED_WIDTH(ft_face) &&
4208 (pOS2->version == 0xFFFFU ||
4209 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4210 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
4212 TM.tmPitchAndFamily = 0;
4214 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
4215 case PAN_FAMILY_SCRIPT:
4216 TM.tmPitchAndFamily |= FF_SCRIPT;
4218 case PAN_FAMILY_DECORATIVE:
4219 case PAN_FAMILY_PICTORIAL:
4220 TM.tmPitchAndFamily |= FF_DECORATIVE;
4222 case PAN_FAMILY_TEXT_DISPLAY:
4223 if(TM.tmPitchAndFamily == 0) /* fixed */
4224 TM.tmPitchAndFamily = FF_MODERN;
4226 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
4227 case PAN_SERIF_NORMAL_SANS:
4228 case PAN_SERIF_OBTUSE_SANS:
4229 case PAN_SERIF_PERP_SANS:
4230 TM.tmPitchAndFamily |= FF_SWISS;
4233 TM.tmPitchAndFamily |= FF_ROMAN;
4238 TM.tmPitchAndFamily |= FF_DONTCARE;
4241 if(FT_IS_SCALABLE(ft_face))
4242 TM.tmPitchAndFamily |= TMPF_VECTOR;
4244 if(FT_IS_SFNT(ft_face))
4246 if (font->ntmFlags & NTM_PS_OPENTYPE)
4247 TM.tmPitchAndFamily |= TMPF_DEVICE;
4249 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
4252 TM.tmCharSet = font->charset;
4255 font->potm->otmFiller = 0;
4256 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
4257 font->potm->otmfsSelection = pOS2->fsSelection;
4258 font->potm->otmfsType = pOS2->fsType;
4259 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
4260 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
4261 font->potm->otmItalicAngle = 0; /* POST table */
4262 font->potm->otmEMSquare = ft_face->units_per_EM;
4263 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
4264 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4265 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4266 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
4267 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4268 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
4269 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
4270 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
4271 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4272 font->potm->otmMacAscent = 0; /* where do these come from ? */
4273 font->potm->otmMacDescent = 0;
4274 font->potm->otmMacLineGap = 0;
4275 font->potm->otmusMinimumPPEM = 0; /* TT Header */
4276 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
4277 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
4278 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
4279 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
4280 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
4281 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
4282 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
4283 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
4284 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
4285 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4287 font->potm->otmsUnderscoreSize = 0;
4288 font->potm->otmsUnderscorePosition = 0;
4290 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
4291 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
4294 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4295 cp = (char*)font->potm + sizeof(*font->potm);
4296 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4297 strcpyW((WCHAR*)cp, family_nameW);
4299 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4300 strcpyW((WCHAR*)cp, style_nameW);
4302 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4303 strcpyW((WCHAR*)cp, family_nameW);
4304 if(strcasecmp(ft_face->style_name, "regular")) {
4305 strcatW((WCHAR*)cp, spaceW);
4306 strcatW((WCHAR*)cp, style_nameW);
4307 cp += lenfam + lensty;
4310 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
4311 strcpyW((WCHAR*)cp, family_nameW);
4312 strcatW((WCHAR*)cp, spaceW);
4313 strcatW((WCHAR*)cp, style_nameW);
4316 if(potm && needed <= cbSize)
4317 memcpy(potm, font->potm, font->potm->otmSize);
4320 HeapFree(GetProcessHeap(), 0, style_nameW);
4321 HeapFree(GetProcessHeap(), 0, family_nameW);
4326 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
4328 HFONTLIST *hfontlist;
4329 child->font = alloc_font();
4330 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
4331 if(!child->font->ft_face)
4333 free_font(child->font);
4338 child->font->ntmFlags = child->face->ntmFlags;
4339 child->font->orientation = font->orientation;
4340 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
4341 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
4342 list_add_head(&child->font->hfontlist, &hfontlist->entry);
4343 child->font->base_font = font;
4344 list_add_head(&child_font_list, &child->font->entry);
4345 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
4349 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
4352 CHILD_FONT *child_font;
4355 font = font->base_font;
4357 *linked_font = font;
4359 if((*glyph = get_glyph_index(font, c)))
4362 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
4364 if(!child_font->font)
4365 if(!load_child_font(font, child_font))
4368 if(!child_font->font->ft_face)
4370 g = get_glyph_index(child_font->font, c);
4374 *linked_font = child_font->font;
4381 /*************************************************************
4382 * WineEngGetCharWidth
4385 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4390 FT_UInt glyph_index;
4391 GdiFont *linked_font;
4393 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4395 for(c = firstChar; c <= lastChar; c++) {
4396 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4397 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4398 &gm, 0, NULL, NULL);
4399 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
4404 /*************************************************************
4405 * WineEngGetCharABCWidths
4408 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4413 FT_UInt glyph_index;
4414 GdiFont *linked_font;
4416 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4418 if(!FT_IS_SCALABLE(font->ft_face))
4421 for(c = firstChar; c <= lastChar; c++) {
4422 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4423 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4424 &gm, 0, NULL, NULL);
4425 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
4426 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
4427 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
4428 FONT_GM(linked_font,glyph_index)->bbx;
4433 /*************************************************************
4434 * WineEngGetCharABCWidthsI
4437 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4442 FT_UInt glyph_index;
4443 GdiFont *linked_font;
4445 if(!FT_IS_SCALABLE(font->ft_face))
4448 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
4450 for(c = firstChar; c < firstChar+count; c++) {
4451 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
4452 &gm, 0, NULL, NULL);
4453 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
4454 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
4455 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
4456 - FONT_GM(linked_font,c)->bbx;
4459 for(c = 0; c < count; c++) {
4460 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
4461 &gm, 0, NULL, NULL);
4462 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
4463 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
4464 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
4465 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
4471 /*************************************************************
4472 * WineEngGetTextExtentExPoint
4475 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4476 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4482 FT_UInt glyph_index;
4483 GdiFont *linked_font;
4485 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
4489 WineEngGetTextMetrics(font, &tm);
4490 size->cy = tm.tmHeight;
4492 for(idx = 0; idx < count; idx++) {
4493 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
4494 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4495 &gm, 0, NULL, NULL);
4496 size->cx += FONT_GM(linked_font,glyph_index)->adv;
4498 if (! pnfit || ext <= max_ext) {
4508 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4512 /*************************************************************
4513 * WineEngGetTextExtentPointI
4516 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4523 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
4526 WineEngGetTextMetrics(font, &tm);
4527 size->cy = tm.tmHeight;
4529 for(idx = 0; idx < count; idx++) {
4530 WineEngGetGlyphOutline(font, indices[idx],
4531 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
4533 size->cx += FONT_GM(font,indices[idx])->adv;
4535 TRACE("return %d,%d\n", size->cx, size->cy);
4539 /*************************************************************
4540 * WineEngGetFontData
4543 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4546 FT_Face ft_face = font->ft_face;
4550 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
4551 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
4552 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
4554 if(!FT_IS_SFNT(ft_face))
4562 if(table) { /* MS tags differ in endidness from FT ones */
4563 table = table >> 24 | table << 24 |
4564 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
4567 /* If the FT_Load_Sfnt_Table function is there we'll use it */
4568 if(pFT_Load_Sfnt_Table) {
4569 /* make sure value of len is the value freetype says it needs */
4571 FT_ULong needed = 0;
4572 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4573 if( !err && needed < len) len = needed;
4575 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4577 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
4578 else { /* Do it the hard way */
4579 TT_Face tt_face = (TT_Face) ft_face;
4580 SFNT_Interface *sfnt;
4581 if (FT_Version.major==2 && FT_Version.minor==0)
4584 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
4588 /* A field was added in the middle of the structure in 2.1.x */
4589 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
4591 /* make sure value of len is the value freetype says it needs */
4593 FT_ULong needed = 0;
4594 err = sfnt->load_any(tt_face, table, offset, NULL, &needed);
4595 if( !err && needed < len) len = needed;
4597 err = sfnt->load_any(tt_face, table, offset, buf, &len);
4603 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
4604 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
4605 "Please upgrade your freetype library.\n");
4608 err = FT_Err_Unimplemented_Feature;
4612 TRACE("Can't find table %c%c%c%c\n",
4613 /* bytes were reversed */
4614 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4615 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4621 /*************************************************************
4622 * WineEngGetTextFace
4625 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4628 lstrcpynW(str, font->name, count);
4629 return strlenW(font->name);
4631 return strlenW(font->name) + 1;
4634 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4636 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4637 return font->charset;
4640 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4642 GdiFont *font = dc->gdiFont, *linked_font;
4643 struct list *first_hfont;
4646 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4647 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4648 if(font == linked_font)
4649 *new_hfont = dc->hFont;
4652 first_hfont = list_head(&linked_font->hfontlist);
4653 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4659 /* Retrieve a list of supported Unicode ranges for a given font.
4660 * Can be called with NULL gs to calculate the buffer size. Returns
4661 * the number of ranges found.
4663 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
4665 DWORD num_ranges = 0;
4667 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4670 FT_ULong char_code, char_code_prev;
4673 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
4675 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4676 face->num_glyphs, glyph_code, char_code);
4678 if (!glyph_code) return 0;
4682 gs->ranges[0].wcLow = (USHORT)char_code;
4683 gs->ranges[0].cGlyphs = 0;
4684 gs->cGlyphsSupported = 0;
4690 if (char_code < char_code_prev)
4692 ERR("expected increasing char code from FT_Get_Next_Char\n");
4695 if (char_code - char_code_prev > 1)
4700 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4701 gs->ranges[num_ranges - 1].cGlyphs = 1;
4702 gs->cGlyphsSupported++;
4707 gs->ranges[num_ranges - 1].cGlyphs++;
4708 gs->cGlyphsSupported++;
4710 char_code_prev = char_code;
4711 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
4715 FIXME("encoding %u not supported\n", face->charmap->encoding);
4720 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
4723 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
4725 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
4728 glyphset->cbThis = size;
4729 glyphset->cRanges = num_ranges;
4734 /*************************************************************
4737 BOOL WineEngFontIsLinked(GdiFont *font)
4739 return !list_empty(&font->child_fonts);
4742 static BOOL is_hinting_enabled(void)
4744 /* Use the >= 2.2.0 function if available */
4745 if(pFT_Get_TrueType_Engine_Type)
4747 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4748 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4750 #ifdef FT_DRIVER_HAS_HINTER
4755 /* otherwise if we've been compiled with < 2.2.0 headers
4756 use the internal macro */
4757 mod = pFT_Get_Module(library, "truetype");
4758 if(mod && FT_DRIVER_HAS_HINTER(mod))
4766 /*************************************************************************
4767 * GetRasterizerCaps (GDI32.@)
4769 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4771 static int hinting = -1;
4775 hinting = is_hinting_enabled();
4776 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
4779 lprs->nSize = sizeof(RASTERIZER_STATUS);
4780 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4781 lprs->nLanguageID = 0;
4785 /*************************************************************************
4786 * Kerning support for TrueType fonts
4788 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4790 struct TT_kern_table
4796 struct TT_kern_subtable
4805 USHORT horizontal : 1;
4807 USHORT cross_stream: 1;
4808 USHORT override : 1;
4809 USHORT reserved1 : 4;
4815 struct TT_format0_kern_subtable
4819 USHORT entrySelector;
4830 static DWORD parse_format0_kern_subtable(GdiFont *font,
4831 const struct TT_format0_kern_subtable *tt_f0_ks,
4832 const USHORT *glyph_to_char,
4833 KERNINGPAIR *kern_pair, DWORD cPairs)
4836 const struct TT_kern_pair *tt_kern_pair;
4838 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
4840 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4842 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4843 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4844 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4846 if (!kern_pair || !cPairs)
4849 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4851 nPairs = min(nPairs, cPairs);
4853 for (i = 0; i < nPairs; i++)
4855 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4856 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4857 /* this algorithm appears to better match what Windows does */
4858 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4859 if (kern_pair->iKernAmount < 0)
4861 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
4862 kern_pair->iKernAmount -= font->ppem;
4864 else if (kern_pair->iKernAmount > 0)
4866 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
4867 kern_pair->iKernAmount += font->ppem;
4869 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
4871 TRACE("left %u right %u value %d\n",
4872 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
4876 TRACE("copied %u entries\n", nPairs);
4880 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4884 const struct TT_kern_table *tt_kern_table;
4885 const struct TT_kern_subtable *tt_kern_subtable;
4887 USHORT *glyph_to_char;
4889 if (font->total_kern_pairs != (DWORD)-1)
4891 if (cPairs && kern_pair)
4893 cPairs = min(cPairs, font->total_kern_pairs);
4894 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4897 return font->total_kern_pairs;
4900 font->total_kern_pairs = 0;
4902 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
4904 if (length == GDI_ERROR)
4906 TRACE("no kerning data in the font\n");
4910 buf = HeapAlloc(GetProcessHeap(), 0, length);
4913 WARN("Out of memory\n");
4917 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
4919 /* build a glyph index to char code map */
4920 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
4923 WARN("Out of memory allocating a glyph index to char code map\n");
4924 HeapFree(GetProcessHeap(), 0, buf);
4928 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4934 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
4936 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4937 font->ft_face->num_glyphs, glyph_code, char_code);
4941 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4943 /* FIXME: This doesn't match what Windows does: it does some fancy
4944 * things with duplicate glyph index to char code mappings, while
4945 * we just avoid overriding existing entries.
4947 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
4948 glyph_to_char[glyph_code] = (USHORT)char_code;
4950 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
4957 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
4958 for (n = 0; n <= 65535; n++)
4959 glyph_to_char[n] = (USHORT)n;
4962 tt_kern_table = buf;
4963 nTables = GET_BE_WORD(tt_kern_table->nTables);
4964 TRACE("version %u, nTables %u\n",
4965 GET_BE_WORD(tt_kern_table->version), nTables);
4967 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
4969 for (i = 0; i < nTables; i++)
4971 struct TT_kern_subtable tt_kern_subtable_copy;
4973 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
4974 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
4975 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
4977 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4978 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
4979 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
4981 /* According to the TrueType specification this is the only format
4982 * that will be properly interpreted by Windows and OS/2
4984 if (tt_kern_subtable_copy.coverage.bits.format == 0)
4986 DWORD new_chunk, old_total = font->total_kern_pairs;
4988 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4989 glyph_to_char, NULL, 0);
4990 font->total_kern_pairs += new_chunk;
4992 if (!font->kern_pairs)
4993 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
4994 font->total_kern_pairs * sizeof(*font->kern_pairs));
4996 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
4997 font->total_kern_pairs * sizeof(*font->kern_pairs));
4999 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5000 glyph_to_char, font->kern_pairs + old_total, new_chunk);
5003 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
5005 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
5008 HeapFree(GetProcessHeap(), 0, glyph_to_char);
5009 HeapFree(GetProcessHeap(), 0, buf);
5011 if (cPairs && kern_pair)
5013 cPairs = min(cPairs, font->total_kern_pairs);
5014 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5017 return font->total_kern_pairs;
5020 #else /* HAVE_FREETYPE */
5022 /*************************************************************************/
5024 BOOL WineEngInit(void)
5028 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
5032 BOOL WineEngDestroyFontInstance(HFONT hfont)
5037 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
5042 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
5043 LPWORD pgi, DWORD flags)
5048 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
5049 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5052 ERR("called but we don't have FreeType\n");
5056 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5058 ERR("called but we don't have FreeType\n");
5062 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5063 OUTLINETEXTMETRICW *potm)
5065 ERR("called but we don't have FreeType\n");
5069 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5072 ERR("called but we don't have FreeType\n");
5076 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5079 ERR("called but we don't have FreeType\n");
5083 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5086 ERR("called but we don't have FreeType\n");
5090 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5091 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5093 ERR("called but we don't have FreeType\n");
5097 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
5100 ERR("called but we don't have FreeType\n");
5104 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5107 ERR("called but we don't have FreeType\n");
5111 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5113 ERR("called but we don't have FreeType\n");
5117 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5123 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5129 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
5135 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5138 return DEFAULT_CHARSET;
5141 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5146 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5148 FIXME("(%p, %p): stub\n", font, glyphset);
5152 BOOL WineEngFontIsLinked(GdiFont *font)
5157 /*************************************************************************
5158 * GetRasterizerCaps (GDI32.@)
5160 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5162 lprs->nSize = sizeof(RASTERIZER_STATUS);
5164 lprs->nLanguageID = 0;
5168 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5170 ERR("called but we don't have FreeType\n");
5174 #endif /* HAVE_FREETYPE */