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 /*****************************************************************
950 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
951 * of FreeType that don't export this function.
954 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
959 /* If the FT_Load_Sfnt_Table function is there we'll use it */
960 if(pFT_Load_Sfnt_Table)
962 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
964 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
965 else /* Do it the hard way */
967 TT_Face tt_face = (TT_Face) ft_face;
968 SFNT_Interface *sfnt;
969 if (FT_Version.major==2 && FT_Version.minor==0)
972 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
976 /* A field was added in the middle of the structure in 2.1.x */
977 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
979 err = sfnt->load_any(tt_face, table, offset, buf, len);
987 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
988 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
989 "Please upgrade your freetype library.\n");
992 err = FT_Err_Unimplemented_Feature;
999 #define ADDFONT_EXTERNAL_FONT 0x01
1000 #define ADDFONT_FORCE_BITMAP 0x02
1001 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1005 TT_Header *pHeader = NULL;
1006 WCHAR *english_family, *localised_family, *StyleW;
1010 struct list *family_elem_ptr, *face_elem_ptr;
1012 FT_Long face_index = 0, num_faces;
1013 #ifdef HAVE_FREETYPE_FTWINFNT_H
1014 FT_WinFNT_HeaderRec winfnt_header;
1016 int i, bitmap_num, internal_leading;
1019 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1020 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1022 #ifdef HAVE_CARBON_CARBON_H
1023 if(file && !fake_family)
1025 char **mac_list = expand_mac_font(file);
1028 BOOL had_one = FALSE;
1030 for(cursor = mac_list; *cursor; cursor++)
1033 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1034 HeapFree(GetProcessHeap(), 0, *cursor);
1036 HeapFree(GetProcessHeap(), 0, mac_list);
1041 #endif /* HAVE_CARBON_CARBON_H */
1044 char *family_name = fake_family;
1048 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1049 err = pFT_New_Face(library, file, face_index, &ft_face);
1052 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1053 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1057 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1061 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*/
1062 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1063 pFT_Done_Face(ft_face);
1067 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1068 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1069 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1070 pFT_Done_Face(ft_face);
1074 if(FT_IS_SFNT(ft_face))
1076 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1077 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1078 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1080 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1081 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1082 pFT_Done_Face(ft_face);
1086 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1087 we don't want to load these. */
1088 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1092 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1094 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1095 pFT_Done_Face(ft_face);
1101 if(!ft_face->family_name || !ft_face->style_name) {
1102 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1103 pFT_Done_Face(ft_face);
1109 localised_family = get_familyname(ft_face);
1110 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1112 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1113 HeapFree(GetProcessHeap(), 0, localised_family);
1114 num_faces = ft_face->num_faces;
1115 pFT_Done_Face(ft_face);
1118 HeapFree(GetProcessHeap(), 0, localised_family);
1122 family_name = ft_face->family_name;
1126 My_FT_Bitmap_Size *size = NULL;
1129 if(!FT_IS_SCALABLE(ft_face))
1130 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1132 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1133 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1134 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1136 localised_family = NULL;
1138 localised_family = get_familyname(ft_face);
1139 if(localised_family && !strcmpW(localised_family, english_family)) {
1140 HeapFree(GetProcessHeap(), 0, localised_family);
1141 localised_family = NULL;
1146 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1147 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1148 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1153 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1154 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1155 list_init(&family->faces);
1156 list_add_tail(&font_list, &family->entry);
1158 if(localised_family) {
1159 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1160 subst->from.name = strdupW(english_family);
1161 subst->from.charset = -1;
1162 subst->to.name = strdupW(localised_family);
1163 subst->to.charset = -1;
1164 add_font_subst(&font_subst_list, subst, 0);
1167 HeapFree(GetProcessHeap(), 0, localised_family);
1168 HeapFree(GetProcessHeap(), 0, english_family);
1170 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1171 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1172 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1174 internal_leading = 0;
1175 memset(&fs, 0, sizeof(fs));
1177 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1179 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1180 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1181 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1182 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1183 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1184 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1185 if(pOS2->version == 0) {
1188 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1191 fs.fsCsb[0] |= 1L << 31;
1194 #ifdef HAVE_FREETYPE_FTWINFNT_H
1195 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1197 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1198 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1199 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1200 memcpy(&fs, &csi.fs, sizeof(csi.fs));
1201 internal_leading = winfnt_header.internal_leading;
1205 face_elem_ptr = list_head(&family->faces);
1206 while(face_elem_ptr) {
1207 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1208 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1209 if(!strcmpW(face->StyleName, StyleW) &&
1210 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1211 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1212 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1213 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1216 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1217 HeapFree(GetProcessHeap(), 0, StyleW);
1218 pFT_Done_Face(ft_face);
1221 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1222 TRACE("Original font is newer so skipping this one\n");
1223 HeapFree(GetProcessHeap(), 0, StyleW);
1224 pFT_Done_Face(ft_face);
1227 TRACE("Replacing original with this one\n");
1228 list_remove(&face->entry);
1229 HeapFree(GetProcessHeap(), 0, face->file);
1230 HeapFree(GetProcessHeap(), 0, face->StyleName);
1231 HeapFree(GetProcessHeap(), 0, face);
1236 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1237 list_add_tail(&family->faces, &face->entry);
1238 face->StyleName = StyleW;
1241 face->file = strdupA(file);
1242 face->font_data_ptr = NULL;
1243 face->font_data_size = 0;
1248 face->font_data_ptr = font_data_ptr;
1249 face->font_data_size = font_data_size;
1251 face->face_index = face_index;
1252 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
1253 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
1254 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1255 face->family = family;
1256 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1257 memcpy(&face->fs, &fs, sizeof(face->fs));
1258 memset(&face->fs_links, 0, sizeof(face->fs_links));
1260 if(FT_IS_SCALABLE(ft_face)) {
1261 memset(&face->size, 0, sizeof(face->size));
1262 face->scalable = TRUE;
1264 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1265 size->height, size->width, size->size >> 6,
1266 size->x_ppem >> 6, size->y_ppem >> 6);
1267 face->size.height = size->height;
1268 face->size.width = size->width;
1269 face->size.size = size->size;
1270 face->size.x_ppem = size->x_ppem;
1271 face->size.y_ppem = size->y_ppem;
1272 face->size.internal_leading = internal_leading;
1273 face->scalable = FALSE;
1276 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1278 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1280 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1281 face->ntmFlags = NTM_PS_OPENTYPE;
1286 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1287 face->fs.fsCsb[0], face->fs.fsCsb[1],
1288 face->fs.fsUsb[0], face->fs.fsUsb[1],
1289 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1292 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1293 for(i = 0; i < ft_face->num_charmaps; i++) {
1294 switch(ft_face->charmaps[i]->encoding) {
1295 case FT_ENCODING_UNICODE:
1296 case FT_ENCODING_APPLE_ROMAN:
1297 face->fs.fsCsb[0] |= 1;
1299 case FT_ENCODING_MS_SYMBOL:
1300 face->fs.fsCsb[0] |= 1L << 31;
1308 if(face->fs.fsCsb[0] & ~(1L << 31))
1309 have_installed_roman_font = TRUE;
1310 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1312 num_faces = ft_face->num_faces;
1313 pFT_Done_Face(ft_face);
1314 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1315 debugstr_w(StyleW));
1316 } while(num_faces > ++face_index);
1320 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1322 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1325 static void DumpFontList(void)
1329 struct list *family_elem_ptr, *face_elem_ptr;
1331 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1332 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1333 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1334 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1335 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1336 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1338 TRACE(" %d", face->size.height);
1345 /***********************************************************
1346 * The replacement list is a way to map an entire font
1347 * family onto another family. For example adding
1349 * [HKCU\Software\Wine\Fonts\Replacements]
1350 * "Wingdings"="Winedings"
1352 * would enumerate the Winedings font both as Winedings and
1353 * Wingdings. However if a real Wingdings font is present the
1354 * replacement does not take place.
1357 static void LoadReplaceList(void)
1360 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1365 struct list *family_elem_ptr, *face_elem_ptr;
1368 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1369 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1371 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1372 &valuelen, &datalen, NULL, NULL);
1374 valuelen++; /* returned value doesn't include room for '\0' */
1375 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1376 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1380 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1381 &dlen) == ERROR_SUCCESS) {
1382 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1383 /* "NewName"="Oldname" */
1384 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1386 /* Find the old family and hence all of the font files
1388 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1389 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1390 if(!strcmpiW(family->FamilyName, data)) {
1391 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1392 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1393 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1394 debugstr_w(face->StyleName), familyA);
1395 /* Now add a new entry with the new family name */
1396 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1401 /* reset dlen and vlen */
1405 HeapFree(GetProcessHeap(), 0, data);
1406 HeapFree(GetProcessHeap(), 0, value);
1411 /*************************************************************
1414 static BOOL init_system_links(void)
1416 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1417 'W','i','n','d','o','w','s',' ','N','T','\\',
1418 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1419 'S','y','s','t','e','m','L','i','n','k',0};
1422 DWORD type, max_val, max_data, val_len, data_len, index;
1423 WCHAR *value, *data;
1424 WCHAR *entry, *next;
1425 SYSTEM_LINKS *font_link, *system_font_link;
1426 CHILD_FONT *child_font;
1427 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1428 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1429 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1435 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1437 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1438 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1439 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1440 val_len = max_val + 1;
1441 data_len = max_data;
1443 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1445 TRACE("%s:\n", debugstr_w(value));
1447 memset(&fs, 0, sizeof(fs));
1448 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1449 psub = get_font_subst(&font_subst_list, value, -1);
1450 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1451 list_init(&font_link->links);
1452 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1455 CHILD_FONT *child_font;
1457 TRACE("\t%s\n", debugstr_w(entry));
1459 next = entry + strlenW(entry) + 1;
1461 face_name = strchrW(entry, ',');
1465 while(isspaceW(*face_name))
1468 psub = get_font_subst(&font_subst_list, face_name, -1);
1470 face_name = psub->to.name;
1472 face = find_face_from_filename(entry, face_name);
1475 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1479 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1480 child_font->face = face;
1481 child_font->font = NULL;
1482 fs.fsCsb[0] |= face->fs.fsCsb[0];
1483 fs.fsCsb[1] |= face->fs.fsCsb[1];
1484 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1485 list_add_tail(&font_link->links, &child_font->entry);
1487 family = find_family_from_name(font_link->font_name);
1490 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1492 memcpy(&face->fs_links, &fs, sizeof(fs));
1495 list_add_tail(&system_links, &font_link->entry);
1496 val_len = max_val + 1;
1497 data_len = max_data;
1500 HeapFree(GetProcessHeap(), 0, value);
1501 HeapFree(GetProcessHeap(), 0, data);
1505 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1508 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1509 system_font_link->font_name = strdupW(System);
1510 list_init(&system_font_link->links);
1512 face = find_face_from_filename(tahoma_ttf, Tahoma);
1515 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1516 child_font->face = face;
1517 child_font->font = NULL;
1518 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1519 list_add_tail(&system_font_link->links, &child_font->entry);
1521 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1523 if(!strcmpiW(font_link->font_name, Tahoma))
1525 CHILD_FONT *font_link_entry;
1526 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1528 CHILD_FONT *new_child;
1529 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1530 new_child->face = font_link_entry->face;
1531 new_child->font = NULL;
1532 list_add_tail(&system_font_link->links, &new_child->entry);
1537 list_add_tail(&system_links, &system_font_link->entry);
1541 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1544 struct dirent *dent;
1545 char path[MAX_PATH];
1547 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1549 dir = opendir(dirname);
1551 WARN("Can't open directory %s\n", debugstr_a(dirname));
1554 while((dent = readdir(dir)) != NULL) {
1555 struct stat statbuf;
1557 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1560 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1562 sprintf(path, "%s/%s", dirname, dent->d_name);
1564 if(stat(path, &statbuf) == -1)
1566 WARN("Can't stat %s\n", debugstr_a(path));
1569 if(S_ISDIR(statbuf.st_mode))
1570 ReadFontDir(path, external_fonts);
1572 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1578 static void load_fontconfig_fonts(void)
1580 #ifdef SONAME_LIBFONTCONFIG
1581 void *fc_handle = NULL;
1590 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1592 TRACE("Wine cannot find the fontconfig library (%s).\n",
1593 SONAME_LIBFONTCONFIG);
1596 #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;}
1597 LOAD_FUNCPTR(FcConfigGetCurrent);
1598 LOAD_FUNCPTR(FcFontList);
1599 LOAD_FUNCPTR(FcFontSetDestroy);
1600 LOAD_FUNCPTR(FcInit);
1601 LOAD_FUNCPTR(FcObjectSetAdd);
1602 LOAD_FUNCPTR(FcObjectSetCreate);
1603 LOAD_FUNCPTR(FcObjectSetDestroy);
1604 LOAD_FUNCPTR(FcPatternCreate);
1605 LOAD_FUNCPTR(FcPatternDestroy);
1606 LOAD_FUNCPTR(FcPatternGetBool);
1607 LOAD_FUNCPTR(FcPatternGetString);
1610 if(!pFcInit()) return;
1612 config = pFcConfigGetCurrent();
1613 pat = pFcPatternCreate();
1614 os = pFcObjectSetCreate();
1615 pFcObjectSetAdd(os, FC_FILE);
1616 pFcObjectSetAdd(os, FC_SCALABLE);
1617 fontset = pFcFontList(config, pat, os);
1618 if(!fontset) return;
1619 for(i = 0; i < fontset->nfont; i++) {
1622 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1624 TRACE("fontconfig: %s\n", file);
1626 /* We're just interested in OT/TT fonts for now, so this hack just
1627 picks up the scalable fonts without extensions .pf[ab] to save time
1628 loading every other font */
1630 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1632 TRACE("not scalable\n");
1636 len = strlen( file );
1637 if(len < 4) continue;
1638 ext = &file[ len - 3 ];
1639 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1640 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1642 pFcFontSetDestroy(fontset);
1643 pFcObjectSetDestroy(os);
1644 pFcPatternDestroy(pat);
1650 static BOOL load_font_from_data_dir(LPCWSTR file)
1653 const char *data_dir = wine_get_data_dir();
1655 if (!data_dir) data_dir = wine_get_build_dir();
1662 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1664 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1666 strcpy(unix_name, data_dir);
1667 strcat(unix_name, "/fonts/");
1669 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1671 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1672 HeapFree(GetProcessHeap(), 0, unix_name);
1677 static void load_system_fonts(void)
1680 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1681 const WCHAR * const *value;
1683 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1686 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1687 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1688 strcatW(windowsdir, fontsW);
1689 for(value = SystemFontValues; *value; value++) {
1690 dlen = sizeof(data);
1691 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1695 sprintfW(pathW, fmtW, windowsdir, data);
1696 if((unixname = wine_get_unix_file_name(pathW))) {
1697 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1698 HeapFree(GetProcessHeap(), 0, unixname);
1701 load_font_from_data_dir(data);
1708 /*************************************************************
1710 * This adds registry entries for any externally loaded fonts
1711 * (fonts from fontconfig or FontDirs). It also deletes entries
1712 * of no longer existing fonts.
1715 static void update_reg_entries(void)
1717 HKEY winkey = 0, externalkey = 0;
1720 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1723 struct list *family_elem_ptr, *face_elem_ptr;
1725 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1726 static const WCHAR spaceW[] = {' ', '\0'};
1729 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1730 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1731 ERR("Can't create Windows font reg key\n");
1734 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1735 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1736 ERR("Can't create external font reg key\n");
1740 /* Delete all external fonts added last time */
1742 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1743 &valuelen, &datalen, NULL, NULL);
1744 valuelen++; /* returned value doesn't include room for '\0' */
1745 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1746 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1748 dlen = datalen * sizeof(WCHAR);
1751 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1752 &dlen) == ERROR_SUCCESS) {
1754 RegDeleteValueW(winkey, valueW);
1755 /* reset dlen and vlen */
1759 HeapFree(GetProcessHeap(), 0, data);
1760 HeapFree(GetProcessHeap(), 0, valueW);
1762 /* Delete the old external fonts key */
1763 RegCloseKey(externalkey);
1765 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1767 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1768 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1769 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1770 ERR("Can't create external font reg key\n");
1774 /* enumerate the fonts and add external ones to the two keys */
1776 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1777 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1778 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1779 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1780 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1781 if(!face->external) continue;
1783 if(strcmpiW(face->StyleName, RegularW))
1784 len = len_fam + strlenW(face->StyleName) + 1;
1785 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1786 strcpyW(valueW, family->FamilyName);
1787 if(len != len_fam) {
1788 strcatW(valueW, spaceW);
1789 strcatW(valueW, face->StyleName);
1791 strcatW(valueW, TrueType);
1792 if((path = strrchr(face->file, '/')) == NULL)
1796 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1798 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1799 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1800 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1801 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1803 HeapFree(GetProcessHeap(), 0, file);
1804 HeapFree(GetProcessHeap(), 0, valueW);
1809 RegCloseKey(externalkey);
1811 RegCloseKey(winkey);
1816 /*************************************************************
1817 * WineEngAddFontResourceEx
1820 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1822 if (ft_handle) /* do it only if we have freetype up and running */
1827 FIXME("Ignoring flags %x\n", flags);
1829 if((unixname = wine_get_unix_file_name(file)))
1831 INT ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1832 HeapFree(GetProcessHeap(), 0, unixname);
1839 /*************************************************************
1840 * WineEngAddFontMemResourceEx
1843 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
1845 if (ft_handle) /* do it only if we have freetype up and running */
1847 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
1849 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
1850 memcpy(pFontCopy, pbFont, cbFont);
1852 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
1856 TRACE("AddFontToList failed\n");
1857 HeapFree(GetProcessHeap(), 0, pFontCopy);
1860 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
1861 * For now return something unique but quite random
1863 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
1864 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
1871 /*************************************************************
1872 * WineEngRemoveFontResourceEx
1875 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1881 static const struct nls_update_font_list
1883 UINT ansi_cp, oem_cp;
1884 const char *oem, *fixed, *system;
1885 const char *courier, *serif, *small, *sserif;
1886 /* these are for font substitute */
1887 const char *shelldlg, *tmsrmn;
1888 } nls_update_font_list[] =
1890 /* Latin 1 (United States) */
1891 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1892 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1893 "Tahoma","Times New Roman",
1895 /* Latin 1 (Multilingual) */
1896 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1897 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1898 "Tahoma","Times New Roman", /* FIXME unverified */
1900 /* Eastern Europe */
1901 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1902 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1903 "Tahoma","Times New Roman", /* FIXME unverified */
1906 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1907 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1908 "Tahoma","Times New Roman", /* FIXME unverified */
1911 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1912 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1913 "Tahoma","Times New Roman", /* FIXME unverified */
1916 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1917 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1918 "Tahoma","Times New Roman", /* FIXME unverified */
1921 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1922 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1923 "Tahoma","Times New Roman", /* FIXME unverified */
1926 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1927 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1928 "Tahoma","Times New Roman", /* FIXME unverified */
1931 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1932 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1933 "Tahoma","Times New Roman", /* FIXME unverified */
1936 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1937 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1938 "Tahoma","Times New Roman", /* FIXME unverified */
1941 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1942 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1943 "Tahoma","Times New Roman", /* FIXME unverified */
1946 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1947 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1948 "MS UI Gothic","MS Serif",
1950 /* Chinese Simplified */
1951 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1952 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1953 "Tahoma", "Times New Roman", /* FIXME unverified */
1956 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1957 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1960 /* Chinese Traditional */
1961 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1962 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1963 "Tahoma", "Times New Roman", /* FIXME unverified */
1967 static inline HKEY create_fonts_NT_registry_key(void)
1971 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1972 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1976 static inline HKEY create_fonts_9x_registry_key(void)
1980 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1981 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1985 static inline HKEY create_config_fonts_registry_key(void)
1989 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1990 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1994 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1996 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1997 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1998 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1999 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2002 static void update_font_info(void)
2004 char buf[40], cpbuf[40];
2007 UINT i, ansi_cp = 0, oem_cp = 0;
2009 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2012 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2013 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2014 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2015 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2016 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2019 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2021 if (!strcmp( buf, cpbuf )) /* already set correctly */
2026 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2028 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2030 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2033 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2035 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2036 nls_update_font_list[i].oem_cp == oem_cp)
2040 hkey = create_config_fonts_registry_key();
2041 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2042 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2043 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2046 hkey = create_fonts_NT_registry_key();
2047 add_font_list(hkey, &nls_update_font_list[i]);
2050 hkey = create_fonts_9x_registry_key();
2051 add_font_list(hkey, &nls_update_font_list[i]);
2054 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2056 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2057 strlen(nls_update_font_list[i].shelldlg)+1);
2058 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2059 strlen(nls_update_font_list[i].tmsrmn)+1);
2065 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2068 /*************************************************************
2071 * Initialize FreeType library and create a list of available faces
2073 BOOL WineEngInit(void)
2075 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2076 static const WCHAR pathW[] = {'P','a','t','h',0};
2078 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2080 WCHAR windowsdir[MAX_PATH];
2083 const char *data_dir;
2087 /* update locale dependent font info in registry */
2090 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2093 "Wine cannot find the FreeType font library. To enable Wine to\n"
2094 "use TrueType fonts please install a version of FreeType greater than\n"
2095 "or equal to 2.0.5.\n"
2096 "http://www.freetype.org\n");
2100 #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;}
2102 LOAD_FUNCPTR(FT_Vector_Unit)
2103 LOAD_FUNCPTR(FT_Done_Face)
2104 LOAD_FUNCPTR(FT_Get_Char_Index)
2105 LOAD_FUNCPTR(FT_Get_Module)
2106 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2107 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2108 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2109 LOAD_FUNCPTR(FT_Init_FreeType)
2110 LOAD_FUNCPTR(FT_Load_Glyph)
2111 LOAD_FUNCPTR(FT_Matrix_Multiply)
2112 LOAD_FUNCPTR(FT_MulFix)
2113 LOAD_FUNCPTR(FT_New_Face)
2114 LOAD_FUNCPTR(FT_New_Memory_Face)
2115 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2116 LOAD_FUNCPTR(FT_Outline_Transform)
2117 LOAD_FUNCPTR(FT_Outline_Translate)
2118 LOAD_FUNCPTR(FT_Select_Charmap)
2119 LOAD_FUNCPTR(FT_Set_Charmap)
2120 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2121 LOAD_FUNCPTR(FT_Vector_Transform)
2124 /* Don't warn if this one is missing */
2125 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2126 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2127 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2128 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2129 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2130 #ifdef HAVE_FREETYPE_FTWINFNT_H
2131 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2133 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2134 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2135 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2136 <= 2.0.3 has FT_Sqrt64 */
2140 if(pFT_Init_FreeType(&library) != 0) {
2141 ERR("Can't init FreeType library\n");
2142 wine_dlclose(ft_handle, NULL, 0);
2146 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
2147 if (pFT_Library_Version)
2149 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2151 if (FT_Version.major<=0)
2157 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2158 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2159 ((FT_Version.minor << 8) & 0x00ff00) |
2160 ((FT_Version.patch ) & 0x0000ff);
2162 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2163 ERR("Failed to create font mutex\n");
2166 WaitForSingleObject(font_mutex, INFINITE);
2168 /* load the system bitmap fonts */
2169 load_system_fonts();
2171 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2172 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2173 strcatW(windowsdir, fontsW);
2174 if((unixname = wine_get_unix_file_name(windowsdir)))
2176 ReadFontDir(unixname, FALSE);
2177 HeapFree(GetProcessHeap(), 0, unixname);
2180 /* load the system truetype fonts */
2181 data_dir = wine_get_data_dir();
2182 if (!data_dir) data_dir = wine_get_build_dir();
2183 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2184 strcpy(unixname, data_dir);
2185 strcat(unixname, "/fonts/");
2186 ReadFontDir(unixname, TRUE);
2187 HeapFree(GetProcessHeap(), 0, unixname);
2190 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2191 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2192 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2194 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2195 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2196 &hkey) == ERROR_SUCCESS) {
2198 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2199 &valuelen, &datalen, NULL, NULL);
2201 valuelen++; /* returned value doesn't include room for '\0' */
2202 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2203 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2206 dlen = datalen * sizeof(WCHAR);
2208 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2209 &dlen) == ERROR_SUCCESS) {
2210 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2212 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2214 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2215 HeapFree(GetProcessHeap(), 0, unixname);
2218 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2220 WCHAR pathW[MAX_PATH];
2221 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2224 sprintfW(pathW, fmtW, windowsdir, data);
2225 if((unixname = wine_get_unix_file_name(pathW)))
2227 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2228 HeapFree(GetProcessHeap(), 0, unixname);
2231 load_font_from_data_dir(data);
2233 /* reset dlen and vlen */
2238 HeapFree(GetProcessHeap(), 0, data);
2239 HeapFree(GetProcessHeap(), 0, valueW);
2243 load_fontconfig_fonts();
2245 /* then look in any directories that we've specified in the config file */
2246 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2247 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2253 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2255 len += sizeof(WCHAR);
2256 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2257 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2259 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2260 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2261 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2262 TRACE( "got font path %s\n", debugstr_a(valueA) );
2266 LPSTR next = strchr( ptr, ':' );
2267 if (next) *next++ = 0;
2268 ReadFontDir( ptr, TRUE );
2271 HeapFree( GetProcessHeap(), 0, valueA );
2273 HeapFree( GetProcessHeap(), 0, valueW );
2282 update_reg_entries();
2284 init_system_links();
2286 ReleaseMutex(font_mutex);
2290 "Wine cannot find certain functions that it needs inside the FreeType\n"
2291 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2292 "FreeType to at least version 2.0.5.\n"
2293 "http://www.freetype.org\n");
2294 wine_dlclose(ft_handle, NULL, 0);
2300 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2303 TT_HoriHeader *pHori;
2307 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2308 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2310 if(height == 0) height = 16;
2312 /* Calc. height of EM square:
2314 * For +ve lfHeight we have
2315 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2316 * Re-arranging gives:
2317 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2319 * For -ve lfHeight we have
2321 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2322 * with il = winAscent + winDescent - units_per_em]
2327 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2328 ppem = ft_face->units_per_EM * height /
2329 (pHori->Ascender - pHori->Descender);
2331 ppem = ft_face->units_per_EM * height /
2332 (pOS2->usWinAscent + pOS2->usWinDescent);
2340 static struct font_mapping *map_font_file( const char *name )
2342 struct font_mapping *mapping;
2346 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2347 if (fstat( fd, &st ) == -1) goto error;
2349 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2351 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2353 mapping->refcount++;
2358 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2361 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2364 if (mapping->data == MAP_FAILED)
2366 HeapFree( GetProcessHeap(), 0, mapping );
2369 mapping->refcount = 1;
2370 mapping->dev = st.st_dev;
2371 mapping->ino = st.st_ino;
2372 mapping->size = st.st_size;
2373 list_add_tail( &mappings_list, &mapping->entry );
2381 static void unmap_font_file( struct font_mapping *mapping )
2383 if (!--mapping->refcount)
2385 list_remove( &mapping->entry );
2386 munmap( mapping->data, mapping->size );
2387 HeapFree( GetProcessHeap(), 0, mapping );
2391 static LONG load_VDMX(GdiFont*, LONG);
2393 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2400 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2404 if (!(font->mapping = map_font_file( face->file )))
2406 WARN("failed to map %s\n", debugstr_a(face->file));
2409 data_ptr = font->mapping->data;
2410 data_size = font->mapping->size;
2414 data_ptr = face->font_data_ptr;
2415 data_size = face->font_data_size;
2418 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2420 ERR("FT_New_Face rets %d\n", err);
2424 /* set it here, as load_VDMX needs it */
2425 font->ft_face = ft_face;
2427 if(FT_IS_SCALABLE(ft_face)) {
2428 /* load the VDMX table if we have one */
2429 font->ppem = load_VDMX(font, height);
2431 font->ppem = calc_ppem_for_height(ft_face, height);
2433 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2434 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2436 font->ppem = height;
2437 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2438 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2444 static int get_nearest_charset(Face *face, int *cp)
2446 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2447 a single face with the requested charset. The idea is to check if
2448 the selected font supports the current ANSI codepage, if it does
2449 return the corresponding charset, else return the first charset */
2452 int acp = GetACP(), i;
2456 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2457 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2458 return csi.ciCharset;
2460 for(i = 0; i < 32; i++) {
2462 if(face->fs.fsCsb[0] & fs0) {
2463 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2465 return csi.ciCharset;
2468 FIXME("TCI failing on %x\n", fs0);
2472 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2473 face->fs.fsCsb[0], face->file);
2475 return DEFAULT_CHARSET;
2478 static GdiFont *alloc_font(void)
2480 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2482 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2483 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2485 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2486 ret->total_kern_pairs = (DWORD)-1;
2487 ret->kern_pairs = NULL;
2488 list_init(&ret->hfontlist);
2489 list_init(&ret->child_fonts);
2493 static void free_font(GdiFont *font)
2495 struct list *cursor, *cursor2;
2498 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2500 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2501 struct list *first_hfont;
2502 HFONTLIST *hfontlist;
2503 list_remove(cursor);
2506 first_hfont = list_head(&child->font->hfontlist);
2507 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2508 DeleteObject(hfontlist->hfont);
2509 HeapFree(GetProcessHeap(), 0, hfontlist);
2510 free_font(child->font);
2512 HeapFree(GetProcessHeap(), 0, child);
2515 if (font->ft_face) pFT_Done_Face(font->ft_face);
2516 if (font->mapping) unmap_font_file( font->mapping );
2517 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2518 HeapFree(GetProcessHeap(), 0, font->potm);
2519 HeapFree(GetProcessHeap(), 0, font->name);
2520 for (i = 0; i < font->gmsize; i++)
2521 HeapFree(GetProcessHeap(),0,font->gm[i]);
2522 HeapFree(GetProcessHeap(), 0, font->gm);
2523 HeapFree(GetProcessHeap(), 0, font);
2527 /*************************************************************
2530 * load the vdmx entry for the specified height
2533 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2534 ( ( (FT_ULong)_x4 << 24 ) | \
2535 ( (FT_ULong)_x3 << 16 ) | \
2536 ( (FT_ULong)_x2 << 8 ) | \
2539 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2554 static LONG load_VDMX(GdiFont *font, LONG height)
2558 BYTE devXRatio, devYRatio;
2559 USHORT numRecs, numRatios;
2560 DWORD result, offset = -1;
2564 /* For documentation on VDMX records, see
2565 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2568 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2570 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2573 /* FIXME: need the real device aspect ratio */
2577 numRecs = GET_BE_WORD(hdr[1]);
2578 numRatios = GET_BE_WORD(hdr[2]);
2580 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2581 for(i = 0; i < numRatios; i++) {
2584 offset = (3 * 2) + (i * sizeof(Ratios));
2585 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2588 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2590 if((ratio.xRatio == 0 &&
2591 ratio.yStartRatio == 0 &&
2592 ratio.yEndRatio == 0) ||
2593 (devXRatio == ratio.xRatio &&
2594 devYRatio >= ratio.yStartRatio &&
2595 devYRatio <= ratio.yEndRatio))
2597 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2598 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2599 offset = GET_BE_WORD(tmp);
2605 FIXME("No suitable ratio found\n");
2609 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2611 BYTE startsz, endsz;
2614 recs = GET_BE_WORD(group.recs);
2615 startsz = group.startsz;
2616 endsz = group.endsz;
2618 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2620 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2621 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2622 if(result == GDI_ERROR) {
2623 FIXME("Failed to retrieve vTable\n");
2628 for(i = 0; i < recs; i++) {
2629 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2630 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2631 ppem = GET_BE_WORD(vTable[i * 3]);
2633 if(yMax + -yMin == height) {
2636 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2639 if(yMax + -yMin > height) {
2642 goto end; /* failed */
2644 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2645 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2646 ppem = GET_BE_WORD(vTable[i * 3]);
2647 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2653 TRACE("ppem not found for height %d\n", height);
2657 if(ppem < startsz || ppem > endsz)
2660 for(i = 0; i < recs; i++) {
2662 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2664 if(yPelHeight > ppem)
2667 if(yPelHeight == ppem) {
2668 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2669 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2670 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2676 HeapFree(GetProcessHeap(), 0, vTable);
2682 static BOOL fontcmp(GdiFont *font, FONT_DESC *fd)
2684 if(font->font_desc.hash != fd->hash) return TRUE;
2685 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2686 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2687 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2688 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2691 static void calc_hash(FONT_DESC *pfd)
2693 DWORD hash = 0, *ptr, two_chars;
2697 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2699 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2701 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2703 pwc = (WCHAR *)&two_chars;
2705 *pwc = toupperW(*pwc);
2707 *pwc = toupperW(*pwc);
2711 hash ^= !pfd->can_use_bitmap;
2716 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2721 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2723 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2724 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2725 fd.can_use_bitmap = can_use_bitmap;
2728 /* try the in-use list */
2729 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2730 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2731 if(!fontcmp(ret, &fd)) {
2732 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2733 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2734 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2735 if(hflist->hfont == hfont)
2738 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2739 hflist->hfont = hfont;
2740 list_add_head(&ret->hfontlist, &hflist->entry);
2745 /* then the unused list */
2746 font_elem_ptr = list_head(&unused_gdi_font_list);
2747 while(font_elem_ptr) {
2748 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2749 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2750 if(!fontcmp(ret, &fd)) {
2751 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2752 assert(list_empty(&ret->hfontlist));
2753 TRACE("Found %p in unused list\n", ret);
2754 list_remove(&ret->entry);
2755 list_add_head(&gdi_font_list, &ret->entry);
2756 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2757 hflist->hfont = hfont;
2758 list_add_head(&ret->hfontlist, &hflist->entry);
2766 /*************************************************************
2767 * create_child_font_list
2769 static BOOL create_child_font_list(GdiFont *font)
2772 SYSTEM_LINKS *font_link;
2773 CHILD_FONT *font_link_entry, *new_child;
2775 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2777 if(!strcmpW(font_link->font_name, font->name))
2779 TRACE("found entry in system list\n");
2780 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2782 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2783 new_child->face = font_link_entry->face;
2784 new_child->font = NULL;
2785 list_add_tail(&font->child_fonts, &new_child->entry);
2786 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
2796 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
2798 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
2800 if (pFT_Set_Charmap)
2803 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
2805 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
2807 for (i = 0; i < ft_face->num_charmaps; i++)
2809 if (ft_face->charmaps[i]->encoding == encoding)
2811 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2812 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
2814 switch (ft_face->charmaps[i]->platform_id)
2817 cmap_def = ft_face->charmaps[i];
2819 case 0: /* Apple Unicode */
2820 cmap0 = ft_face->charmaps[i];
2822 case 1: /* Macintosh */
2823 cmap1 = ft_face->charmaps[i];
2826 cmap2 = ft_face->charmaps[i];
2828 case 3: /* Microsoft */
2829 cmap3 = ft_face->charmaps[i];
2834 if (cmap3) /* prefer Microsoft cmap table */
2835 ft_err = pFT_Set_Charmap(ft_face, cmap3);
2837 ft_err = pFT_Set_Charmap(ft_face, cmap1);
2839 ft_err = pFT_Set_Charmap(ft_face, cmap2);
2841 ft_err = pFT_Set_Charmap(ft_face, cmap0);
2843 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
2845 return ft_err == FT_Err_Ok;
2848 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
2851 /*************************************************************
2852 * WineEngCreateFontInstance
2855 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
2858 Face *face, *best, *best_bitmap;
2859 Family *family, *last_resort_family;
2860 struct list *family_elem_ptr, *face_elem_ptr;
2861 INT height, width = 0;
2862 unsigned int score = 0, new_score;
2863 signed int diff = 0, newdiff;
2864 BOOL bd, it, can_use_bitmap;
2869 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2871 struct list *first_hfont = list_head(&ret->hfontlist);
2872 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2873 if(hflist->hfont == hfont)
2877 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2878 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2880 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2881 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2882 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2885 /* check the cache first */
2886 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2887 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2891 TRACE("not in cache\n");
2892 if(list_empty(&font_list)) /* No fonts installed */
2894 TRACE("No fonts installed\n");
2897 if(!have_installed_roman_font)
2899 TRACE("No roman font installed\n");
2905 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2906 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2907 ret->font_desc.can_use_bitmap = can_use_bitmap;
2908 calc_hash(&ret->font_desc);
2909 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2910 hflist->hfont = hfont;
2911 list_add_head(&ret->hfontlist, &hflist->entry);
2914 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2915 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2916 original value lfCharSet. Note this is a special case for
2917 Symbol and doesn't happen at least for "Wingdings*" */
2919 if(!strcmpiW(lf.lfFaceName, SymbolW))
2920 lf.lfCharSet = SYMBOL_CHARSET;
2922 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2923 switch(lf.lfCharSet) {
2924 case DEFAULT_CHARSET:
2925 csi.fs.fsCsb[0] = 0;
2928 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2929 csi.fs.fsCsb[0] = 0;
2935 if(lf.lfFaceName[0] != '\0') {
2937 SYSTEM_LINKS *font_link;
2938 CHILD_FONT *font_link_entry;
2940 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2943 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2944 debugstr_w(psub->to.name));
2945 strcpyW(lf.lfFaceName, psub->to.name);
2948 /* We want a match on name and charset or just name if
2949 charset was DEFAULT_CHARSET. If the latter then
2950 we fixup the returned charset later in get_nearest_charset
2951 where we'll either use the charset of the current ansi codepage
2952 or if that's unavailable the first charset that the font supports.
2954 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2955 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2956 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
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])) || !csi.fs.fsCsb[0])
2960 if(face->scalable || can_use_bitmap)
2967 * Try check the SystemLink list first for a replacement font.
2968 * We may find good replacements there.
2970 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2972 if(!strcmpiW(font_link->font_name, lf.lfFaceName))
2974 TRACE("found entry in system list\n");
2975 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2977 face = font_link_entry->face;
2978 family = face->family;
2979 if(csi.fs.fsCsb[0] &
2980 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
2982 if(face->scalable || can_use_bitmap)
2990 /* If requested charset was DEFAULT_CHARSET then try using charset
2991 corresponding to the current ansi codepage */
2992 if(!csi.fs.fsCsb[0]) {
2994 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
2995 FIXME("TCI failed on codepage %d\n", acp);
2996 csi.fs.fsCsb[0] = 0;
2998 lf.lfCharSet = csi.ciCharset;
3001 /* Face families are in the top 4 bits of lfPitchAndFamily,
3002 so mask with 0xF0 before testing */
3004 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3005 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3006 strcpyW(lf.lfFaceName, defFixed);
3007 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3008 strcpyW(lf.lfFaceName, defSerif);
3009 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3010 strcpyW(lf.lfFaceName, defSans);
3012 strcpyW(lf.lfFaceName, defSans);
3013 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3014 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3015 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3016 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3017 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3018 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3019 if(face->scalable || can_use_bitmap)
3025 last_resort_family = NULL;
3026 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3027 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3028 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3029 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3030 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3033 if(can_use_bitmap && !last_resort_family)
3034 last_resort_family = family;
3039 if(last_resort_family) {
3040 family = last_resort_family;
3041 csi.fs.fsCsb[0] = 0;
3045 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3046 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3047 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3048 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3049 if(face->scalable) {
3050 csi.fs.fsCsb[0] = 0;
3051 WARN("just using first face for now\n");
3054 if(can_use_bitmap && !last_resort_family)
3055 last_resort_family = family;
3058 if(!last_resort_family) {
3059 FIXME("can't find a single appropriate font - bailing\n");
3064 WARN("could only find a bitmap font - this will probably look awful!\n");
3065 family = last_resort_family;
3066 csi.fs.fsCsb[0] = 0;
3069 it = lf.lfItalic ? 1 : 0;
3070 bd = lf.lfWeight > 550 ? 1 : 0;
3072 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
3073 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
3075 face = best = best_bitmap = NULL;
3076 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3078 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3080 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
3081 if(!best || new_score <= score)
3083 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3084 face->Italic, face->Bold, it, bd);
3087 if(best->scalable && score == 0) break;
3091 newdiff = height - (signed int)(best->size.height);
3093 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3094 if(!best_bitmap || new_score < score ||
3095 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3097 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3100 if(score == 0 && diff == 0) break;
3107 face = best->scalable ? best : best_bitmap;
3108 ret->fake_italic = (it && !face->Italic);
3109 ret->fake_bold = (bd && !face->Bold);
3111 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
3113 if(csi.fs.fsCsb[0]) {
3114 ret->charset = lf.lfCharSet;
3115 ret->codepage = csi.ciACP;
3118 ret->charset = get_nearest_charset(face, &ret->codepage);
3120 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3121 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3123 if(!face->scalable) {
3124 width = face->size.x_ppem >> 6;
3125 height = face->size.y_ppem >> 6;
3127 ret->ft_face = OpenFontFace(ret, face, width, height);
3135 ret->ntmFlags = face->ntmFlags;
3137 if (ret->charset == SYMBOL_CHARSET &&
3138 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3141 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3145 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3148 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3149 ret->name = strdupW(family->FamilyName);
3150 ret->underline = lf.lfUnderline ? 0xff : 0;
3151 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3152 create_child_font_list(ret);
3154 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3156 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? abs(lf.lfWidth) : 0;
3157 list_add_head(&gdi_font_list, &ret->entry);
3161 static void dump_gdi_font_list(void)
3164 struct list *elem_ptr;
3166 TRACE("---------- gdiFont Cache ----------\n");
3167 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3168 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3169 TRACE("gdiFont=%p %s %d\n",
3170 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3173 TRACE("---------- Unused gdiFont Cache ----------\n");
3174 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3175 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3176 TRACE("gdiFont=%p %s %d\n",
3177 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3181 /*************************************************************
3182 * WineEngDestroyFontInstance
3184 * free the gdiFont associated with this handle
3187 BOOL WineEngDestroyFontInstance(HFONT handle)
3192 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3195 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3197 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3198 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3199 if(hflist->hfont == handle)
3201 TRACE("removing child font %p from child list\n", gdiFont);
3202 list_remove(&gdiFont->entry);
3207 TRACE("destroying hfont=%p\n", handle);
3209 dump_gdi_font_list();
3211 font_elem_ptr = list_head(&gdi_font_list);
3212 while(font_elem_ptr) {
3213 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3214 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3216 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3217 while(hfontlist_elem_ptr) {
3218 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3219 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3220 if(hflist->hfont == handle) {
3221 list_remove(&hflist->entry);
3222 HeapFree(GetProcessHeap(), 0, hflist);
3226 if(list_empty(&gdiFont->hfontlist)) {
3227 TRACE("Moving to Unused list\n");
3228 list_remove(&gdiFont->entry);
3229 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3234 font_elem_ptr = list_head(&unused_gdi_font_list);
3235 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3236 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3237 while(font_elem_ptr) {
3238 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3239 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3240 TRACE("freeing %p\n", gdiFont);
3241 list_remove(&gdiFont->entry);
3247 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3248 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3250 OUTLINETEXTMETRICW *potm = NULL;
3252 TEXTMETRICW tm, *ptm;
3253 GdiFont *font = alloc_font();
3256 if(face->scalable) {
3260 height = face->size.y_ppem >> 6;
3261 width = face->size.x_ppem >> 6;
3264 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3270 font->name = strdupW(face->family->FamilyName);
3271 font->ntmFlags = face->ntmFlags;
3273 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
3275 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
3277 potm = HeapAlloc(GetProcessHeap(), 0, size);
3278 WineEngGetOutlineTextMetrics(font, size, potm);
3279 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
3281 WineEngGetTextMetrics(font, &tm);
3285 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
3286 pntm->ntmTm.tmAscent = ptm->tmAscent;
3287 pntm->ntmTm.tmDescent = ptm->tmDescent;
3288 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
3289 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
3290 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
3291 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
3292 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
3293 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
3294 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
3295 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
3296 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
3297 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
3298 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
3299 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
3300 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
3301 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
3302 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
3303 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
3304 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
3305 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
3306 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3307 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3308 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3311 if (ptm->tmPitchAndFamily & TMPF_TRUETYPE)
3312 *ptype |= TRUETYPE_FONTTYPE;
3313 if (ptm->tmPitchAndFamily & TMPF_DEVICE)
3314 *ptype |= DEVICE_FONTTYPE;
3315 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
3316 *ptype |= RASTER_FONTTYPE;
3318 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
3319 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
3320 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
3321 pntm->ntmTm.ntmFlags |= face->ntmFlags;
3323 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3324 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3325 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
3328 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
3330 lstrcpynW(pelf->elfLogFont.lfFaceName,
3331 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
3333 lstrcpynW(pelf->elfFullName,
3334 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
3336 lstrcpynW(pelf->elfStyle,
3337 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
3340 HeapFree(GetProcessHeap(), 0, potm);
3342 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3344 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3345 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
3346 pelf->elfStyle[0] = '\0';
3349 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3354 /*************************************************************
3358 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3362 struct list *family_elem_ptr, *face_elem_ptr;
3364 NEWTEXTMETRICEXW ntm;
3365 DWORD type, ret = 1;
3371 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3373 if(plf->lfFaceName[0]) {
3375 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3378 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3379 debugstr_w(psub->to.name));
3380 memcpy(&lf, plf, sizeof(lf));
3381 strcpyW(lf.lfFaceName, psub->to.name);
3385 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3386 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3387 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3388 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3389 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3390 GetEnumStructs(face, &elf, &ntm, &type);
3391 for(i = 0; i < 32; i++) {
3392 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3393 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3394 strcpyW(elf.elfScript, OEM_DOSW);
3395 i = 32; /* break out of loop */
3396 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3399 fs.fsCsb[0] = 1L << i;
3401 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3403 csi.ciCharset = DEFAULT_CHARSET;
3404 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3405 if(csi.ciCharset != DEFAULT_CHARSET) {
3406 elf.elfLogFont.lfCharSet =
3407 ntm.ntmTm.tmCharSet = csi.ciCharset;
3409 strcpyW(elf.elfScript, ElfScriptsW[i]);
3411 FIXME("Unknown elfscript for bit %d\n", i);
3414 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3415 debugstr_w(elf.elfLogFont.lfFaceName),
3416 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3417 csi.ciCharset, type, debugstr_w(elf.elfScript),
3418 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3419 ntm.ntmTm.ntmFlags);
3420 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3427 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3428 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3429 face_elem_ptr = list_head(&family->faces);
3430 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3431 GetEnumStructs(face, &elf, &ntm, &type);
3432 for(i = 0; i < 32; i++) {
3433 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3434 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3435 strcpyW(elf.elfScript, OEM_DOSW);
3436 i = 32; /* break out of loop */
3437 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3440 fs.fsCsb[0] = 1L << i;
3442 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3444 csi.ciCharset = DEFAULT_CHARSET;
3445 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3446 if(csi.ciCharset != DEFAULT_CHARSET) {
3447 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3450 strcpyW(elf.elfScript, ElfScriptsW[i]);
3452 FIXME("Unknown elfscript for bit %d\n", i);
3455 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3456 debugstr_w(elf.elfLogFont.lfFaceName),
3457 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3458 csi.ciCharset, type, debugstr_w(elf.elfScript),
3459 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3460 ntm.ntmTm.ntmFlags);
3461 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3470 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3472 pt->x.value = vec->x >> 6;
3473 pt->x.fract = (vec->x & 0x3f) << 10;
3474 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3475 pt->y.value = vec->y >> 6;
3476 pt->y.fract = (vec->y & 0x3f) << 10;
3477 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3481 /***************************************************
3482 * According to the MSDN documentation on WideCharToMultiByte,
3483 * certain codepages cannot set the default_used parameter.
3484 * This returns TRUE if the codepage can set that parameter, false else
3485 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3487 static BOOL codepage_sets_default_used(UINT codepage)
3500 static FT_UInt get_glyph_index(GdiFont *font, UINT glyph)
3502 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
3503 WCHAR wc = (WCHAR)glyph;
3505 BOOL *default_used_pointer;
3508 default_used_pointer = NULL;
3509 default_used = FALSE;
3510 if (codepage_sets_default_used(font->codepage))
3511 default_used_pointer = &default_used;
3512 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
3515 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
3516 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
3520 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
3521 glyph = glyph + 0xf000;
3522 return pFT_Get_Char_Index(font->ft_face, glyph);
3525 /*************************************************************
3526 * WineEngGetGlyphIndices
3528 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3530 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
3531 LPWORD pgi, DWORD flags)
3534 WCHAR default_char = 0;
3537 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
3539 for(i = 0; i < count; i++)
3541 pgi[i] = get_glyph_index(font, lpstr[i]);
3546 WineEngGetTextMetrics(font, &textm);
3547 default_char = textm.tmDefaultChar;
3549 pgi[i] = default_char;
3555 /*************************************************************
3556 * WineEngGetGlyphOutline
3558 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3559 * except that the first parameter is the HWINEENGFONT of the font in
3560 * question rather than an HDC.
3563 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
3564 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3567 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3568 FT_Face ft_face = incoming_font->ft_face;
3569 GdiFont *font = incoming_font;
3570 FT_UInt glyph_index;
3571 DWORD width, height, pitch, needed = 0;
3572 FT_Bitmap ft_bitmap;
3574 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
3576 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3577 float widthRatio = 1.0;
3578 FT_Matrix transMat = identityMat;
3579 BOOL needsTransform = FALSE;
3582 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
3583 buflen, buf, lpmat);
3585 if(format & GGO_GLYPH_INDEX) {
3586 glyph_index = glyph;
3587 format &= ~GGO_GLYPH_INDEX;
3589 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
3590 ft_face = font->ft_face;
3593 if(glyph_index >= font->gmsize * GM_BLOCK_SIZE) {
3594 font->gmsize = (glyph_index / GM_BLOCK_SIZE + 1);
3595 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
3596 font->gmsize * sizeof(GM*));
3598 if(format == GGO_METRICS && font->gm[glyph_index / GM_BLOCK_SIZE] != NULL && FONT_GM(font,glyph_index)->init ) {
3599 *lpgm = FONT_GM(font,glyph_index)->gm;
3600 return 1; /* FIXME */
3604 if (!font->gm[glyph_index / GM_BLOCK_SIZE])
3605 font->gm[glyph_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3607 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || font->aveWidth || lpmat)
3608 load_flags |= FT_LOAD_NO_BITMAP;
3610 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
3613 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
3617 /* Scaling factor */
3618 if (font->aveWidth && font->potm) {
3619 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
3622 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3623 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3625 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3627 bbx = (right - left) >> 6;
3629 /* Scaling transform */
3630 if(font->aveWidth) {
3632 scaleMat.xx = FT_FixedFromFloat(widthRatio);
3635 scaleMat.yy = (1 << 16);
3637 pFT_Matrix_Multiply(&scaleMat, &transMat);
3638 needsTransform = TRUE;
3641 /* Slant transform */
3642 if (font->fake_italic) {
3645 slantMat.xx = (1 << 16);
3646 slantMat.xy = ((1 << 16) >> 2);
3648 slantMat.yy = (1 << 16);
3649 pFT_Matrix_Multiply(&slantMat, &transMat);
3650 needsTransform = TRUE;
3653 /* Rotation transform */
3654 if(font->orientation) {
3655 FT_Matrix rotationMat;
3657 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3658 pFT_Vector_Unit(&vecAngle, angle);
3659 rotationMat.xx = vecAngle.x;
3660 rotationMat.xy = -vecAngle.y;
3661 rotationMat.yx = -rotationMat.xy;
3662 rotationMat.yy = rotationMat.xx;
3664 pFT_Matrix_Multiply(&rotationMat, &transMat);
3665 needsTransform = TRUE;
3668 /* Extra transformation specified by caller */
3671 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3672 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3673 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3674 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3675 pFT_Matrix_Multiply(&extraMat, &transMat);
3676 needsTransform = TRUE;
3679 if(!needsTransform) {
3680 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3681 bottom = (ft_face->glyph->metrics.horiBearingY -
3682 ft_face->glyph->metrics.height) & -64;
3683 lpgm->gmCellIncX = adv;
3684 lpgm->gmCellIncY = 0;
3688 for(xc = 0; xc < 2; xc++) {
3689 for(yc = 0; yc < 2; yc++) {
3690 vec.x = (ft_face->glyph->metrics.horiBearingX +
3691 xc * ft_face->glyph->metrics.width);
3692 vec.y = ft_face->glyph->metrics.horiBearingY -
3693 yc * ft_face->glyph->metrics.height;
3694 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3695 pFT_Vector_Transform(&vec, &transMat);
3696 if(xc == 0 && yc == 0) {
3697 left = right = vec.x;
3698 top = bottom = vec.y;
3700 if(vec.x < left) left = vec.x;
3701 else if(vec.x > right) right = vec.x;
3702 if(vec.y < bottom) bottom = vec.y;
3703 else if(vec.y > top) top = vec.y;
3708 right = (right + 63) & -64;
3709 bottom = bottom & -64;
3710 top = (top + 63) & -64;
3712 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3713 vec.x = ft_face->glyph->metrics.horiAdvance;
3715 pFT_Vector_Transform(&vec, &transMat);
3716 lpgm->gmCellIncX = (vec.x+63) >> 6;
3717 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3719 lpgm->gmBlackBoxX = (right - left) >> 6;
3720 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3721 lpgm->gmptGlyphOrigin.x = left >> 6;
3722 lpgm->gmptGlyphOrigin.y = top >> 6;
3724 if(format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP)
3726 FONT_GM(font,glyph_index)->gm = *lpgm;
3727 FONT_GM(font,glyph_index)->adv = adv;
3728 FONT_GM(font,glyph_index)->lsb = lsb;
3729 FONT_GM(font,glyph_index)->bbx = bbx;
3730 FONT_GM(font,glyph_index)->init = TRUE;
3733 if(format == GGO_METRICS)
3734 return 1; /* FIXME */
3736 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
3737 TRACE("loaded a bitmap\n");
3743 width = lpgm->gmBlackBoxX;
3744 height = lpgm->gmBlackBoxY;
3745 pitch = ((width + 31) >> 5) << 2;
3746 needed = pitch * height;
3748 if(!buf || !buflen) break;
3750 switch(ft_face->glyph->format) {
3751 case ft_glyph_format_bitmap:
3753 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3754 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3755 INT h = ft_face->glyph->bitmap.rows;
3757 memcpy(dst, src, w);
3758 src += ft_face->glyph->bitmap.pitch;
3764 case ft_glyph_format_outline:
3765 ft_bitmap.width = width;
3766 ft_bitmap.rows = height;
3767 ft_bitmap.pitch = pitch;
3768 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3769 ft_bitmap.buffer = buf;
3771 if(needsTransform) {
3772 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3775 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3777 /* Note: FreeType will only set 'black' bits for us. */
3778 memset(buf, 0, needed);
3779 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3783 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3788 case GGO_GRAY2_BITMAP:
3789 case GGO_GRAY4_BITMAP:
3790 case GGO_GRAY8_BITMAP:
3791 case WINE_GGO_GRAY16_BITMAP:
3793 unsigned int mult, row, col;
3796 width = lpgm->gmBlackBoxX;
3797 height = lpgm->gmBlackBoxY;
3798 pitch = (width + 3) / 4 * 4;
3799 needed = pitch * height;
3801 if(!buf || !buflen) break;
3803 switch(ft_face->glyph->format) {
3804 case ft_glyph_format_bitmap:
3806 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3807 INT h = ft_face->glyph->bitmap.rows;
3810 for(x = 0; x < pitch; x++)
3811 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
3812 src += ft_face->glyph->bitmap.pitch;
3817 case ft_glyph_format_outline:
3819 ft_bitmap.width = width;
3820 ft_bitmap.rows = height;
3821 ft_bitmap.pitch = pitch;
3822 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3823 ft_bitmap.buffer = buf;
3826 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3828 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3830 memset(ft_bitmap.buffer, 0, buflen);
3832 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3834 if(format == GGO_GRAY2_BITMAP)
3836 else if(format == GGO_GRAY4_BITMAP)
3838 else if(format == GGO_GRAY8_BITMAP)
3840 else /* format == WINE_GGO_GRAY16_BITMAP */
3846 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3851 for(row = 0; row < height; row++) {
3853 for(col = 0; col < width; col++, ptr++) {
3854 *ptr = (((int)*ptr) * mult + 128) / 256;
3863 int contour, point = 0, first_pt;
3864 FT_Outline *outline = &ft_face->glyph->outline;
3865 TTPOLYGONHEADER *pph;
3867 DWORD pph_start, cpfx, type;
3869 if(buflen == 0) buf = NULL;
3871 if (needsTransform && buf) {
3872 pFT_Outline_Transform(outline, &transMat);
3875 for(contour = 0; contour < outline->n_contours; contour++) {
3877 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3880 pph->dwType = TT_POLYGON_TYPE;
3881 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3883 needed += sizeof(*pph);
3885 while(point <= outline->contours[contour]) {
3886 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3887 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3888 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3892 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3895 } while(point <= outline->contours[contour] &&
3896 (outline->tags[point] & FT_Curve_Tag_On) ==
3897 (outline->tags[point-1] & FT_Curve_Tag_On));
3898 /* At the end of a contour Windows adds the start point, but
3900 if(point > outline->contours[contour] &&
3901 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3903 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3905 } else if(point <= outline->contours[contour] &&
3906 outline->tags[point] & FT_Curve_Tag_On) {
3907 /* add closing pt for bezier */
3909 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3917 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3920 pph->cb = needed - pph_start;
3926 /* Convert the quadratic Beziers to cubic Beziers.
3927 The parametric eqn for a cubic Bezier is, from PLRM:
3928 r(t) = at^3 + bt^2 + ct + r0
3929 with the control points:
3934 A quadratic Beizer has the form:
3935 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3937 So equating powers of t leads to:
3938 r1 = 2/3 p1 + 1/3 p0
3939 r2 = 2/3 p1 + 1/3 p2
3940 and of course r0 = p0, r3 = p2
3943 int contour, point = 0, first_pt;
3944 FT_Outline *outline = &ft_face->glyph->outline;
3945 TTPOLYGONHEADER *pph;
3947 DWORD pph_start, cpfx, type;
3948 FT_Vector cubic_control[4];
3949 if(buflen == 0) buf = NULL;
3951 if (needsTransform && buf) {
3952 pFT_Outline_Transform(outline, &transMat);
3955 for(contour = 0; contour < outline->n_contours; contour++) {
3957 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3960 pph->dwType = TT_POLYGON_TYPE;
3961 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3963 needed += sizeof(*pph);
3965 while(point <= outline->contours[contour]) {
3966 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3967 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3968 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3971 if(type == TT_PRIM_LINE) {
3973 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3977 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3980 /* FIXME: Possible optimization in endpoint calculation
3981 if there are two consecutive curves */
3982 cubic_control[0] = outline->points[point-1];
3983 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3984 cubic_control[0].x += outline->points[point].x + 1;
3985 cubic_control[0].y += outline->points[point].y + 1;
3986 cubic_control[0].x >>= 1;
3987 cubic_control[0].y >>= 1;
3989 if(point+1 > outline->contours[contour])
3990 cubic_control[3] = outline->points[first_pt];
3992 cubic_control[3] = outline->points[point+1];
3993 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3994 cubic_control[3].x += outline->points[point].x + 1;
3995 cubic_control[3].y += outline->points[point].y + 1;
3996 cubic_control[3].x >>= 1;
3997 cubic_control[3].y >>= 1;
4000 /* r1 = 1/3 p0 + 2/3 p1
4001 r2 = 1/3 p2 + 2/3 p1 */
4002 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4003 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4004 cubic_control[2] = cubic_control[1];
4005 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4006 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4007 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4008 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4010 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4011 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4012 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4017 } while(point <= outline->contours[contour] &&
4018 (outline->tags[point] & FT_Curve_Tag_On) ==
4019 (outline->tags[point-1] & FT_Curve_Tag_On));
4020 /* At the end of a contour Windows adds the start point,
4021 but only for Beziers and we've already done that.
4023 if(point <= outline->contours[contour] &&
4024 outline->tags[point] & FT_Curve_Tag_On) {
4025 /* This is the closing pt of a bezier, but we've already
4026 added it, so just inc point and carry on */
4033 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4036 pph->cb = needed - pph_start;
4042 FIXME("Unsupported format %d\n", format);
4048 static BOOL get_bitmap_text_metrics(GdiFont *font)
4050 FT_Face ft_face = font->ft_face;
4051 #ifdef HAVE_FREETYPE_FTWINFNT_H
4052 FT_WinFNT_HeaderRec winfnt_header;
4054 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4055 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4056 font->potm->otmSize = size;
4058 #define TM font->potm->otmTextMetrics
4059 #ifdef HAVE_FREETYPE_FTWINFNT_H
4060 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4062 TM.tmHeight = winfnt_header.pixel_height;
4063 TM.tmAscent = winfnt_header.ascent;
4064 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4065 TM.tmInternalLeading = winfnt_header.internal_leading;
4066 TM.tmExternalLeading = winfnt_header.external_leading;
4067 TM.tmAveCharWidth = winfnt_header.avg_width;
4068 TM.tmMaxCharWidth = winfnt_header.max_width;
4069 TM.tmWeight = winfnt_header.weight;
4071 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4072 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4073 TM.tmFirstChar = winfnt_header.first_char;
4074 TM.tmLastChar = winfnt_header.last_char;
4075 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4076 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4077 TM.tmItalic = winfnt_header.italic;
4078 TM.tmUnderlined = font->underline;
4079 TM.tmStruckOut = font->strikeout;
4080 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4081 TM.tmCharSet = winfnt_header.charset;
4086 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4087 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4088 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4089 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4090 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4091 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4092 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4093 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4095 TM.tmDigitizedAspectX = 96; /* FIXME */
4096 TM.tmDigitizedAspectY = 96; /* FIXME */
4098 TM.tmLastChar = 255;
4099 TM.tmDefaultChar = 32;
4100 TM.tmBreakChar = 32;
4101 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4102 TM.tmUnderlined = font->underline;
4103 TM.tmStruckOut = font->strikeout;
4104 /* NB inverted meaning of TMPF_FIXED_PITCH */
4105 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4106 TM.tmCharSet = font->charset;
4113 /*************************************************************
4114 * WineEngGetTextMetrics
4117 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4120 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
4121 if(!get_bitmap_text_metrics(font))
4124 if(!font->potm) return FALSE;
4125 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
4127 if (font->aveWidth) {
4128 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
4134 /*************************************************************
4135 * WineEngGetOutlineTextMetrics
4138 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4139 OUTLINETEXTMETRICW *potm)
4141 FT_Face ft_face = font->ft_face;
4142 UINT needed, lenfam, lensty, ret;
4144 TT_HoriHeader *pHori;
4145 TT_Postscript *pPost;
4146 FT_Fixed x_scale, y_scale;
4147 WCHAR *family_nameW, *style_nameW;
4148 static const WCHAR spaceW[] = {' ', '\0'};
4150 INT ascent, descent;
4152 TRACE("font=%p\n", font);
4154 if(!FT_IS_SCALABLE(ft_face))
4158 if(cbSize >= font->potm->otmSize)
4159 memcpy(potm, font->potm, font->potm->otmSize);
4160 return font->potm->otmSize;
4164 needed = sizeof(*potm);
4166 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
4167 family_nameW = strdupW(font->name);
4169 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
4171 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
4172 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
4173 style_nameW, lensty/sizeof(WCHAR));
4175 /* These names should be read from the TT name table */
4177 /* length of otmpFamilyName */
4180 /* length of otmpFaceName */
4181 if(!strcasecmp(ft_face->style_name, "regular")) {
4182 needed += lenfam; /* just the family name */
4184 needed += lenfam + lensty; /* family + " " + style */
4187 /* length of otmpStyleName */
4190 /* length of otmpFullName */
4191 needed += lenfam + lensty;
4194 x_scale = ft_face->size->metrics.x_scale;
4195 y_scale = ft_face->size->metrics.y_scale;
4197 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4199 FIXME("Can't find OS/2 table - not TT font?\n");
4204 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4206 FIXME("Can't find HHEA table - not TT font?\n");
4211 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
4213 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",
4214 pOS2->usWinAscent, pOS2->usWinDescent,
4215 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
4216 ft_face->ascender, ft_face->descender, ft_face->height,
4217 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
4218 ft_face->bbox.yMax, ft_face->bbox.yMin);
4220 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
4221 font->potm->otmSize = needed;
4223 #define TM font->potm->otmTextMetrics
4225 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
4226 ascent = pHori->Ascender;
4227 descent = -pHori->Descender;
4229 ascent = pOS2->usWinAscent;
4230 descent = pOS2->usWinDescent;
4234 TM.tmAscent = font->yMax;
4235 TM.tmDescent = -font->yMin;
4236 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
4238 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
4239 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
4240 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
4241 - ft_face->units_per_EM, y_scale) + 32) >> 6;
4244 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4247 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4249 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
4250 ((ascent + descent) -
4251 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
4253 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
4254 if (TM.tmAveCharWidth == 0) {
4255 TM.tmAveCharWidth = 1;
4257 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
4258 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
4260 TM.tmDigitizedAspectX = 300;
4261 TM.tmDigitizedAspectY = 300;
4262 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4263 * symbol range to 0 - f0ff
4265 if (font->charset == SYMBOL_CHARSET)
4268 TM.tmFirstChar = pOS2->usFirstCharIndex;
4269 TM.tmLastChar = pOS2->usLastCharIndex;
4270 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4271 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
4272 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4273 TM.tmUnderlined = font->underline;
4274 TM.tmStruckOut = font->strikeout;
4276 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4277 if(!FT_IS_FIXED_WIDTH(ft_face) &&
4278 (pOS2->version == 0xFFFFU ||
4279 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4280 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
4282 TM.tmPitchAndFamily = 0;
4284 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
4285 case PAN_FAMILY_SCRIPT:
4286 TM.tmPitchAndFamily |= FF_SCRIPT;
4288 case PAN_FAMILY_DECORATIVE:
4289 case PAN_FAMILY_PICTORIAL:
4290 TM.tmPitchAndFamily |= FF_DECORATIVE;
4292 case PAN_FAMILY_TEXT_DISPLAY:
4293 if(TM.tmPitchAndFamily == 0) /* fixed */
4294 TM.tmPitchAndFamily = FF_MODERN;
4296 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
4297 case PAN_SERIF_NORMAL_SANS:
4298 case PAN_SERIF_OBTUSE_SANS:
4299 case PAN_SERIF_PERP_SANS:
4300 TM.tmPitchAndFamily |= FF_SWISS;
4303 TM.tmPitchAndFamily |= FF_ROMAN;
4308 TM.tmPitchAndFamily |= FF_DONTCARE;
4311 if(FT_IS_SCALABLE(ft_face))
4312 TM.tmPitchAndFamily |= TMPF_VECTOR;
4314 if(FT_IS_SFNT(ft_face))
4316 if (font->ntmFlags & NTM_PS_OPENTYPE)
4317 TM.tmPitchAndFamily |= TMPF_DEVICE;
4319 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
4322 TM.tmCharSet = font->charset;
4325 font->potm->otmFiller = 0;
4326 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
4327 font->potm->otmfsSelection = pOS2->fsSelection;
4328 font->potm->otmfsType = pOS2->fsType;
4329 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
4330 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
4331 font->potm->otmItalicAngle = 0; /* POST table */
4332 font->potm->otmEMSquare = ft_face->units_per_EM;
4333 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
4334 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4335 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4336 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
4337 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4338 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
4339 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
4340 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
4341 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4342 font->potm->otmMacAscent = 0; /* where do these come from ? */
4343 font->potm->otmMacDescent = 0;
4344 font->potm->otmMacLineGap = 0;
4345 font->potm->otmusMinimumPPEM = 0; /* TT Header */
4346 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
4347 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
4348 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
4349 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
4350 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
4351 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
4352 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
4353 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
4354 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
4355 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4357 font->potm->otmsUnderscoreSize = 0;
4358 font->potm->otmsUnderscorePosition = 0;
4360 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
4361 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
4364 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4365 cp = (char*)font->potm + sizeof(*font->potm);
4366 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4367 strcpyW((WCHAR*)cp, family_nameW);
4369 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4370 strcpyW((WCHAR*)cp, style_nameW);
4372 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4373 strcpyW((WCHAR*)cp, family_nameW);
4374 if(strcasecmp(ft_face->style_name, "regular")) {
4375 strcatW((WCHAR*)cp, spaceW);
4376 strcatW((WCHAR*)cp, style_nameW);
4377 cp += lenfam + lensty;
4380 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
4381 strcpyW((WCHAR*)cp, family_nameW);
4382 strcatW((WCHAR*)cp, spaceW);
4383 strcatW((WCHAR*)cp, style_nameW);
4386 if(potm && needed <= cbSize)
4387 memcpy(potm, font->potm, font->potm->otmSize);
4390 HeapFree(GetProcessHeap(), 0, style_nameW);
4391 HeapFree(GetProcessHeap(), 0, family_nameW);
4396 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
4398 HFONTLIST *hfontlist;
4399 child->font = alloc_font();
4400 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
4401 if(!child->font->ft_face)
4403 free_font(child->font);
4408 child->font->ntmFlags = child->face->ntmFlags;
4409 child->font->orientation = font->orientation;
4410 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
4411 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
4412 list_add_head(&child->font->hfontlist, &hfontlist->entry);
4413 child->font->base_font = font;
4414 list_add_head(&child_font_list, &child->font->entry);
4415 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
4419 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
4422 CHILD_FONT *child_font;
4425 font = font->base_font;
4427 *linked_font = font;
4429 if((*glyph = get_glyph_index(font, c)))
4432 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
4434 if(!child_font->font)
4435 if(!load_child_font(font, child_font))
4438 if(!child_font->font->ft_face)
4440 g = get_glyph_index(child_font->font, c);
4444 *linked_font = child_font->font;
4451 /*************************************************************
4452 * WineEngGetCharWidth
4455 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4460 FT_UInt glyph_index;
4461 GdiFont *linked_font;
4463 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4465 for(c = firstChar; c <= lastChar; c++) {
4466 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4467 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4468 &gm, 0, NULL, NULL);
4469 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
4474 /*************************************************************
4475 * WineEngGetCharABCWidths
4478 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4483 FT_UInt glyph_index;
4484 GdiFont *linked_font;
4486 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4488 if(!FT_IS_SCALABLE(font->ft_face))
4491 for(c = firstChar; c <= lastChar; c++) {
4492 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4493 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4494 &gm, 0, NULL, NULL);
4495 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
4496 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
4497 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
4498 FONT_GM(linked_font,glyph_index)->bbx;
4503 /*************************************************************
4504 * WineEngGetCharABCWidthsI
4507 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4512 FT_UInt glyph_index;
4513 GdiFont *linked_font;
4515 if(!FT_IS_SCALABLE(font->ft_face))
4518 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
4520 for(c = firstChar; c < firstChar+count; c++) {
4521 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
4522 &gm, 0, NULL, NULL);
4523 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
4524 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
4525 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
4526 - FONT_GM(linked_font,c)->bbx;
4529 for(c = 0; c < count; c++) {
4530 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
4531 &gm, 0, NULL, NULL);
4532 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
4533 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
4534 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
4535 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
4541 /*************************************************************
4542 * WineEngGetTextExtentExPoint
4545 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4546 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4552 FT_UInt glyph_index;
4553 GdiFont *linked_font;
4555 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
4559 WineEngGetTextMetrics(font, &tm);
4560 size->cy = tm.tmHeight;
4562 for(idx = 0; idx < count; idx++) {
4563 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
4564 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4565 &gm, 0, NULL, NULL);
4566 size->cx += FONT_GM(linked_font,glyph_index)->adv;
4568 if (! pnfit || ext <= max_ext) {
4578 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4582 /*************************************************************
4583 * WineEngGetTextExtentPointI
4586 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4593 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
4596 WineEngGetTextMetrics(font, &tm);
4597 size->cy = tm.tmHeight;
4599 for(idx = 0; idx < count; idx++) {
4600 WineEngGetGlyphOutline(font, indices[idx],
4601 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
4603 size->cx += FONT_GM(font,indices[idx])->adv;
4605 TRACE("return %d,%d\n", size->cx, size->cy);
4609 /*************************************************************
4610 * WineEngGetFontData
4613 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4616 FT_Face ft_face = font->ft_face;
4620 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
4621 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
4622 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
4624 if(!FT_IS_SFNT(ft_face))
4632 if(table) { /* MS tags differ in endidness from FT ones */
4633 table = table >> 24 | table << 24 |
4634 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
4637 /* make sure value of len is the value freetype says it needs */
4640 FT_ULong needed = 0;
4641 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
4642 if( !err && needed < len) len = needed;
4644 err = load_sfnt_table(ft_face, table, offset, buf, &len);
4647 TRACE("Can't find table %c%c%c%c\n",
4648 /* bytes were reversed */
4649 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4650 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4656 /*************************************************************
4657 * WineEngGetTextFace
4660 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4663 lstrcpynW(str, font->name, count);
4664 return strlenW(font->name);
4666 return strlenW(font->name) + 1;
4669 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4671 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4672 return font->charset;
4675 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4677 GdiFont *font = dc->gdiFont, *linked_font;
4678 struct list *first_hfont;
4681 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4682 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4683 if(font == linked_font)
4684 *new_hfont = dc->hFont;
4687 first_hfont = list_head(&linked_font->hfontlist);
4688 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4694 /* Retrieve a list of supported Unicode ranges for a given font.
4695 * Can be called with NULL gs to calculate the buffer size. Returns
4696 * the number of ranges found.
4698 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
4700 DWORD num_ranges = 0;
4702 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4705 FT_ULong char_code, char_code_prev;
4708 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
4710 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4711 face->num_glyphs, glyph_code, char_code);
4713 if (!glyph_code) return 0;
4717 gs->ranges[0].wcLow = (USHORT)char_code;
4718 gs->ranges[0].cGlyphs = 0;
4719 gs->cGlyphsSupported = 0;
4725 if (char_code < char_code_prev)
4727 ERR("expected increasing char code from FT_Get_Next_Char\n");
4730 if (char_code - char_code_prev > 1)
4735 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4736 gs->ranges[num_ranges - 1].cGlyphs = 1;
4737 gs->cGlyphsSupported++;
4742 gs->ranges[num_ranges - 1].cGlyphs++;
4743 gs->cGlyphsSupported++;
4745 char_code_prev = char_code;
4746 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
4750 FIXME("encoding %u not supported\n", face->charmap->encoding);
4755 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
4758 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
4760 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
4763 glyphset->cbThis = size;
4764 glyphset->cRanges = num_ranges;
4769 /*************************************************************
4772 BOOL WineEngFontIsLinked(GdiFont *font)
4774 return !list_empty(&font->child_fonts);
4777 static BOOL is_hinting_enabled(void)
4779 /* Use the >= 2.2.0 function if available */
4780 if(pFT_Get_TrueType_Engine_Type)
4782 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4783 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4785 #ifdef FT_DRIVER_HAS_HINTER
4790 /* otherwise if we've been compiled with < 2.2.0 headers
4791 use the internal macro */
4792 mod = pFT_Get_Module(library, "truetype");
4793 if(mod && FT_DRIVER_HAS_HINTER(mod))
4801 /*************************************************************************
4802 * GetRasterizerCaps (GDI32.@)
4804 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4806 static int hinting = -1;
4810 hinting = is_hinting_enabled();
4811 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
4814 lprs->nSize = sizeof(RASTERIZER_STATUS);
4815 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4816 lprs->nLanguageID = 0;
4820 /*************************************************************************
4821 * Kerning support for TrueType fonts
4823 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4825 struct TT_kern_table
4831 struct TT_kern_subtable
4840 USHORT horizontal : 1;
4842 USHORT cross_stream: 1;
4843 USHORT override : 1;
4844 USHORT reserved1 : 4;
4850 struct TT_format0_kern_subtable
4854 USHORT entrySelector;
4865 static DWORD parse_format0_kern_subtable(GdiFont *font,
4866 const struct TT_format0_kern_subtable *tt_f0_ks,
4867 const USHORT *glyph_to_char,
4868 KERNINGPAIR *kern_pair, DWORD cPairs)
4871 const struct TT_kern_pair *tt_kern_pair;
4873 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
4875 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4877 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4878 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4879 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4881 if (!kern_pair || !cPairs)
4884 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4886 nPairs = min(nPairs, cPairs);
4888 for (i = 0; i < nPairs; i++)
4890 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4891 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4892 /* this algorithm appears to better match what Windows does */
4893 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4894 if (kern_pair->iKernAmount < 0)
4896 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
4897 kern_pair->iKernAmount -= font->ppem;
4899 else if (kern_pair->iKernAmount > 0)
4901 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
4902 kern_pair->iKernAmount += font->ppem;
4904 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
4906 TRACE("left %u right %u value %d\n",
4907 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
4911 TRACE("copied %u entries\n", nPairs);
4915 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4919 const struct TT_kern_table *tt_kern_table;
4920 const struct TT_kern_subtable *tt_kern_subtable;
4922 USHORT *glyph_to_char;
4924 if (font->total_kern_pairs != (DWORD)-1)
4926 if (cPairs && kern_pair)
4928 cPairs = min(cPairs, font->total_kern_pairs);
4929 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4932 return font->total_kern_pairs;
4935 font->total_kern_pairs = 0;
4937 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
4939 if (length == GDI_ERROR)
4941 TRACE("no kerning data in the font\n");
4945 buf = HeapAlloc(GetProcessHeap(), 0, length);
4948 WARN("Out of memory\n");
4952 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
4954 /* build a glyph index to char code map */
4955 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
4958 WARN("Out of memory allocating a glyph index to char code map\n");
4959 HeapFree(GetProcessHeap(), 0, buf);
4963 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4969 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
4971 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4972 font->ft_face->num_glyphs, glyph_code, char_code);
4976 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4978 /* FIXME: This doesn't match what Windows does: it does some fancy
4979 * things with duplicate glyph index to char code mappings, while
4980 * we just avoid overriding existing entries.
4982 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
4983 glyph_to_char[glyph_code] = (USHORT)char_code;
4985 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
4992 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
4993 for (n = 0; n <= 65535; n++)
4994 glyph_to_char[n] = (USHORT)n;
4997 tt_kern_table = buf;
4998 nTables = GET_BE_WORD(tt_kern_table->nTables);
4999 TRACE("version %u, nTables %u\n",
5000 GET_BE_WORD(tt_kern_table->version), nTables);
5002 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5004 for (i = 0; i < nTables; i++)
5006 struct TT_kern_subtable tt_kern_subtable_copy;
5008 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5009 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5010 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5012 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5013 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
5014 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
5016 /* According to the TrueType specification this is the only format
5017 * that will be properly interpreted by Windows and OS/2
5019 if (tt_kern_subtable_copy.coverage.bits.format == 0)
5021 DWORD new_chunk, old_total = font->total_kern_pairs;
5023 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5024 glyph_to_char, NULL, 0);
5025 font->total_kern_pairs += new_chunk;
5027 if (!font->kern_pairs)
5028 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
5029 font->total_kern_pairs * sizeof(*font->kern_pairs));
5031 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
5032 font->total_kern_pairs * sizeof(*font->kern_pairs));
5034 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5035 glyph_to_char, font->kern_pairs + old_total, new_chunk);
5038 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
5040 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
5043 HeapFree(GetProcessHeap(), 0, glyph_to_char);
5044 HeapFree(GetProcessHeap(), 0, buf);
5046 if (cPairs && kern_pair)
5048 cPairs = min(cPairs, font->total_kern_pairs);
5049 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5052 return font->total_kern_pairs;
5055 #else /* HAVE_FREETYPE */
5057 /*************************************************************************/
5059 BOOL WineEngInit(void)
5063 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
5067 BOOL WineEngDestroyFontInstance(HFONT hfont)
5072 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
5077 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
5078 LPWORD pgi, DWORD flags)
5083 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
5084 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5087 ERR("called but we don't have FreeType\n");
5091 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5093 ERR("called but we don't have FreeType\n");
5097 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5098 OUTLINETEXTMETRICW *potm)
5100 ERR("called but we don't have FreeType\n");
5104 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5107 ERR("called but we don't have FreeType\n");
5111 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5114 ERR("called but we don't have FreeType\n");
5118 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5121 ERR("called but we don't have FreeType\n");
5125 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5126 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5128 ERR("called but we don't have FreeType\n");
5132 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
5135 ERR("called but we don't have FreeType\n");
5139 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5142 ERR("called but we don't have FreeType\n");
5146 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5148 ERR("called but we don't have FreeType\n");
5152 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5158 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5164 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
5170 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5173 return DEFAULT_CHARSET;
5176 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5181 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5183 FIXME("(%p, %p): stub\n", font, glyphset);
5187 BOOL WineEngFontIsLinked(GdiFont *font)
5192 /*************************************************************************
5193 * GetRasterizerCaps (GDI32.@)
5195 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5197 lprs->nSize = sizeof(RASTERIZER_STATUS);
5199 lprs->nLanguageID = 0;
5203 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5205 ERR("called but we don't have FreeType\n");
5209 #endif /* HAVE_FREETYPE */